propagate available intentions to find action/search everywhere (IDEA-117167)

This commit is contained in:
Anna Kozlova
2013-12-17 13:34:51 +04:00
parent bd4018c07d
commit 772e035bf1
4 changed files with 124 additions and 72 deletions
@@ -0,0 +1,77 @@
/*
* Copyright 2000-2013 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.actions;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ApplyIntentionAction extends AnAction {
private final HighlightInfo.IntentionActionDescriptor myDescriptor;
private final Editor myEditor;
private final PsiFile myFile;
public ApplyIntentionAction(HighlightInfo.IntentionActionDescriptor descriptor, Editor editor, PsiFile file) {
super(descriptor.getAction().getText());
myDescriptor = descriptor;
myEditor = editor;
myFile = file;
}
@Override
public void actionPerformed(AnActionEvent e) {
final IntentionAction action = myDescriptor.getAction();
ShowIntentionActionsHandler.chooseActionAndInvoke(myFile, myEditor, action, action.getText());
}
public String getName() {
return myDescriptor.getAction().getText();
}
@Nullable
public static ApplyIntentionAction[] getAvailableIntentions(final Editor editor, final PsiFile file) {
final ShowIntentionsPass.IntentionsInfo info = new ShowIntentionsPass.IntentionsInfo();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
ShowIntentionsPass.getActionsToShow(editor, file, info, -1);
}
});
if (info.isEmpty()) return null;
final List<HighlightInfo.IntentionActionDescriptor> actions = new ArrayList<HighlightInfo.IntentionActionDescriptor>();
actions.addAll(info.errorFixesToShow);
actions.addAll(info.inspectionFixesToShow);
actions.addAll(info.intentionsToShow);
final ApplyIntentionAction[] result = new ApplyIntentionAction[actions.size()];
for (int i = 0; i < result.length; i++) {
result[i] = new ApplyIntentionAction(actions.get(i), editor, file);
}
return result;
}
}
@@ -27,10 +27,12 @@ import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -54,9 +56,11 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
public void gotoActionPerformed(final AnActionEvent e) {
final Project project = e.getData(CommonDataKeys.PROJECT);
final Component component = e.getData(PlatformDataKeys.CONTEXT_COMPONENT);
final Editor editor = e.getData(CommonDataKeys.EDITOR);
final PsiFile file = e.getData(CommonDataKeys.PSI_FILE);
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.action");
final GotoActionModel model = new GotoActionModel(project, component);
final GotoActionModel model = new GotoActionModel(project, component, editor, file);
final GotoActionCallback<Object> callback = new GotoActionCallback<Object>() {
@Override
public void elementChosen(ChooseByNamePopup popup, final Object element) {
@@ -27,7 +27,6 @@ import com.intellij.ide.ui.laf.darcula.ui.DarculaTextBorder;
import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI;
import com.intellij.ide.ui.search.BooleanOptionDescription;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.ide.ui.search.SearchableOptionsRegistrarImpl;
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.gotoByName.*;
@@ -37,10 +36,10 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.actionSystem.ex.CustomComponentAction;
import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actions.TextComponentEditorAction;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
@@ -256,6 +255,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private Component myFocusOwner;
private ChooseByNamePopup myFileChooseByName;
private Editor myEditor;
private PsiFile myFile;
@Override
public JComponent createCustomComponent(Presentation presentation) {
JPanel panel = new JPanel(new BorderLayout()) {
@@ -624,6 +626,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
rebuildList(myPopupField.getText());
return;
}
if (e != null) {
myEditor = e.getData(CommonDataKeys.EDITOR);
myFile = e.getData(CommonDataKeys.PSI_FILE);
}
if (e == null && myFocusOwner != null) {
e = new AnActionEvent(me, DataManager.getInstance().getDataContext(myFocusOwner), ActionPlaces.UNKNOWN, getTemplatePresentation(), ActionManager.getInstance(), 0);
}
@@ -1474,76 +1480,11 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
private GotoActionModel createActionModel() {
return new GotoActionModel(project, myFocusComponent) {
return new GotoActionModel(project, myFocusComponent, myEditor, myFile) {
@Override
public boolean matches(@NotNull String name, @NotNull String pattern) {
final AnAction anAction = ActionManager.getInstance().getAction(name);
if (anAction == null) return true;
return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE).matches(
anAction.getTemplatePresentation().getText());
}
@NotNull
@Override
public Object[] getElementsByName(String id, boolean checkBoxState, String pattern) {
final HashMap<AnAction, String> map = new HashMap<AnAction, String>();
final AnAction act = myActionManager.getAction(id);
if (act != null) {
map.put(act, myActionsMap.get(act));
if (checkBoxState) {
final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
for (AnAction action : map.keySet()) { //do not add already included actions
ids.remove(getActionId(action));
}
if (ids.contains(id)) {
final AnAction anAction = myActionManager.getAction(id);
map.put(anAction, null);
}
}
}
Object[] objects = map.entrySet().toArray(new Map.Entry[map.size()]);
if (Comparing.strEqual(id, SETTINGS_KEY)) {
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();
}
}
final Object[] descriptions = optionDescriptions.toArray();
Arrays.sort(descriptions);
objects = ArrayUtil.mergeArrays(objects, descriptions);
}
}
return objects;
protected boolean actionMatches(String pattern, @NotNull AnAction anAction) {
return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE)
.matches(anAction.getTemplatePresentation().getText());
}
};
}
@@ -18,6 +18,7 @@ package com.intellij.ide.util.gotoByName;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.actions.ApplyIntentionAction;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
import com.intellij.ide.ui.search.SearchableOptionsRegistrarImpl;
@@ -25,11 +26,13 @@ import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.LayeredIcon;
import com.intellij.ui.LightColors;
@@ -48,6 +51,7 @@ import java.util.*;
public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, Comparator<Object> {
@NonNls public static final String SETTINGS_KEY = "$$$SETTINGS$$$";
@NonNls public static final String INTENTIONS_KEY = "$$$INTENTIONS_KEY$$$";
@Nullable private final Project myProject;
private final Component myContextComponent;
@@ -69,11 +73,25 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
}
});
protected final Map<String, ApplyIntentionAction> myIntentions = new TreeMap<String, ApplyIntentionAction>();
public GotoActionModel(@Nullable Project project, final Component component) {
this(project, component, null, null);
}
public GotoActionModel(@Nullable Project project, final Component component, @Nullable Editor editor, @Nullable PsiFile file) {
myProject = project;
myContextComponent = component;
final ActionGroup mainMenu = (ActionGroup)myActionManager.getActionOrStub(IdeActions.GROUP_MAIN_MENU);
collectActions(myActionsMap, mainMenu, mainMenu.getTemplatePresentation().getText());
if (project != null && editor != null && file != null) {
final ApplyIntentionAction[] children = ApplyIntentionAction.getAvailableIntentions(editor, file);
if (children != null) {
for (ApplyIntentionAction action : children) {
myIntentions.put(action.getName(), action);
}
}
}
myIndex = SearchableOptionsRegistrar.getInstance();
}
@@ -266,6 +284,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
@NotNull
public String[] getNames(boolean checkBoxState) {
final ArrayList<String> result = new ArrayList<String>();
result.add(INTENTIONS_KEY);
for (AnAction action : myActionsMap.keySet()) {
result.add(getActionId(action));
}
@@ -296,6 +315,13 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
map.put(anAction, null);
}
}
} else if (Comparing.strEqual(id, INTENTIONS_KEY)) {
for (String intentionText : myIntentions.keySet()) {
final ApplyIntentionAction intentionAction = myIntentions.get(intentionText);
if (actionMatches(pattern, intentionAction)) {
map.put(intentionAction, intentionText);
}
}
}
Object[] objects = map.entrySet().toArray(new Map.Entry[map.size()]);
if (Comparing.strEqual(id, SETTINGS_KEY)) {
@@ -409,6 +435,10 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
public boolean matches(@NotNull final String name, @NotNull final String pattern) {
final AnAction anAction = myActionManager.getAction(name);
if (anAction == null) return true;
return actionMatches(pattern, anAction);
}
protected boolean actionMatches(String pattern, @NotNull AnAction anAction) {
final Pattern compiledPattern = getPattern(pattern);
final Presentation presentation = anAction.getTemplatePresentation();
final String text = presentation.getText();