blob: 99d3c9b338ae45fa3bf92f6ae87b6c8d66ff4686 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.util.gotoByName;
import com.intellij.ide.DataManager;
import com.intellij.ide.actions.ApplyIntentionAction;
import com.intellij.ide.ui.search.ActionFromOptionDescriptorProvider;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
import com.intellij.ide.ui.search.SearchableOptionsRegistrarImpl;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.util.Function;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import static com.intellij.ide.util.gotoByName.GotoActionModel.*;
/**
* @author peter
*/
public class GotoActionItemProvider implements ChooseByNameItemProvider {
private final ActionManager myActionManager = ActionManager.getInstance();
protected final SearchableOptionsRegistrar myIndex = SearchableOptionsRegistrar.getInstance();
private final GotoActionModel myModel;
public GotoActionItemProvider(GotoActionModel model) {
myModel = model;
}
@NotNull
@Override
public List<String> filterNames(@NotNull ChooseByNameBase base, @NotNull String[] names, @NotNull String pattern) {
return Collections.emptyList(); // no common prefix insertion in goto action
}
@Override
public boolean filterElements(@NotNull final ChooseByNameBase base,
@NotNull final String pattern,
boolean everywhere,
@NotNull ProgressIndicator cancelled,
@NotNull final Processor<Object> consumer) {
return filterElements(pattern, everywhere, new Processor<MatchedValue>() {
@Override
public boolean process(MatchedValue value) {
return consumer.process(value);
}
});
}
public boolean filterElements(String pattern, boolean everywhere, Processor<MatchedValue> consumer) {
DataContext dataContext = DataManager.getInstance().getDataContext(myModel.getContextComponent());
if (!processIntentions(pattern, consumer, dataContext)) return false;
if (!processActions(pattern, everywhere, consumer, dataContext)) return false;
if (!processOptions(pattern, consumer, dataContext)) return false;
return true;
}
private boolean processOptions(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
List<Comparable> options = ContainerUtil.newArrayList();
final Set<String> words = myIndex.getProcessedWords(pattern);
Set<OptionDescription> optionDescriptions = null;
final String actionManagerName = myActionManager.getComponentName();
for (String word : words) {
final Set<OptionDescription> descriptions = ((SearchableOptionsRegistrarImpl)myIndex).getAcceptableDescriptions(word);
if (descriptions != null) {
for (Iterator<OptionDescription> iterator = descriptions.iterator(); iterator.hasNext(); ) {
OptionDescription description = iterator.next();
if (actionManagerName.equals(description.getPath())) {
iterator.remove();
}
}
if (!descriptions.isEmpty()) {
if (optionDescriptions == null) {
optionDescriptions = descriptions;
}
else {
optionDescriptions.retainAll(descriptions);
}
}
} else {
optionDescriptions = null;
break;
}
}
if (optionDescriptions != null && !optionDescriptions.isEmpty()) {
Set<String> currentHits = new HashSet<String>();
for (Iterator<OptionDescription> iterator = optionDescriptions.iterator(); iterator.hasNext(); ) {
OptionDescription description = iterator.next();
final String hit = description.getHit();
if (hit == null || !currentHits.add(hit.trim())) {
iterator.remove();
}
}
for (OptionDescription description : optionDescriptions) {
for (ActionFromOptionDescriptorProvider converter : ActionFromOptionDescriptorProvider.EP.getExtensions()) {
AnAction action = converter.provide(description);
if (action != null) options.add(new ActionWrapper(action, null, MatchMode.NAME, dataContext));
options.add(description);
}
}
}
return processItems(pattern, options, consumer);
}
private boolean processActions(String pattern, boolean everywhere, Processor<MatchedValue> consumer, DataContext dataContext) {
List<AnAction> actions = ContainerUtil.newArrayList();
if (everywhere) {
for (String id : ((ActionManagerImpl)myActionManager).getActionIds()) {
ProgressManager.checkCanceled();
ContainerUtil.addIfNotNull(actions, myActionManager.getAction(id));
}
} else {
actions.addAll(myModel.myActionGroups.keySet());
}
List<ActionWrapper> actionWrappers = ContainerUtil.newArrayList();
for (AnAction action : actions) {
ProgressManager.checkCanceled();
MatchMode mode = myModel.actionMatches(pattern, action);
if (mode != MatchMode.NONE) {
actionWrappers.add(new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext));
}
}
return processItems(pattern, actionWrappers, consumer);
}
private boolean processIntentions(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
List<ActionWrapper> intentions = ContainerUtil.newArrayList();
for (String intentionText : myModel.myIntentions.keySet()) {
final ApplyIntentionAction intentionAction = myModel.myIntentions.get(intentionText);
if (myModel.actionMatches(pattern, intentionAction) != MatchMode.NONE) {
intentions.add(new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext));
}
}
return processItems(pattern, intentions, consumer);
}
private static boolean processItems(final String pattern, List<? extends Comparable> items, Processor<MatchedValue> consumer) {
List<MatchedValue> matched = ContainerUtil.map(items, new Function<Comparable, MatchedValue>() {
@Override
public MatchedValue fun(Comparable comparable) {
return new MatchedValue(comparable, pattern);
}
});
Collections.sort(matched);
return ContainerUtil.process(matched, consumer);
}
}