diff options
Diffstat (limited to 'platform/lang-impl/src/com/intellij/ide')
13 files changed, 546 insertions, 417 deletions
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java index c939787fb632..e57d1eba05ef 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java @@ -20,9 +20,8 @@ import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.DataManager; import com.intellij.ide.ui.search.OptionDescription; import com.intellij.ide.util.gotoByName.ChooseByNamePopup; -import com.intellij.ide.util.gotoByName.DefaultChooseByNameItemProvider; +import com.intellij.ide.util.gotoByName.GotoActionItemProvider; import com.intellij.ide.util.gotoByName.GotoActionModel; -import com.intellij.ide.util.gotoByName.MatchResult; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; @@ -33,27 +32,11 @@ 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; import java.awt.*; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; public class GotoActionAction extends GotoActionBase implements DumbAware { - public static final Comparator<MatchResult> ELEMENTS_COMPARATOR = new Comparator<MatchResult>() { - @Override - public int compare(@NotNull MatchResult o1, @NotNull MatchResult o2) { - if (o1.elementName.equals(GotoActionModel.INTENTIONS_KEY)) return -1; - if (o2.elementName.equals(GotoActionModel.INTENTIONS_KEY)) return 1; - - if (o1.elementName.equals(GotoActionModel.SETTINGS_KEY)) return 1; - if (o2.elementName.equals(GotoActionModel.SETTINGS_KEY)) return -1; - - return o1.elementName.compareToIgnoreCase(o2.elementName); - } - }; @Override public void gotoActionPerformed(final AnActionEvent e) { @@ -68,7 +51,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { @Override public void elementChosen(ChooseByNamePopup popup, final Object element) { final String enteredText = popup.getEnteredText(); - openOptionOrPerformAction(element, enteredText, project, component, e); + openOptionOrPerformAction(((GotoActionModel.MatchedValue)element).value, enteredText, project, component, e); } }; @@ -79,12 +62,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware { private static ChooseByNamePopup createPopup(Project project, GotoActionModel model, String initialText, int initialIndex) { return ChooseByNamePopup.createPopup(project, model, - new DefaultChooseByNameItemProvider(null) { - @Override - protected void sortNamesList(@NotNull String namePattern, @NotNull List<MatchResult> namesList) { - Collections.sort(namesList, ELEMENTS_COMPARATOR); - } - }, + new GotoActionItemProvider(model), initialText, false, initialIndex); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java new file mode 100644 index 000000000000..6d734d52a584 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java @@ -0,0 +1,46 @@ +/* + * 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.actions; + +import com.intellij.navigation.GotoRelatedItem; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @deprecated API compatibility. Utility methods will be moved to NavigationUtil + * @author gregsh + */ +public class GotoRelatedFileAction { + + /** + * @deprecated This method will be moved to NavigationUtil + */ + public static JBPopup createPopup(List<? extends GotoRelatedItem> items, final String title) { + return GotoRelatedSymbolAction.createPopup(items, title); + } + + /** + * @deprecated This method will be moved to NavigationUtil + */ + public static List<GotoRelatedItem> getItems(@NotNull PsiElement contextElement, @Nullable DataContext dataContext) { + return GotoRelatedSymbolAction.getItems(contextElement, dataContext); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java index f333c0f35db8..2870f806ab8a 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java @@ -42,6 +42,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.awt.*; @@ -56,26 +57,23 @@ public class GotoRelatedSymbolAction extends AnAction { @Override public void update(AnActionEvent e) { - PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); - PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(e.getDataContext()); - e.getPresentation().setEnabled(element != null || file != null); + PsiElement element = getContextElement(e.getDataContext()); + e.getPresentation().setEnabled(element != null); } @Override public void actionPerformed(AnActionEvent e) { - DataContext dataContext = e.getDataContext(); - PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext()); - Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext()); - PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); - if (element == null && file == null) return; + PsiElement element = getContextElement(e.getDataContext()); + if (element == null) return; - List<GotoRelatedItem> items = element == null? getItems(file, editor, dataContext) : getItems(element, dataContext); + List<GotoRelatedItem> items = getItems(element, e.getDataContext()); if (items.isEmpty()) return; + if (items.size() == 1 && items.get(0).getElement() != null) { items.get(0).navigate(); return; } - createPopup(items, "Choose Target").showInBestPositionFor(dataContext); + createPopup(items, "Choose Target").showInBestPositionFor(e.getDataContext()); } public static JBPopup createPopup(final List<? extends GotoRelatedItem> items, final String title) { @@ -268,8 +266,25 @@ public class GotoRelatedSymbolAction extends AnAction { return popup; } + @TestOnly @NotNull public static List<GotoRelatedItem> getItems(@NotNull PsiFile psiFile, @Nullable Editor editor, @Nullable DataContext dataContext) { + return getItems(getContextElement(psiFile, editor), dataContext); + } + + @Nullable + private static PsiElement getContextElement(@NotNull DataContext dataContext) { + PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext); + Editor editor = CommonDataKeys.EDITOR.getData(dataContext); + PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); + if (file != null && editor != null) { + return getContextElement(file, editor); + } + return element; + } + + @NotNull + private static PsiElement getContextElement(@NotNull PsiFile psiFile, @Nullable Editor editor) { PsiElement contextElement = psiFile; if (editor != null) { PsiElement element = psiFile.findElementAt(editor.getCaretModel().getOffset()); @@ -277,7 +292,7 @@ public class GotoRelatedSymbolAction extends AnAction { contextElement = element; } } - return getItems(contextElement, dataContext); + return contextElement; } @NotNull diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java index 996601065278..ae7ee4363247 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -56,10 +56,9 @@ import com.intellij.openapi.fileEditor.impl.EditorHistoryManager; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.keymap.MacKeymapUtil; +import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.options.ex.IdeConfigurablesGroup; -import com.intellij.openapi.options.ex.ProjectConfigurablesGroup; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.util.ProgressIndicatorBase; @@ -96,6 +95,7 @@ import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.ui.popup.AbstractPopup; import com.intellij.ui.popup.PopupPositionManager; import com.intellij.util.*; +import com.intellij.util.text.Matcher; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.StatusText; import com.intellij.util.ui.UIUtil; @@ -138,9 +138,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA MySearchTextField myPopupField; private volatile GotoClassModel2 myClassModel; private volatile GotoFileModel myFileModel; - private volatile GotoActionModel myActionModel; + private volatile GotoActionItemProvider myActionProvider; private volatile GotoSymbolModel2 mySymbolsModel; - private volatile String[] myActions; private Component myFocusComponent; private JBPopup myPopup; private Map<String, String> myConfigurables = new HashMap<String, String>(); @@ -153,106 +152,25 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private Component myContextComponent; private CalcThread myCalcThread; private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false); - private final static Couple<AtomicBoolean> ourPressed = Couple.of(new AtomicBoolean(false), new AtomicBoolean(false)); - private final static Couple<AtomicBoolean> ourReleased = Couple.of(new AtomicBoolean(false), new AtomicBoolean(false)); - private static AtomicBoolean ourOtherKeyWasPressed = new AtomicBoolean(false); - private static AtomicLong ourLastTimePressed = new AtomicLong(0); private static AtomicBoolean showAll = new AtomicBoolean(false); private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; private int myHistoryIndex = 0; boolean mySkipFocusGain = false; static { + ModifierKeyDoubleClickHandler.getInstance().registerAction(IdeActions.ACTION_SEARCH_EVERYWHERE, KeyEvent.VK_SHIFT, -1); + IdeEventQueue.getInstance().addPostprocessor(new IdeEventQueue.EventDispatcher() { @Override public boolean dispatch(AWTEvent event) { if (event instanceof KeyEvent) { - final KeyEvent keyEvent = (KeyEvent)event; - final int keyCode = keyEvent.getKeyCode(); - + final int keyCode = ((KeyEvent)event).getKeyCode(); if (keyCode == KeyEvent.VK_SHIFT) { ourShiftIsPressed.set(event.getID() == KeyEvent.KEY_PRESSED); - - if (keyEvent.isControlDown() || keyEvent.isAltDown() || keyEvent.isMetaDown()) { - resetState(); - return false; - } - if (ourOtherKeyWasPressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() < 500) { - resetState(); - return false; - } - ourOtherKeyWasPressed.set(false); - if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 500) { - resetState(); - } - handleShift((KeyEvent)event); - return false; - } else { - ourLastTimePressed.set(System.currentTimeMillis()); - ourOtherKeyWasPressed.set(true); - if (keyCode == KeyEvent.VK_ESCAPE || keyCode == KeyEvent.VK_TAB) { - ourLastTimePressed.set(0); - } } - resetState(); } return false; } - - private void resetState() { - ourPressed.first.set(false); - ourPressed.second.set(false); - ourReleased.first.set(false); - ourReleased.second.set(false); - } - - private void handleShift(KeyEvent event) { - if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 300) { - resetState(); - return; - } - - if (event.getID() == KeyEvent.KEY_PRESSED) { - if (!ourPressed.first.get()) { - resetState(); - ourPressed.first.set(true); - ourLastTimePressed.set(System.currentTimeMillis()); - return; - } else { - if (ourPressed.first.get() && ourReleased.first.get()) { - ourPressed.second.set(true); - ourLastTimePressed.set(System.currentTimeMillis()); - return; - } - } - } else if (event.getID() == KeyEvent.KEY_RELEASED) { - if (ourPressed.first.get() && !ourReleased.first.get()) { - ourReleased.first.set(true); - ourLastTimePressed.set(System.currentTimeMillis()); - return; - } else if (ourPressed.first.get() && ourReleased.first.get() && ourPressed.second.get()) { - resetState(); - run(event); - return; - } - } - resetState(); - } - - private void run(KeyEvent event) { - final ActionManager actionManager = ActionManager.getInstance(); - final AnAction action = actionManager.getAction(IdeActions.ACTION_SEARCH_EVERYWHERE); - if (KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_SEARCH_EVERYWHERE).length > 0) { - return; - } - final AnActionEvent anActionEvent = new AnActionEvent(event, - DataManager.getInstance().getDataContext(IdeFocusManager.findInstance().getFocusOwner()), - ActionPlaces.MAIN_MENU, - action.getTemplatePresentation(), - actionManager, - 0); - action.actionPerformed(anActionEvent); - } }, null); } @@ -840,7 +758,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA if (split.length != 3 || text.equals(split[0])) { continue; } - history.add(new HistoryItem(split[0], split[1], split[2])); + if (!StringUtil.isEmpty(split[0])) { + history.add(new HistoryItem(split[0], split[1], split[2])); + } } } history.add(0, new HistoryItem(text, type == null ? null : type.name(), fqn)); @@ -1008,14 +928,18 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA Component cmp; PsiFile file = null; myLocationString = null; + String pattern = "*" + myPopupField.getText(); + Matcher matcher = NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern)); if (isMoreItem(index)) { cmp = More.get(isSelected); } else if (value instanceof VirtualFile && myProject != null && (((VirtualFile)value).isDirectory() || (file = PsiManager.getInstance(myProject).findFile((VirtualFile)value)) != null)) { + myFileRenderer.setPatternMatcher(matcher); cmp = myFileRenderer.getListCellRendererComponent(list, file == null ? value : file, index, isSelected, cellHasFocus); } else if (value instanceof PsiElement) { + myPsiRenderer.setPatternMatcher(matcher); cmp = myPsiRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected); } else { cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected); @@ -1185,16 +1109,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return text; } - private void schedulePopupUpdate() { - myUpdateAlarm.cancelAllRequests(); - myUpdateAlarm.addRequest(new Runnable() { - @Override - public void run() { - updatePopupBounds(); - } - }, 50); - } - private static boolean isActionValue(Object o) { return o instanceof GotoActionModel.ActionWrapper || o instanceof AnAction; } @@ -1353,21 +1267,16 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private SearchResult getActionsOrSettings(final String pattern, final int max, final boolean actions) { final SearchResult result = new SearchResult(); final MinusculeMatcher matcher = new MinusculeMatcher("*" +pattern, NameUtil.MatchingCaseSensitivity.NONE); - if (myActions == null) { - if (myActionModel == null) { - myActionModel = createActionModel(); - } - myActions = myActionModel.getNames(true); + if (myActionProvider == null) { + myActionProvider = createActionProvider(); } - List<MatchResult> matches = collectResults(pattern, myActions, myActionModel); - - for (MatchResult o : matches) { - check(); - Object[] objects = myActionModel.getElementsByName(o.elementName, true, pattern); - for (Object object : objects) { + myActionProvider.filterElements(pattern, true, new Processor<GotoActionModel.MatchedValue>() { + @Override + public boolean process(GotoActionModel.MatchedValue matched) { check(); - if (myListModel.contains(object)) continue; + Object object = matched.value; + if (myListModel.contains(object)) return true; if (!actions && isSetting(object)) { if (matcher.matches(getSettingText((OptionDescription)object))) { @@ -1376,9 +1285,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } else if (actions && !isToolWindowAction(object) && isActionValue(object)) { result.add(object); } - if (result.size() == max) return result; + return result.size() <= max; } - } + }); + return result; } @@ -1411,7 +1321,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } private synchronized void buildFiles(final String pattern) { - final SearchResult files = getFiles(pattern, MAX_FILES); + final SearchResult files = getFiles(pattern, MAX_FILES, myFileChooseByName); check(); @@ -1434,7 +1344,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA private synchronized void buildSymbols(final String pattern) { - final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS); + final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS, mySymbolsChooseByName); check(); if (symbols.size() > 0) { @@ -1522,7 +1432,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } check(); - final SearchResult classes = getClasses(pattern, showAll.get(), MAX_CLASSES); + final SearchResult classes = getClasses(pattern, showAll.get(), MAX_CLASSES, myClassChooseByName); check(); @@ -1544,10 +1454,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - private SearchResult getSymbols(String pattern, final int max) { + private SearchResult getSymbols(String pattern, final int max, ChooseByNamePopup chooseByNamePopup) { final SearchResult symbols = new SearchResult(); final GlobalSearchScope scope = GlobalSearchScope.projectScope(project); - mySymbolsChooseByName.getProvider().filterElements(mySymbolsChooseByName, pattern, false, + chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, false, myProgressIndicator, new Processor<Object>() { @Override public boolean process(Object o) { @@ -1567,9 +1477,12 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA return symbols; } - private SearchResult getClasses(String pattern, boolean includeLibs, final int max) { + private SearchResult getClasses(String pattern, boolean includeLibs, final int max, ChooseByNamePopup chooseByNamePopup) { final SearchResult classes = new SearchResult(); - myClassChooseByName.getProvider().filterElements(myClassChooseByName, pattern, includeLibs, + if (chooseByNamePopup == null) { + return classes; + } + chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, includeLibs, myProgressIndicator, new Processor<Object>() { @Override public boolean process(Object o) { @@ -1584,15 +1497,18 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } }); if (!includeLibs && classes.isEmpty()) { - return getClasses(pattern, true, max); + return getClasses(pattern, true, max, chooseByNamePopup); } return classes; } - private SearchResult getFiles(final String pattern, final int max) { + private SearchResult getFiles(final String pattern, final int max, ChooseByNamePopup chooseByNamePopup) { final SearchResult files = new SearchResult(); + if (chooseByNamePopup == null) { + return files; + } final GlobalSearchScope scope = GlobalSearchScope.projectScope(project); - myFileChooseByName.getProvider().filterElements(myFileChooseByName, pattern, true, + chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, true, myProgressIndicator, new Processor<Object>() { @Override public boolean process(Object o) { @@ -1786,10 +1702,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA myClassChooseByName = ChooseByNamePopup.createPopup(project, myClassModel, (PsiElement)null); mySymbolsChooseByName = ChooseByNamePopup.createPopup(project, mySymbolsModel, (PsiElement)null); project.putUserData(ChooseByNamePopup.CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, null); - myActionModel = createActionModel(); + myActionProvider = createActionProvider(); myConfigurables.clear(); - fillConfigurablesIds(null, new IdeConfigurablesGroup().getConfigurables()); - fillConfigurablesIds(null, new ProjectConfigurablesGroup(project).getConfigurables()); + fillConfigurablesIds(null, ShowSettingsUtilImpl.getConfigurables(project, true)); } } @@ -1797,14 +1712,16 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA buildRecentFiles(""); } - private GotoActionModel createActionModel() { - return new GotoActionModel(project, myFocusComponent, myEditor, myFile) { + private GotoActionItemProvider createActionProvider() { + GotoActionModel model = new GotoActionModel(project, myFocusComponent, myEditor, myFile) { @Override protected MatchMode actionMatches(String pattern, @NotNull AnAction anAction) { - return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE) - .matches(anAction.getTemplatePresentation().getText()) ? MatchMode.NAME : MatchMode.NONE; + String text = anAction.getTemplatePresentation().getText(); + return text != null && NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE) + .matches(text) ? MatchMode.NAME : MatchMode.NONE; } }; + return new GotoActionItemProvider(model); } @SuppressWarnings("SSBasedInspection") @@ -1880,57 +1797,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA }); } - private List<MatchResult> collectResults(String pattern, String[] names, final ChooseByNameModel model) { - if (names == null) return Collections.emptyList(); - pattern = ChooseByNamePopup.getTransformedPattern(pattern, model); - pattern = DefaultChooseByNameItemProvider.getNamePattern(model, pattern); - if (model != myFileModel && model != myActionModel && !pattern.startsWith("*") && pattern.length() > 1) { - pattern = "*" + pattern; - } - final ArrayList<MatchResult> results = new ArrayList<MatchResult>(); - final String p = pattern; - MinusculeMatcher matcher = new MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE) { - @Override - public boolean matches(@NotNull String name) { - if (!(model instanceof GotoActionModel) && p.indexOf(' ') > 0 && name.trim().indexOf(' ') < 0) { - return false; - } - return super.matches(name); - } - }; - MatchResult result; - - for (String name : names) { - check(); - result = null; - if (model instanceof CustomMatcherModel) { - try { - result = ((CustomMatcherModel)model).matches(name, pattern) ? new MatchResult(name, 0, true) : null; - if (result != null && model == myActionModel) { - ((CustomMatcherModel)model).matches(name, pattern); - } - } - catch (Exception ignore) { - } - } - else { - result = matcher.matches(name) ? new MatchResult(name, matcher.matchingDegree(name), matcher.isStartMatch(name)) : null; - } - - if (result != null) { - results.add(result); - } - } - - Collections.sort(results, new Comparator<MatchResult>() { - @Override - public int compare(MatchResult o1, MatchResult o2) { - return o1.compareTo(o2); - } - }); - return results; - } - public ActionCallback cancel() { myProgressIndicator.cancel(); myDone.setRejected(); @@ -1945,10 +1811,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void run() { try { final SearchResult result - = id == WidgetID.CLASSES ? getClasses(pattern, showAll.get(), DEFAULT_MORE_STEP_COUNT) - : id == WidgetID.FILES ? getFiles(pattern, DEFAULT_MORE_STEP_COUNT) + = id == WidgetID.CLASSES ? getClasses(pattern, showAll.get(), DEFAULT_MORE_STEP_COUNT, myClassChooseByName) + : id == WidgetID.FILES ? getFiles(pattern, DEFAULT_MORE_STEP_COUNT, myFileChooseByName) : id == WidgetID.RUN_CONFIGURATIONS ? getConfigurations(pattern, DEFAULT_MORE_STEP_COUNT) - : id == WidgetID.SYMBOLS ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT) + : id == WidgetID.SYMBOLS ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT, mySymbolsChooseByName) : id == WidgetID.ACTIONS ? getActionsOrSettings(pattern, DEFAULT_MORE_STEP_COUNT, true) : id == WidgetID.SETTINGS ? getActionsOrSettings(pattern, DEFAULT_MORE_STEP_COUNT, false) : new SearchResult(); @@ -2030,8 +1896,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA if (lock != null) { synchronized (lock) { myClassModel = null; - myActionModel = null; - myActions = null; + myActionProvider = null; mySymbolsModel = null; myConfigurables.clear(); myFocusComponent = null; diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java index 58bef64556c2..e2c79cffef46 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java @@ -125,8 +125,10 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap updater.addSubtreeToUpdate(rootNode); return; } - - updater.addSubtreeToUpdateByElement(element); + final PsiElement parent = element.getParent(); + if (parent == null || !updater.addSubtreeToUpdateByElement(parent)) { + updater.addSubtreeToUpdateByElement(element); + } } else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_TYPES)){ updater.addSubtreeToUpdate(rootNode); diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java index 85964857c5d0..2e55b4aee11a 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java @@ -21,6 +21,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -32,11 +33,13 @@ public class MarkExcludeRootAction extends MarkRootActionBase { public void actionPerformed(AnActionEvent e) { VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); - String message = files.length == 1 ? FileUtil.toSystemDependentName(files[0].getPath()) : files.length + " selected files"; - final int rc = Messages.showOkCancelDialog(e.getData(CommonDataKeys.PROJECT), getPromptText(message), "Mark as Excluded", - Messages.getQuestionIcon()); - if (rc != Messages.OK) { - return; + if (Registry.is("ide.hide.excluded.files")) { + String message = files.length == 1 ? FileUtil.toSystemDependentName(files[0].getPath()) : files.length + " selected files"; + final int rc = Messages.showOkCancelDialog(e.getData(CommonDataKeys.PROJECT), getPromptText(message), "Mark as Excluded", + Messages.getQuestionIcon()); + if (rc != Messages.OK) { + return; + } } super.actionPerformed(e); } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java index 815c3e8815ac..ac2326da6dac 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java @@ -22,7 +22,9 @@ import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.impl.DirectoryIndex; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; @@ -38,23 +40,24 @@ import java.util.List; public abstract class MarkRootActionBase extends DumbAwareAction { @Override public void actionPerformed(AnActionEvent e) { - final Module module = e.getData(LangDataKeys.MODULE); - VirtualFile[] vFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); - if (module == null || vFiles == null) { + VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); + final Module module = getModule(e, files); + if (module == null) { return; } + final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel(); - for (VirtualFile vFile : vFiles) { - ContentEntry entry = findContentEntry(model, vFile); + for (VirtualFile file : files) { + ContentEntry entry = findContentEntry(model, file); if (entry != null) { final SourceFolder[] sourceFolders = entry.getSourceFolders(); for (SourceFolder sourceFolder : sourceFolders) { - if (Comparing.equal(sourceFolder.getFile(), vFile)) { + if (Comparing.equal(sourceFolder.getFile(), file)) { entry.removeSourceFolder(sourceFolder); break; } } - modifyRoots(vFile, entry); + modifyRoots(file, entry); } } ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -66,7 +69,7 @@ public abstract class MarkRootActionBase extends DumbAwareAction { }); } - protected abstract void modifyRoots(VirtualFile vFile, ContentEntry entry); + protected abstract void modifyRoots(VirtualFile file, ContentEntry entry); @Nullable public static ContentEntry findContentEntry(@NotNull ModuleRootModel model, @NotNull VirtualFile vFile) { @@ -82,21 +85,22 @@ public abstract class MarkRootActionBase extends DumbAwareAction { @Override public void update(AnActionEvent e) { - Module module = e.getData(LangDataKeys.MODULE); RootsSelection selection = getSelection(e); - boolean enabled = module != null && (!selection.mySelectedRoots.isEmpty() || !selection.mySelectedDirectories.isEmpty()) && isEnabled(selection, module); - e.getPresentation().setVisible(enabled); - e.getPresentation().setEnabled(enabled); + doUpdate(e, e.getData(LangDataKeys.MODULE), selection); + } + + protected void doUpdate(@NotNull AnActionEvent e, @Nullable Module module, @NotNull RootsSelection selection) { + boolean enabled = module != null && (!selection.mySelectedRoots.isEmpty() || !selection.mySelectedDirectories.isEmpty()) + && selection.mySelectedExcludeRoots.isEmpty() && isEnabled(selection, module); + e.getPresentation().setEnabledAndVisible(enabled); } protected abstract boolean isEnabled(@NotNull RootsSelection selection, @NotNull Module module); protected static RootsSelection getSelection(AnActionEvent e) { - Module module = e.getData(LangDataKeys.MODULE); VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY); - if (module == null || files == null) { - return RootsSelection.EMPTY; - } + Module module = getModule(e, files); + if (module == null) return RootsSelection.EMPTY; RootsSelection selection = new RootsSelection(); final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(module.getProject()).getFileIndex(); @@ -105,7 +109,14 @@ public abstract class MarkRootActionBase extends DumbAwareAction { return RootsSelection.EMPTY; } if (!fileIndex.isInContent(file)) { - return RootsSelection.EMPTY; + ExcludeFolder excludeFolder = ProjectRootsUtil.findExcludeFolder(module, file); + if (excludeFolder != null) { + selection.mySelectedExcludeRoots.add(excludeFolder); + continue; + } + else { + return RootsSelection.EMPTY; + } } SourceFolder folder; if (Comparing.equal(fileIndex.getSourceRootForFile(file), file) && ((folder = ProjectRootsUtil.findSourceFolder(module, file)) != null)) { @@ -121,10 +132,39 @@ public abstract class MarkRootActionBase extends DumbAwareAction { return selection; } + @Nullable + private static Module getModule(@NotNull AnActionEvent e, @Nullable VirtualFile[] files) { + if (files == null) return null; + Module module = e.getData(LangDataKeys.MODULE); + if (module == null) { + module = findParentModule(e.getProject(), files); + } + return module; + } + + @Nullable + private static Module findParentModule(@Nullable Project project, @NotNull VirtualFile[] files) { + if (project == null) return null; + Module result = null; + DirectoryIndex index = DirectoryIndex.getInstance(project); + for (VirtualFile file : files) { + Module module = index.getInfoForFile(file).getModule(); + if (module == null) return null; + if (result == null) { + result = module; + } + else if (!result.equals(module)) { + return null; + } + } + return result; + } + protected static class RootsSelection { public static final RootsSelection EMPTY = new RootsSelection(); public List<SourceFolder> mySelectedRoots = new ArrayList<SourceFolder>(); + public List<ExcludeFolder> mySelectedExcludeRoots = new ArrayList<ExcludeFolder>(); public List<VirtualFile> mySelectedDirectories = new ArrayList<VirtualFile>(); public boolean myHaveSelectedFilesUnderSourceRoots; } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java index cf2724dc039f..0689fe13c2d3 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java @@ -18,12 +18,15 @@ package com.intellij.ide.projectView.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ExcludeFolder; import com.intellij.openapi.roots.SourceFolder; import com.intellij.openapi.roots.ui.configuration.ModuleSourceRootEditHandler; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import java.util.Set; @@ -33,9 +36,16 @@ import java.util.Set; */ public class UnmarkRootAction extends MarkRootActionBase { @Override - public void update(AnActionEvent e) { - super.update(e); - RootsSelection selection = getSelection(e); + protected void doUpdate(@NotNull AnActionEvent e, @Nullable Module module, @NotNull RootsSelection selection) { + if (!Registry.is("ide.hide.excluded.files") && !selection.mySelectedExcludeRoots.isEmpty() + && selection.mySelectedDirectories.isEmpty() && selection.mySelectedRoots.isEmpty()) { + e.getPresentation().setEnabledAndVisible(true); + e.getPresentation().setText("Cancel Exclusion"); + return; + } + + super.doUpdate(e, module, selection); + Set<JpsModuleSourceRootType<?>> selectedRootTypes = new HashSet<JpsModuleSourceRootType<?>>(); for (SourceFolder root : selection.mySelectedRoots) { selectedRootTypes.add(root.getRootType()); @@ -60,6 +70,12 @@ public class UnmarkRootAction extends MarkRootActionBase { return selection.mySelectedDirectories.isEmpty() && !selection.mySelectedRoots.isEmpty(); } - protected void modifyRoots(VirtualFile vFile, ContentEntry entry) { + protected void modifyRoots(VirtualFile file, ContentEntry entry) { + for (ExcludeFolder excludeFolder : entry.getExcludeFolders()) { + if (file.equals(excludeFolder.getFile())) { + entry.removeExcludeFolder(excludeFolder); + break; + } + } } } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java index ee05f0a10283..13ba91900521 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java @@ -25,6 +25,7 @@ import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleFileIndex; @@ -32,7 +33,9 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.roots.impl.DirectoryIndex; +import com.intellij.openapi.roots.impl.DirectoryInfo; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; @@ -123,7 +126,7 @@ public class ProjectViewDirectoryHelper { final Module module = fileIndex.getModuleForFile(psiDirectory.getVirtualFile()); final ModuleFileIndex moduleFileIndex = module == null ? null : ModuleRootManager.getInstance(module).getFileIndex(); if (!settings.isFlattenPackages() || skipDirectory(psiDirectory)) { - processPsiDirectoryChildren(psiDirectory, directoryChildrenInProject(psiDirectory), + processPsiDirectoryChildren(psiDirectory, directoryChildrenInProject(fileIndex, psiDirectory), children, fileIndex, null, settings, withSubDirectories); } else { // source directory in "flatten packages" mode @@ -137,7 +140,13 @@ public class ProjectViewDirectoryHelper { continue; } VirtualFile directoryFile = subdir.getVirtualFile(); - if (fileIndex.isIgnored(directoryFile)) continue; + + if (Registry.is("ide.hide.excluded.files")) { + if (fileIndex.isExcluded(directoryFile)) continue; + } + else { + if (FileTypeRegistry.getInstance().isFileIgnored(directoryFile)) continue; + } if (withSubDirectories) { children.add(new PsiDirectoryNode(project, subdir, settings)); @@ -163,9 +172,9 @@ public class ProjectViewDirectoryHelper { return topLevelContentRoots; } - private PsiElement[] directoryChildrenInProject(PsiDirectory psiDirectory) { + private PsiElement[] directoryChildrenInProject(ProjectFileIndex fileIndex, PsiDirectory psiDirectory) { VirtualFile dir = psiDirectory.getVirtualFile(); - if (myIndex.getInfoForDirectory(dir) != null) { + if (isInProject(dir)) { return psiDirectory.getChildren(); } @@ -189,6 +198,16 @@ public class ProjectViewDirectoryHelper { return PsiUtilCore.toPsiElementArray(directoriesOnTheWayToContentRoots); } + private boolean isInProject(VirtualFile dir) { + DirectoryInfo directoryInfo = myIndex.getInfoForFile(dir); + if (directoryInfo.isInProject()) return true; + + if (!Registry.is("ide.hide.excluded.files")) { + return directoryInfo.isExcluded(); + } + return false; + } + // used only for non-flatten packages mode public void processPsiDirectoryChildren(final PsiDirectory psiDir, PsiElement[] children, @@ -211,7 +230,7 @@ public class ProjectViewDirectoryHelper { vFile = dir.getVirtualFile(); if (!vFile.equals(projectFileIndex.getSourceRootForFile(vFile))) { // if is not a source root if (viewSettings.isHideEmptyMiddlePackages() && !skipDirectory(psiDir) && isEmptyMiddleDirectory(dir, true)) { - processPsiDirectoryChildren(dir, directoryChildrenInProject(dir), + processPsiDirectoryChildren(dir, directoryChildrenInProject(projectFileIndex, dir), container, projectFileIndex, moduleFileIndex, viewSettings, withSubDirectories); // expand it recursively continue; } diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java index a010828cd8ec..16aa930b806a 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java @@ -26,6 +26,7 @@ import com.intellij.ide.projectView.impl.ProjectRootsUtil; import com.intellij.ide.projectView.impl.ProjectViewImpl; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileTypes.FileTypeRegistry; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; @@ -38,6 +39,7 @@ import com.intellij.openapi.roots.ui.configuration.ModuleSourceRootEditHandler; import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VFileProperty; import com.intellij.openapi.vfs.VfsUtilCore; @@ -183,9 +185,14 @@ public class PsiDirectoryNode extends BasePsiNode<PsiDirectory> implements Navig return false; } - final Project project = value.getProject(); - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); - return !fileIndex.isIgnored(file); + if (Registry.is("ide.hide.excluded.files")) { + final Project project = value.getProject(); + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); + return !fileIndex.isExcluded(file); + } + else { + return !FileTypeRegistry.getInstance().isFileIgnored(file); + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java index b1c1e25e978c..eb22b72eb810 100644 --- a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java +++ b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java @@ -129,7 +129,7 @@ public class TraverseUIStarter implements ApplicationStarter { System.out.println("Searchable options index builder completed"); - ((ApplicationEx)ApplicationManager.getApplication()).exit(true); + ((ApplicationEx)ApplicationManager.getApplication()).exit(true, true); } private static void processFileTemplates(Element configurableElement) { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java new file mode 100644 index 000000000000..a6e6c8fdf658 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java @@ -0,0 +1,169 @@ +/* + * 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.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()) { + ContainerUtil.addIfNotNull(actions, myActionManager.getAction(id)); + } + } else { + actions.addAll(myModel.myActionsMap.keySet()); + } + + List<ActionWrapper> actionWrappers = ContainerUtil.newArrayList(); + for (AnAction action : actions) { + MatchMode mode = myModel.actionMatches(pattern, action); + if (mode != MatchMode.NONE) { + actionWrappers.add(new ActionWrapper(action, myModel.myActionsMap.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); + } + +} diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index 45fe6a9a074c..91f0d3368521 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -16,34 +16,28 @@ 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.ActionFromOptionDescriptorProvider; +import com.intellij.ide.actions.ShowSettingsUtilImpl; 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.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; -import com.intellij.openapi.actionSystem.impl.ActionManagerImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.SearchableConfigurable; -import com.intellij.openapi.options.ex.IdeConfigurablesGroup; -import com.intellij.openapi.options.ex.ProjectConfigurablesGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiFile; -import com.intellij.ui.ColorUtil; -import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.LayeredIcon; -import com.intellij.ui.LightColors; +import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; +import com.intellij.ui.speedSearch.SpeedSearchUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.EmptyIcon; @@ -58,9 +52,10 @@ import java.awt.*; import java.util.*; import java.util.List; +import static com.intellij.ui.SimpleTextAttributes.STYLE_PLAIN; +import static com.intellij.ui.SimpleTextAttributes.STYLE_SEARCH_MATCH; + public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, Comparator<Object>, EdtSortingModel { - @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; @@ -103,10 +98,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C } } myIndex = SearchableOptionsRegistrar.getInstance(); - fillConfigurablesNames(new IdeConfigurablesGroup().getConfigurables()); - if (project != null) { - fillConfigurablesNames(new ProjectConfigurablesGroup(project).getConfigurables()); - } + fillConfigurablesNames(ShowSettingsUtilImpl.getConfigurables(project, true)); } private void fillConfigurablesNames(Configurable[] configurables) { @@ -151,13 +143,61 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C public void saveInitialCheckBoxState(boolean state) { } + public static class MatchedValue implements Comparable<MatchedValue> { + @NotNull public final Comparable value; + @NotNull final String pattern; + + MatchedValue(@NotNull Comparable value, @NotNull String pattern) { + this.value = value; + this.pattern = pattern; + } + + @Nullable + private String getValueText() { + if (value instanceof OptionDescription) return ((OptionDescription)value).getHit(); + if (!(value instanceof ActionWrapper)) return null; + return ((ActionWrapper)value).getAction().getTemplatePresentation().getText(); + } + + private int getMatchingDegree() { + String text = getValueText(); + if (text != null) { + if (StringUtil.equalsIgnoreCase(StringUtil.trimEnd(text, "..."), pattern)) return 3; + if (StringUtil.startsWithIgnoreCase(text, pattern)) return 2; + if (StringUtil.containsIgnoreCase(text, pattern)) return 1; + } + return 0; + } + + @Override + public int compareTo(@NotNull MatchedValue o) { + if (value instanceof OptionDescription && !(o.value instanceof OptionDescription)) { + return 1; + } + if (o.value instanceof OptionDescription && !(value instanceof OptionDescription)) { + return -1; + } + + if (value instanceof ActionWrapper && o.value instanceof ActionWrapper && ApplicationManager.getApplication().isDispatchThread()) { + boolean p1Enable = ((ActionWrapper)value).isAvailable(); + boolean p2enable = ((ActionWrapper)o.value).isAvailable(); + if (p1Enable && !p2enable) return -1; + if (!p1Enable && p2enable) return 1; + } + + int diff = o.getMatchingDegree() - getMatchingDegree(); + //noinspection unchecked + return diff != 0 ? diff : value.compareTo(o.value); + } + } + @Override public ListCellRenderer getListCellRenderer() { return new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(@NotNull final JList list, - final Object value, + final Object matchedValue, final int index, final boolean isSelected, final boolean cellHasFocus) { final JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(IdeBorderFactory.createEmptyBorder(2)); @@ -165,21 +205,40 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C Color bg = UIUtil.getListBackground(isSelected); panel.setBackground(bg); + if (matchedValue instanceof String) { //... + final JBLabel label = new JBLabel((String)matchedValue); + label.setIcon(EMPTY_ICON); + panel.add(label, BorderLayout.WEST); + return panel; + } + Color groupFg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getLabelDisabledForeground(); + Object value = ((MatchedValue) matchedValue).value; + String pattern = ((MatchedValue)matchedValue).pattern; + + SimpleColoredComponent nameComponent = new SimpleColoredComponent(); + nameComponent.setBackground(bg); + panel.add(nameComponent, BorderLayout.CENTER); + if (value instanceof ActionWrapper) { final ActionWrapper actionWithParentGroup = (ActionWrapper)value; final AnAction anAction = actionWithParentGroup.getAction(); final Presentation templatePresentation = anAction.getTemplatePresentation(); - final Icon icon = templatePresentation.getIcon(); final Color fg = defaultActionForeground(isSelected, actionWithParentGroup.getPresentation()); - final JLabel actionLabel = createActionLabel(anAction, templatePresentation.getText(), fg, bg, icon); - panel.add(actionLabel, BorderLayout.WEST); + panel.add(createIconLabel(templatePresentation.getIcon()), BorderLayout.WEST); + + appendWithColoredMatches(nameComponent, templatePresentation.getText(), pattern, fg, isSelected); - final String groupName = actionWithParentGroup.getGroupName(); + final Shortcut shortcut = preferKeyboardShortcut(KeymapManager.getInstance().getActiveKeymap().getShortcuts(getActionId(anAction))); + if (shortcut != null) { + nameComponent.append(" (" + KeymapUtil.getShortcutText(shortcut) + ")", new SimpleTextAttributes(STYLE_PLAIN, groupFg)); + } + + String groupName = actionWithParentGroup.getAction() instanceof ApplyIntentionAction ? null : actionWithParentGroup.getGroupName(); if (groupName != null) { final JLabel groupLabel = new JLabel(groupName); groupLabel.setBackground(bg); @@ -189,7 +248,9 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C } else if (value instanceof OptionDescription) { if (!isSelected) { - panel.setBackground(UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY); + Color descriptorBg = UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY; + panel.setBackground(descriptorBg); + nameComponent.setBackground(descriptorBg); } String hit = ((OptionDescription)value).getHit(); if (hit == null) { @@ -200,23 +261,31 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C hit = hit.replace(" ", " "); //avoid extra spaces from mnemonics and xml conversion final Color fg = UIUtil.getListForeground(isSelected); - final JLabel label = new JLabel(hit.trim()); - label.setIcon(EMPTY_ICON); - label.setForeground(fg); - label.setBackground(bg); - panel.add(label, BorderLayout.WEST); + + appendWithColoredMatches(nameComponent, hit.trim(), pattern, fg, isSelected); + + panel.add(new JLabel(EMPTY_ICON), BorderLayout.WEST); + final JLabel settingsLabel = new JLabel(getGroupName((OptionDescription)value)); settingsLabel.setForeground(groupFg); settingsLabel.setBackground(bg); panel.add(settingsLabel, BorderLayout.EAST); } - else if (value instanceof String) { - final JBLabel label = new JBLabel((String)value); - label.setIcon(EMPTY_ICON); - panel.add(label, BorderLayout.WEST); - } return panel; } + + private void appendWithColoredMatches(SimpleColoredComponent nameComponent, String name, String pattern, Color fg, boolean selected) { + final SimpleTextAttributes plain = new SimpleTextAttributes(STYLE_PLAIN, fg); + final SimpleTextAttributes highlighted = new SimpleTextAttributes(null, fg, null, STYLE_SEARCH_MATCH); + List<TextRange> fragments = ContainerUtil.newArrayList(); + if (selected) { + int matchStart = StringUtil.indexOfIgnoreCase(name, pattern, 0); + if (matchStart >= 0) { + fragments.add(TextRange.from(matchStart, pattern.length())); + } + } + SpeedSearchUtil.appendColoredFragments(nameComponent, name, fragments, plain, highlighted); + } }; } @@ -224,6 +293,18 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C return myActionManager.getId(anAction); } + private static JLabel createIconLabel(final Icon icon) { + final LayeredIcon layeredIcon = new LayeredIcon(2); + layeredIcon.setIcon(EMPTY_ICON, 0); + if (icon != null && icon.getIconWidth() <= EMPTY_ICON.getIconWidth() && icon.getIconHeight() <= EMPTY_ICON.getIconHeight()) { + layeredIcon + .setIcon(icon, 1, (-icon.getIconWidth() + EMPTY_ICON.getIconWidth()) / 2, (EMPTY_ICON.getIconHeight() - icon.getIconHeight()) / 2); + } + + return new JLabel(layeredIcon); + } + + protected JLabel createActionLabel(final AnAction anAction, final String anActionName, final Color fg, final Color bg, final Icon icon) { @@ -256,23 +337,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C public int compare(@NotNull Object o1, @NotNull Object o2) { if (ChooseByNameBase.EXTRA_ELEM.equals(o1)) return 1; if (ChooseByNameBase.EXTRA_ELEM.equals(o2)) return -1; - - if (o1 instanceof OptionDescription && !(o2 instanceof OptionDescription)) { - return 1; - } - if (o2 instanceof OptionDescription && !(o1 instanceof OptionDescription)) { - return -1; - } - - if (o1 instanceof OptionDescription) { - return ((OptionDescription)o1).compareTo(o2); - } - - if (o1 instanceof ActionWrapper && o2 instanceof ActionWrapper) { - return ((ActionWrapper)o1).compareTo((ActionWrapper)o2); - } - - return StringUtil.compare(getFullName(o1), getFullName(o2), true); + return ((MatchedValue) o1).compareTo((MatchedValue)o2); } public static AnActionEvent updateActionBeforeShow(AnAction anAction, DataContext dataContext) { @@ -293,107 +358,17 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C @Override @NotNull public String[] getNames(boolean checkBoxState) { - final LinkedHashSet<String> result = new LinkedHashSet<String>(); - result.add(INTENTIONS_KEY); - for (AnAction action : myActionsMap.keySet()) { - result.add(getActionId(action)); - } - if (checkBoxState) { - final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds(); - for (String id : ids) { - result.add(id); - } - } - result.add(SETTINGS_KEY); - return ArrayUtil.toStringArray(result); + return ArrayUtil.EMPTY_STRING_ARRAY; } @Override @NotNull public Object[] getElementsByName(final String id, final boolean checkBoxState, final String pattern) { - List<Object> objects = new ArrayList<Object>(); - final AnAction act = myActionManager.getAction(id); - DataContext dataContext = DataManager.getInstance().getDataContext(myContextComponent); - if (act != null) { - final HashMap<AnAction, String> map = new HashMap<AnAction, String>(); - final MatchMode matchMode = actionMatches(pattern, act); - final String groupName = myActionsMap.get(act); - if (map.put(act, groupName) == null) { - objects.add(new ActionWrapper(act, groupName, matchMode, dataContext)); - } - 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); - if (anAction != null) { - objects.add(new ActionWrapper(anAction, null, MatchMode.NON_MENU, dataContext)); - } - } - } - } else if (Comparing.strEqual(id, INTENTIONS_KEY)) { - for (String intentionText : myIntentions.keySet()) { - final ApplyIntentionAction intentionAction = myIntentions.get(intentionText); - if (actionMatches(pattern, intentionAction) != MatchMode.NONE) { - objects.add(new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext)); - } - } - } - 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(); - } - } - for (OptionDescription description : optionDescriptions) { - for (ActionFromOptionDescriptorProvider converter : ActionFromOptionDescriptorProvider.EP.getExtensions()) { - AnAction action = converter.provide(description); - if (action != null) { - String title = getGroupName(description); - objects.add(new ActionWrapper(action, title, MatchMode.NAME, dataContext)); - } - objects.add(description); - } - } - } - } - return objects.toArray(new Object[objects.size()]); + return ArrayUtil.EMPTY_OBJECT_ARRAY; } @NotNull - private String getGroupName(@NotNull OptionDescription description) { + String getGroupName(@NotNull OptionDescription description) { String id = description.getConfigurableId(); String name = myConfigurablesNames.get(id); String settings = SystemInfo.isMac ? "Preferences" : "Settings"; @@ -459,10 +434,8 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C } @Override - public String getElementName(final Object element) { - if (element instanceof OptionDescription) return ((OptionDescription)element).getHit(); - if (!(element instanceof ActionWrapper)) return null; - return ((ActionWrapper)element).getAction().getTemplatePresentation().getText(); + public String getElementName(final Object mv) { + return ((MatchedValue) mv).getValueText(); } @Override @@ -485,7 +458,10 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C return MatchMode.DESCRIPTION; } final String groupName = myActionsMap.get(anAction); - return groupName != null && text != null && matcher.matches(groupName + " " + text, compiledPattern) ? MatchMode.GROUP : MatchMode.NONE; + if (groupName == null) { + return text != null && matcher.matches(text, compiledPattern) ? MatchMode.NON_MENU : MatchMode.NONE; + } + return text != null && matcher.matches(groupName + " " + text, compiledPattern) ? MatchMode.GROUP : MatchMode.NONE; } @Nullable @@ -498,7 +474,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C } @NotNull - private Pattern getPattern(@NotNull String pattern) { + Pattern getPattern(@NotNull String pattern) { String converted = convertPattern(pattern.trim()); Pattern compiledPattern = myCompiledPattern; if (compiledPattern != null && !Comparing.strEqual(converted, compiledPattern.getPattern())) { @@ -528,7 +504,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C NONE, INTENTION, NAME, DESCRIPTION, GROUP, NON_MENU } - private static String convertPattern(String pattern) { + static String convertPattern(String pattern) { final int eol = pattern.indexOf('\n'); if (eol != -1) { pattern = pattern.substring(0, eol); @@ -632,7 +608,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C return new Perl5Matcher(); } }; - private PatternMatcher getMatcher() { + PatternMatcher getMatcher() { return myMatcher.get(); } @@ -660,20 +636,13 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C @Override public int compareTo(@NotNull ActionWrapper o) { - if (ApplicationManager.getApplication().isDispatchThread()) { - boolean p1Enable = visible(); - boolean p2enable = o.visible(); - if (p1Enable && !p2enable) return -1; - if (!p1Enable && p2enable) return 1; - } - int compared = myMode.compareTo(o.getMode()); return compared != 0 ? compared : StringUtil.compare(myAction.getTemplatePresentation().getText(), o.getAction().getTemplatePresentation().getText(), true); } - private boolean visible() { + private boolean isAvailable() { return getPresentation().isEnabledAndVisible(); } |