diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java index 228259d6fd27..0917188945c8 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaStructuralSearchProfile.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.JavaDummyHolder; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.javadoc.PsiDocToken; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; @@ -832,10 +833,13 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { case UIUtil.TEXT_HIERARCHY: if (variableNode != null) { final PsiElement parent = variableNode.getParent(); - if (parent instanceof PsiJavaCodeReferenceElement && parent.getParent() instanceof PsiTypeElement || - parent instanceof PsiClass) { - return true; + if (parent instanceof PsiJavaCodeReferenceElement) { + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiTypeElement || grandParent instanceof PsiReferenceList || + grandParent instanceof PsiReferenceExpression) return true; } + else if (parent instanceof PsiClass) return true; + else if (isMemberSurroundedByClass(parent)) return true; } return false; case UIUtil.EXPECTED_TYPE: @@ -856,10 +860,11 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } return variableNode != null && variableNode.getParent() instanceof PsiExpression; case UIUtil.MINIMUM_ZERO: - if (target) return false; - return isApplicableCount(variableNode, false); + if (target || variableNode == null) return false; + return isApplicableMinCount(variableNode) || isApplicableMinMaxCount(variableNode); case UIUtil.MAXIMUM_UNLIMITED: - return isApplicableCount(variableNode, true); + if (variableNode == null) return false; + return isApplicableMaxCount(variableNode) || isApplicableMinMaxCount(variableNode); case UIUtil.REFERENCE: if (completePattern || variableNode == null) return false; if (variableNode instanceof PsiLiteralExpression && ((PsiLiteralExpression)variableNode).getValue() instanceof String) return true; @@ -869,63 +874,90 @@ public class JavaStructuralSearchProfile extends StructuralSearchProfile { } } - private static boolean isApplicableCount(@Nullable PsiElement variableNode, boolean max) { - if (variableNode != null) { - final PsiElement parent = variableNode.getParent(); - if (max && parent instanceof PsiLocalVariable) { - final PsiLocalVariable localVariable = (PsiLocalVariable)parent; - if (localVariable instanceof PsiResourceVariable) return false; - if (localVariable.getTypeElement().isInferredType()) return false; - return true; - } - else if (max && parent instanceof PsiField) { - return true; - } - if (parent instanceof PsiMember && !(parent instanceof PsiTypeParameter)) { - final PsiMember member = (PsiMember)parent; - final PsiClass aClass = member.getContainingClass(); - if (aClass == null) { - return false; - } - final String name = aClass.getName(); - return name != null && !"_Dummy_".equals(name); - } - final PsiElement grandParent = parent.getParent(); - if (!max && parent instanceof PsiReferenceExpression && grandParent instanceof PsiReferenceExpression) { - return true; - } - if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) { - return true; - } - if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) { - if (max) { - return true; - } - else { - final PsiElement greatGrandParent = grandParent.getParent(); - return !(greatGrandParent instanceof PsiCodeBlock) || !(greatGrandParent.getParent() instanceof JavaDummyHolder); - } - } - if (!max && grandParent instanceof PsiVariable && - PsiTreeUtil.isAncestor(((PsiVariable)grandParent).getInitializer(), variableNode, true)) { - return true; - } - if (grandParent instanceof PsiReferenceList) { - if (!max) return true; - final PsiReferenceList referenceList = (PsiReferenceList)grandParent; - final PsiElement greatGrandParent = referenceList.getParent(); - return !(greatGrandParent instanceof PsiClass) || ((PsiClass)greatGrandParent).getExtendsList() != referenceList; - } - if (grandParent instanceof PsiParameterList || grandParent instanceof PsiExpressionList || - grandParent instanceof PsiTypeParameterList || grandParent instanceof PsiResourceList) { - return true; - } - if (grandParent instanceof PsiTypeElement && grandParent.getParent() instanceof PsiReferenceParameterList) return true; - if (grandParent instanceof PsiPolyadicExpression && max) return true; + private static boolean isApplicableMinCount(@NotNull PsiElement variableNode) { + final PsiElement parent = variableNode.getParent(); + if (parent instanceof PsiBreakStatement) return true; + if (parent instanceof PsiContinueStatement) return true; + + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiReferenceList) return true; + if (parent instanceof PsiReferenceExpression) { + if (grandParent instanceof PsiReferenceExpression) return true; + if (grandParent instanceof PsiReturnStatement) return true; + if (grandParent instanceof PsiAssertStatement) return ((PsiAssertStatement)grandParent).getAssertDescription() == parent; + if (grandParent instanceof PsiNameValuePair) return ((PsiNameValuePair)grandParent).getValue() == parent; + } + if (grandParent instanceof PsiVariable) { + return ((PsiVariable)grandParent).getInitializer() == parent; + } + if (grandParent instanceof PsiNewExpression) { + return ((PsiNewExpression)grandParent).getArrayInitializer() != null; + } + if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) { + final PsiElement greatGrandParent = grandParent.getParent(); + return !(greatGrandParent instanceof PsiCodeBlock) || + !(greatGrandParent.getParent() instanceof JavaDummyHolder) || + PsiTreeUtil.getChildrenOfAnyType(greatGrandParent, PsiStatement.class, PsiComment.class).size() > 1; } return false; } + private static boolean isApplicableMaxCount(@NotNull PsiElement variableNode) { + final PsiElement parent = variableNode.getParent(); + if (parent instanceof PsiLocalVariable) { + final PsiLocalVariable localVariable = (PsiLocalVariable)parent; + if (localVariable instanceof PsiResourceVariable) return false; + if (localVariable.getTypeElement().isInferredType()) return false; + return true; + } + if (parent instanceof PsiField) return true; + + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiPolyadicExpression) return true; + if (grandParent instanceof PsiExpressionStatement && hasSemicolon(grandParent)) return true; + if (grandParent instanceof PsiReferenceList) { + final PsiElement greatGrandParent = grandParent.getParent(); + return !(greatGrandParent instanceof PsiClass) || ((PsiClass)greatGrandParent).getExtendsList() != grandParent || + greatGrandParent instanceof PsiTypeParameter; + } + return false; + } + + private static boolean isApplicableMinMaxCount(@NotNull PsiElement variableNode) { + if (variableNode instanceof PsiDocToken) return true; + final PsiElement parent = variableNode.getParent(); + if (isMemberSurroundedByClass(parent)) return true; + final PsiElement grandParent = parent.getParent(); + if (grandParent instanceof PsiCatchSection && parent instanceof PsiParameter) return true; + if (grandParent instanceof PsiAnnotation && !(grandParent.getParent().getNextSibling() instanceof PsiErrorElement)) return true; + if (grandParent instanceof PsiParameterList || grandParent instanceof PsiExpressionList || + grandParent instanceof PsiTypeParameterList || grandParent instanceof PsiResourceList || + grandParent instanceof PsiArrayInitializerExpression || grandParent instanceof PsiArrayInitializerMemberValue) { + return true; + } + if (grandParent instanceof PsiTypeElement) { + final PsiElement greatGrandParent = grandParent.getParent(); + if (greatGrandParent instanceof PsiReferenceParameterList || greatGrandParent instanceof PsiClass) return true; + } + if (grandParent instanceof PsiAnnotationParameterList && parent instanceof PsiNameValuePair) { + return ((PsiNameValuePair)parent).getNameIdentifier() == variableNode; + } + return false; + } + + private static boolean isMemberSurroundedByClass(PsiElement parent) { + if (!(parent instanceof PsiMember) || parent instanceof PsiTypeParameter) { + return false; + } + final PsiMember member = (PsiMember)parent; + final PsiClass aClass = member.getContainingClass(); + if (aClass == null) { + return false; + } + final String name = aClass.getName(); + return name != null && !"_Dummy_".equals(name); + } + private static boolean hasSemicolon(PsiElement element) { PsiElement lastChild = element.getLastChild(); while (lastChild instanceof PsiComment || lastChild instanceof PsiWhiteSpace) { diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java index b6ba5ee14f21..13713b301c8a 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertFieldToAtomicIntention.java @@ -11,7 +11,6 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; import com.intellij.psi.impl.AllowedApiFilterExtension; @@ -138,7 +137,7 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction static void postProcessVariable(@NotNull PsiVariable var, @NotNull String toType) { Project project = var.getProject(); - if (var instanceof PsiField || CodeStyleSettingsManager.getSettings(project).getCustomSettings(JavaCodeStyleSettings.class).GENERATE_FINAL_LOCALS) { + if (var instanceof PsiField || JavaCodeStyleSettings.getInstance(var.getContainingFile()).GENERATE_FINAL_LOCALS) { PsiModifierList modifierList = assertNotNull(var.getModifierList()); WriteAction.run(() -> { if (var.getInitializer() == null) { diff --git a/platform/lang-api/src/com/intellij/application/options/CodeStyle.java b/platform/lang-api/src/com/intellij/application/options/CodeStyle.java index 244696d48796..bf933a00a004 100644 --- a/platform/lang-api/src/com/intellij/application/options/CodeStyle.java +++ b/platform/lang-api/src/com/intellij/application/options/CodeStyle.java @@ -254,4 +254,14 @@ public class CodeStyle { } } + /** + * @param project The project to check. + * @return {@code true} if the project uses its own project code style, {@code false} if global (application-level) code style settings + * are used. + */ + public static boolean usesOwnSettings(@NotNull Project project) { + //noinspection deprecation + return CodeStyleSettingsManager.getInstance(project).USE_PER_PROJECT_SETTINGS; + } + } diff --git a/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java deleted file mode 100644 index 2e0a462bcacc..000000000000 --- a/platform/lang-api/src/com/intellij/ide/actions/SearchEverywhereContributor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package com.intellij.ide.actions; - -import com.intellij.openapi.extensions.ExtensionPointName; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; - -/** - * @author Konstantin Bulenkov - */ -public interface SearchEverywhereContributor { - ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.searchEverywhereContributor"); - @NotNull - String getSearchProviderId(); - - @NotNull - String getGroupName(); - - int getSortWeight(); - - static List getProvidersSorted() { - return Arrays.stream(EP_NAME.getExtensions()) - .sorted(Comparator.comparingInt(SearchEverywhereContributor::getSortWeight)) - .collect(Collectors.toList()); - } -} diff --git a/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java new file mode 100644 index 000000000000..a11ebfe83a64 --- /dev/null +++ b/platform/lang-api/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereContributor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + */ +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.ide.IdeBundle; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.ui.IdeUICustomization; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Konstantin Bulenkov + */ +//todo generic? #UX-1 +public interface SearchEverywhereContributor { + + String ALL_CONTRIBUTORS_GROUP_ID = SearchEverywhereContributor.class.getSimpleName() + ".All"; + + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.searchEverywhereContributor"); + + @NotNull + String getSearchProviderId(); + + @NotNull + String getGroupName(); + + default String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName()); + } + + int getSortWeight(); + + default ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { + return new ContributorSearchResult(Collections.emptyList(), false); + } + + default List search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator) { + return search(project, pattern, everywhere, progressIndicator, -1).getItems(); + } + + void processSelectedItem(Object selected); + + //todo any way to listen project in contributor + ListCellRenderer getElementsRenderer(Project project); + + static List getProvidersSorted() { + return Arrays.stream(EP_NAME.getExtensions()) + .sorted(Comparator.comparingInt(SearchEverywhereContributor::getSortWeight)) + .collect(Collectors.toList()); + } + + class ContributorSearchResult { + private final List items; + private final boolean hasMoreItems; + + public ContributorSearchResult(List items, boolean hasMoreItems) { + this.items = items; + this.hasMoreItems = hasMoreItems; + } + + public List getItems() { + return items; + } + + public boolean hasMoreItems() { + return hasMoreItems; + } + + public boolean isEmpty() { + return items.isEmpty(); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java index a0f9b251427d..6342f2229f7b 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java @@ -16,6 +16,9 @@ package com.intellij.ide.actions; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager; import com.intellij.ide.util.gotoByName.*; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ModalityState; @@ -332,6 +335,24 @@ public abstract class GotoActionBase extends AnAction { }.registerCustomShortcutSet(SearchTextField.SHOW_HISTORY_SHORTCUT, editor); } + protected void showInSearchEverywherePopup(String searchProviderID, AnActionEvent evnt) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); + + SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(evnt.getProject()); + if (seManager.isShown()) { + if (searchProviderID.equals(seManager.getShownContributorID())) { + seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); + } + else { + seManager.setShownContributor(searchProviderID); + } + return; + } + + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + seManager.show(searchProviderID); + } private static boolean historyEnabled() { return !ContainerUtil.isEmpty(ourHistory.get(myInAction)); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java index 2c5011e70bfd..9fde066ef9a4 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoClassAction.java @@ -18,6 +18,7 @@ package com.intellij.ide.actions; import com.intellij.codeInsight.navigation.NavigationUtil; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.searcheverywhere.ClassSearchEverywhereContributor; import com.intellij.ide.structureView.StructureView; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.ide.structureView.StructureViewTreeElement; @@ -40,6 +41,7 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.playback.commands.ActionCommand; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; @@ -59,6 +61,11 @@ import java.util.List; public class GotoClassAction extends GotoActionBase implements DumbAware { @Override public void actionPerformed(@NotNull AnActionEvent e) { + if (Registry.is("new.search.everywhere")) { + showInSearchEverywherePopup(ClassSearchEverywhereContributor.class.getSimpleName(), e); + return; + } + Project project = e.getProject(); if (project == null) return; diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java index 55da4991a82e..7c448703e1a6 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileAction.java @@ -17,7 +17,11 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.IdeBundle; -import com.intellij.ide.util.gotoByName.*; +import com.intellij.ide.actions.searcheverywhere.FileSearchEverywhereContributor; +import com.intellij.ide.util.gotoByName.ChooseByNameFilter; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileConfiguration; +import com.intellij.ide.util.gotoByName.GotoFileModel; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -27,6 +31,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiFile; @@ -48,6 +53,15 @@ import java.util.List; public class GotoFileAction extends GotoActionBase implements DumbAware { public static final String ID = "GotoFile"; + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + if (Registry.is("new.search.everywhere")) { + showInSearchEverywherePopup(FileSearchEverywhereContributor.class.getSimpleName(), e); + } else { + super.actionPerformed(e); + } + } + @Override public void gotoActionPerformed(AnActionEvent e) { final Project project = e.getData(CommonDataKeys.PROJECT); diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java index 81f183f64fbf..c5dd26007a39 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoSymbolAction.java @@ -16,16 +16,28 @@ package com.intellij.ide.actions; import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.ide.actions.searcheverywhere.SymbolSearchEverywhereContributor; import com.intellij.ide.util.gotoByName.*; import com.intellij.lang.Language; import com.intellij.navigation.ChooseByNameRegistry; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.PsiDocumentManager; import org.jetbrains.annotations.NotNull; public class GotoSymbolAction extends GotoActionBase { + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + if (Registry.is("new.search.everywhere")) { + showInSearchEverywherePopup(SymbolSearchEverywhereContributor.class.getSimpleName(), e); + } else { + super.actionPerformed(e); + } + } + @Override public void gotoActionPerformed(AnActionEvent e) { FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.symbol"); 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 dfe8c747eaf3..d5b49e126514 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java @@ -16,6 +16,8 @@ import com.intellij.execution.runners.ProgramRunner; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.icons.AllIcons; import com.intellij.ide.*; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor; +import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager; import com.intellij.ide.structureView.StructureView; import com.intellij.ide.structureView.StructureViewBuilder; import com.intellij.ide.structureView.StructureViewModel; @@ -563,8 +565,27 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA public void actionPerformed(AnActionEvent e, MouseEvent me) { if (Registry.is("new.search.everywhere")) { //todo[mikhail.sokolov] show new UI + String searchProviderID = SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID; + + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); + FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE + "." + searchProviderID); + + SearchEverywhereManager seManager = SearchEverywhereManager.getInstance(e.getProject()); + if (seManager.isShown()) { + if (searchProviderID.equals(seManager.getShownContributorID())) { + seManager.setShowNonProjectItems(!seManager.isShowNonProjectItems()); + } + else { + seManager.setShownContributor(searchProviderID); + } + return; + } + + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + seManager.show(searchProviderID); return; } + if (myBalloon != null && myBalloon.isVisible()) { showAll.set(!showAll.get()); myNonProjectCheckBox.setSelected(showAll.get()); @@ -702,7 +723,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA .setRequestFocus(true) .createPopup(); myBalloon.getContent().setBorder(JBUI.Borders.empty()); - final Window window = WindowManager.getInstance().suggestParentWindow(project); + project.getMessageBus().connect(myBalloon).subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() { @@ -712,18 +733,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } }); - Component parent = UIUtil.findUltimateParent(window); + registerDataProvider(panel, project); - final RelativePoint showPoint; - if (parent != null) { - int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; - if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { - height -= 20; - } - showPoint = new RelativePoint(parent, new Point((parent.getSize().width - panel.getPreferredSize().width) / 2, height)); - } else { - showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); - } + final RelativePoint showPoint = calculateShowingPoint(e, panel); myList.setFont(UIUtil.getListFont()); myBalloon.show(showPoint); initSearchActions(myBalloon, myPopupField); @@ -732,6 +744,26 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA FeatureUsageTracker.getInstance().triggerFeatureUsed(IdeActions.ACTION_SEARCH_EVERYWHERE); } + @NotNull + private static RelativePoint calculateShowingPoint(AnActionEvent e, JComponent showingContent) { + Project project = e.getProject(); + final Window window = project != null + ? WindowManager.getInstance().suggestParentWindow(project) + : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + Component parent = UIUtil.findUltimateParent(window); + final RelativePoint showPoint; + if (parent != null) { + int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; + if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { + height -= 20; + } + showPoint = new RelativePoint(parent, new Point((parent.getSize().width - showingContent.getPreferredSize().width) / 2, height)); + } else { + showPoint = JBPopupFactory.getInstance().guessBestPopupLocation(e.getDataContext()); + } + return showPoint; + } + private void showSettings() { myPopupField.setText(""); final SearchListModel model = new SearchListModel(); @@ -1286,7 +1318,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA enum WidgetID {CLASSES, FILES, ACTIONS, SETTINGS, SYMBOLS, RUN_CONFIGURATIONS} - @SuppressWarnings({"SSBasedInspection", "unchecked"}) + @SuppressWarnings({"SSBasedInspection", "unchecked", "Duplicates"}) private class CalcThread implements Runnable { private final Project project; private final String pattern; @@ -2305,14 +2337,15 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - static class MoreIndex { - volatile int classes = -1; - volatile int files = -1; - volatile int actions = -1; - volatile int settings = -1; - volatile int symbols = -1; - volatile int runConfigurations = -1; - volatile int structure = -1; + //todo return private (same for other) #UX-1 + public static class MoreIndex { + public volatile int classes = -1; + public volatile int files = -1; + public volatile int actions = -1; + public volatile int settings = -1; + public volatile int symbols = -1; + public volatile int runConfigurations = -1; + public volatile int structure = -1; public void shift(int index, int shift) { if (runConfigurations >= index) runConfigurations += shift; @@ -2325,17 +2358,17 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - static class TitleIndex { - volatile int topHit = -1; - volatile int recentFiles = -1; - volatile int runConfigurations = -1; - volatile int classes = -1; - volatile int structure = -1; - volatile int files = -1; - volatile int actions = -1; - volatile int settings = -1; - volatile int toolWindows = -1; - volatile int symbols = -1; + public static class TitleIndex { + public volatile int topHit = -1; + public volatile int recentFiles = -1; + public volatile int runConfigurations = -1; + public volatile int classes = -1; + public volatile int structure = -1; + public volatile int files = -1; + public volatile int actions = -1; + public volatile int settings = -1; + public volatile int toolWindows = -1; + public volatile int symbols = -1; final String gotoClassTitle; final String gotoFileTitle; @@ -2408,19 +2441,19 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - static class SearchResult extends ArrayList { + public static class SearchResult extends ArrayList { boolean needMore; } @SuppressWarnings("unchecked") - private static class SearchListModel extends DefaultListModel { + public static class SearchListModel extends DefaultListModel { @SuppressWarnings("UseOfObsoleteCollectionType") Vector myDelegate; - volatile TitleIndex titleIndex = new TitleIndex(); - volatile MoreIndex moreIndex = new MoreIndex(); + public volatile TitleIndex titleIndex = new TitleIndex(); + public volatile MoreIndex moreIndex = new MoreIndex(); - private SearchListModel() { + public SearchListModel() { super(); myDelegate = ReflectionUtil.getField(DefaultListModel.class, this, Vector.class, "delegate"); } @@ -2475,7 +2508,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - static class More extends JPanel { + public static class More extends JPanel { static final More instance = new More(); final JLabel label = new JLabel(" ... more "); @@ -2507,10 +2540,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA .withBackground(UIUtil.getListBackground()); } - private enum HistoryType {PSI, FILE, SETTING, ACTION, RUN_CONFIGURATION} + public enum HistoryType {PSI, FILE, SETTING, ACTION, RUN_CONFIGURATION} @Nullable - private static HistoryType parseHistoryType(@Nullable String name) { + public static HistoryType parseHistoryType(@Nullable String name) { try { return HistoryType.valueOf(name); } catch (Exception e) { @@ -2518,7 +2551,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA } } - private static class HistoryItem { + //todo history maybe unnecessary #UX-1 + public static class HistoryItem { final String pattern, type, fqn; private HistoryItem(String pattern, String type, String fqn) { diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java deleted file mode 100644 index 632320f1c7e9..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereUI.java +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.actions; - -import com.intellij.ui.JBColor; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.components.BorderLayoutPanel; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import javax.swing.border.Border; -import java.awt.*; - -/** - * @author Konstantin Bulenkov - */ -public class SearchEverywhereUI extends BorderLayoutPanel { - private SETab mySelectedTab; - - public SearchEverywhereUI(@Nullable SearchEverywhereContributor selected) { - - } - - private class SETab extends JLabel { - public SETab(String tabName) { - super(tabName); - } - - @Override - public Border getBorder() { - return JBUI.Borders.empty(0, 12); - } - - @Override - public Color getBackground() { - return mySelectedTab == this ? new JBColor(0xdedede, 0x565a5e) : super.getBackground(); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java new file mode 100644 index 000000000000..868935589114 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/ClassSearchEverywhereContributor.java @@ -0,0 +1,78 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.codeInsight.navigation.NavigationUtil; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.NavigationItemListCellRenderer; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoClassModel2; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.ui.IdeUICustomization; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class ClassSearchEverywhereContributor implements SearchEverywhereContributor { + @NotNull + @Override + public String getSearchProviderId() { + return getClass().getSimpleName(); + } + + @NotNull + @Override + public String getGroupName() { + return "Classes"; + } + + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.classes", IdeUICustomization.getInstance().getProjectConceptName()); + } + + @Override + public int getSortWeight() { + return 100; + } + + public SearchEverywhereContributor.ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { + ChooseByNameModel mdl = new GotoClassModel2(project); + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, mdl, (PsiElement)null); + List items = new ArrayList<>(); + boolean[] hasMore = {false}; //todo builder for ContributorSearchResult #UX-1 + popup.getProvider().filterElements(popup, pattern, everywhere, progressIndicator, o -> { + if (SearchEverywhereClassifier.EP_Manager.isClass(o) && !items.contains(o)) { + if (elementsLimit >=0 && items.size() >= elementsLimit) { + hasMore[0] = true; + return false; + } + items.add(o); + + } + return true; + }); + + return new SearchEverywhereContributor.ContributorSearchResult(items, hasMore[0]); + } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return new NavigationItemListCellRenderer(); + } + + @Override + public void processSelectedItem(Object selected) { + if (selected instanceof PsiElement) { + NavigationUtil.activateFileWithPsiElement((PsiElement) selected, true); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java new file mode 100644 index 000000000000..0291347d2253 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/FileSearchEverywhereContributor.java @@ -0,0 +1,90 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.codeInsight.navigation.NavigationUtil; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileModel; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.ui.IdeUICustomization; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class FileSearchEverywhereContributor implements SearchEverywhereContributor { + @NotNull + @Override + public String getSearchProviderId() { + return getClass().getSimpleName(); + } + + @NotNull + @Override + public String getGroupName() { + return "Files"; + } + + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.files", IdeUICustomization.getInstance().getProjectConceptName()); + } + + @Override + public int getSortWeight() { + return 200; + } + + @Override + public ContributorSearchResult search(Project project, String pattern, boolean everywhere, ProgressIndicator progressIndicator, int elementsLimit) { + ChooseByNameModel mdl = createModel(project); + + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, mdl, (PsiElement)null); + List items = new ArrayList<>(); + boolean[] hasMore = {false}; //todo builder for ContributorSearchResult #UX-1 + popup.getProvider().filterElements(popup, pattern, everywhere, + progressIndicator, o -> { + + if (o != null && !items.contains(o)) { + if (elementsLimit >= 0 && items.size() >= elementsLimit) { + hasMore[0] = true; + return false; + } + items.add(o); + } + return true; + }); + + return new ContributorSearchResult(items, hasMore[0]); + } + + @NotNull + private GotoFileModel createModel(Project project) { + return new GotoFileModel(project){ + @Override + public boolean isSlashlessMatchingEnabled() { + return false; + } + }; + } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return createModel(project).getListCellRenderer(); + } + + @Override + public void processSelectedItem(Object selected) { + //todo maybe another elements types + if (selected instanceof PsiElement) { + NavigationUtil.activateFileWithPsiElement((PsiElement) selected, true); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java new file mode 100644 index 000000000000..ce3b42275059 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManager.java @@ -0,0 +1,29 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +/** + * @author Mikhail.Sokolov + */ +public interface SearchEverywhereManager { + + static SearchEverywhereManager getInstance(Project project) { + return ServiceManager.getService(project, SearchEverywhereManager.class); + } + + boolean isShown(); + + void show(@NotNull String selectedContributorID); //todo change to contributor??? UX-1 + + String getShownContributorID(); + + void setShownContributor(@NotNull String newSelectedContributorID); //todo change to contributor??? UX-1 + + boolean isShowNonProjectItems(); + + void setShowNonProjectItems(boolean show); + +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java new file mode 100644 index 000000000000..66735e0cdb25 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereManagerImpl.java @@ -0,0 +1,117 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.wm.WindowManager; +import com.intellij.openapi.wm.impl.IdeFrameImpl; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +public class SearchEverywhereManagerImpl implements SearchEverywhereManager { + + private final Project myProject; + + private JBPopup myBalloon; //todo appropriate names #UX-1 + private final SearchEverywhereUI mySearchEverywhereUI; + + public SearchEverywhereManagerImpl(Project project) { + myProject = project; + + //SearchEverywhereContributor selected = contributors.stream() + // .filter(contributor -> contributor.getSearchProviderId().equals(mySelectedProviderID)) + // .findAny() + // .orElse(null); + List allContributors = SearchEverywhereContributor.getProvidersSorted(); + mySearchEverywhereUI = new SearchEverywhereUI(project, allContributors, null); + } + + @Override + public void show(@NotNull String selectedContributorID) { + if (isShown()) { + setShownContributor(selectedContributorID); + } + else { + mySearchEverywhereUI.setShown(true); + mySearchEverywhereUI.switchToContributor(selectedContributorID); + myBalloon = JBPopupFactory.getInstance().createComponentPopupBuilder(mySearchEverywhereUI, getSearchField()) + .setProject(myProject) + .setResizable(false) + .setModalContext(false) + .setCancelOnClickOutside(true) + .setRequestFocus(true) + .setCancelKeyEnabled(false) + .setCancelCallback(() -> { + mySearchEverywhereUI.clear(); + mySearchEverywhereUI.setShown(false); + return true; + }) + .addUserData("SIMPLE_WINDOW") + .createPopup(); + mySearchEverywhereUI.setSearchFinishedHandler(() -> myBalloon.cancel()); + + RelativePoint showingPoint = calculateShowingPoint(); + if (showingPoint != null) { + myBalloon.show(showingPoint); + } + else { + myBalloon.showInFocusCenter(); + } + } + + } + + @Override + public boolean isShown() { + return myBalloon != null && !myBalloon.isDisposed(); + } + + @Override + public String getShownContributorID() { + return mySearchEverywhereUI.getSelectedContributorID(); + } + + @Override + public void setShownContributor(@NotNull String contributorID) { + if (!contributorID.equals(getShownContributorID())) { + mySearchEverywhereUI.switchToContributor(contributorID); + } + } + + @Override + public boolean isShowNonProjectItems() { + return mySearchEverywhereUI.isUseNonProjectItems(); + } + + @Override + public void setShowNonProjectItems(boolean show) { + mySearchEverywhereUI.setUseNonProjectItems(show); + } + + private RelativePoint calculateShowingPoint() { + final Window window = myProject != null + ? WindowManager.getInstance().suggestParentWindow(myProject) + : KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow(); + Component parent = UIUtil.findUltimateParent(window); + if (parent == null) { + return null; + } + + int height = UISettings.getInstance().getShowMainToolbar() ? 135 : 115; + if (parent instanceof IdeFrameImpl && ((IdeFrameImpl)parent).isInFullScreen()) { + height -= 20; + } + return new RelativePoint(parent, new Point((parent.getSize().width - mySearchEverywhereUI.getPreferredSize().width) / 2, height)); + } + + private JTextField getSearchField() { + return mySearchEverywhereUI.getSearchField(); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java new file mode 100644 index 000000000000..5dca6758ecd6 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SearchEverywhereUI.java @@ -0,0 +1,826 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.actions.SearchEverywhereAction; +import com.intellij.ide.ui.UISettings; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionButton; +import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.util.ProgressIndicatorBase; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.ComponentPopupBuilder; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.ActionCallback; +import com.intellij.openapi.util.Disposer; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.ui.*; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.components.JBCheckBox; +import com.intellij.ui.components.JBList; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.components.fields.ExtendableTextField; +import com.intellij.util.Alarm; +import com.intellij.util.Range; +import com.intellij.util.text.MatcherHolder; +import com.intellij.util.ui.DialogUtil; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.StatusText; +import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.components.BorderLayoutPanel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.event.DocumentEvent; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.*; +import java.util.List; + +import static com.intellij.ide.actions.SearchEverywhereAction.SEARCH_EVERYWHERE_POPUP; + +/** + * @author Konstantin Bulenkov + * @author Mikhail.Sokolov + */ +public class SearchEverywhereUI extends BorderLayoutPanel { + private static final Logger LOG = Logger.getInstance(SearchEverywhereUI.class); + public static final int ELEMENTS_LIMIT = 15; + + private final List allContributors; + private final Project myProject; + + private boolean myShown; + + private SETab mySelectedTab; + private final JTextField mySearchField; + private final JCheckBox myNonProjectCB; + private final List myTabs = new ArrayList<>(); + + private JBPopup myResultsPopup; + private final JBList myResultsList = new JBList<>(); + + private final Map myResultsRanges = new HashMap<>(); + + private CalcThread myCalcThread; + private volatile ActionCallback myCurrentWorker = ActionCallback.DONE; + private int myCalcThreadRestartRequestId = 0; + private final Object myWorkerRestartRequestLock = new Object(); + private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, ApplicationManager.getApplication()); + + private Runnable searchFinishedHandler = () -> {}; + + // todo remove second param #UX-1 + public SearchEverywhereUI(Project project, + List contributors, + @Nullable SearchEverywhereContributor selected) { + myProject = project; + withMinimumWidth(670); + withPreferredWidth(670); + setBackground(JBUI.CurrentTheme.SearchEverywhere.dialogBackground()); + + allContributors = contributors; + + myNonProjectCB = new JBCheckBox(); + myNonProjectCB.setOpaque(false); + myNonProjectCB.setFocusable(false); + + JPanel contributorsPanel = createTabPanel(contributors, selected); + JPanel settingsPanel = createSettingsPanel(); + mySearchField = createSearchField(); + + addToLeft(contributorsPanel); + addToRight(settingsPanel); + addToBottom(mySearchField); + + myResultsList.setCellRenderer(new CompositeCellRenderer()); + + initSearchActions(); + } + + public JTextField getSearchField() { + return mySearchField; + } + + public void setUseNonProjectItems(boolean use) { + myNonProjectCB.setSelected(use); + } + + public boolean isUseNonProjectItems() { + return myNonProjectCB.isSelected(); + } + + public void switchToContributor(String contributorID) { + SETab selectedTab = myTabs.stream() + .filter(tab -> tab.getID().equals(contributorID)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(String.format("Contributor %s is not supported", contributorID))); + switchToTab(selectedTab); + } + + public void setSearchFinishedHandler(@NotNull Runnable searchFinishedHandler) { + this.searchFinishedHandler = searchFinishedHandler; + } + + public String getSelectedContributorID() { + return mySelectedTab.getID(); + } + + public void clear() { + mySearchField.setText(""); + myNonProjectCB.setSelected(false); + } + + public void setShown(boolean shown) { + myShown = shown; + //todo cancel all threads #UX-1 + } + + private void switchToNextTab() { + int currentIndex = myTabs.indexOf(mySelectedTab); + SETab nextTab = currentIndex == myTabs.size() - 1 ? myTabs.get(0) : myTabs.get(currentIndex + 1); + switchToTab(nextTab); + } + + private void switchToTab(SETab tab) { + mySelectedTab = tab; + String text = tab.getContributor() + .map(SearchEverywhereContributor::includeNonProjectItemsText) + .orElse(IdeBundle.message("checkbox.include.non.project.items", IdeUICustomization.getInstance().getProjectConceptName())); + if (text.indexOf(UIUtil.MNEMONIC) != -1) { + DialogUtil.setTextWithMnemonic(myNonProjectCB, text); + } else { + myNonProjectCB.setText(text); + myNonProjectCB.setDisplayedMnemonicIndex(-1); + myNonProjectCB.setMnemonic(0); + } + myNonProjectCB.setSelected(false); + repaint(); + rebuildList(); + } + + private JTextField createSearchField() { + ExtendableTextField searchField = new ExtendableTextField() { + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height = JBUI.scale(29); + return size; + } + }; + + ExtendableTextField.Extension searchExtension = new ExtendableTextField.Extension() { + @Override + public Icon getIcon(boolean hovered) { + return AllIcons.Actions.Search; + } + + @Override + public boolean isIconBeforeText() { + return true; + } + }; + ExtendableTextField.Extension hintExtension = new ExtendableTextField.Extension() { + private final TextIcon icon; + { + icon = new TextIcon(IdeBundle.message("searcheverywhere.switch.scope.hint"), JBColor.GRAY, null, 0); + icon.setFont(RelativeFont.SMALL.derive(getFont())); + } + + @Override + public Icon getIcon(boolean hovered) { + return icon; + } + }; + searchField.setExtensions(searchExtension, hintExtension); + + //todo gap between icon and text #UX-1 + Insets insets = JBUI.CurrentTheme.SearchEverywhere.searchFieldInsets(); + Border border = JBUI.Borders.merge( + JBUI.Borders.empty(insets.top, searchExtension.getPreferredSpace() + insets.left, insets.bottom, hintExtension.getPreferredSpace() + insets.right), + IdeBorderFactory.createBorder(JBUI.CurrentTheme.SearchEverywhere.searchFieldBorderColor(), SideBorder.BOTTOM | SideBorder.TOP), + true); + searchField.setBorder(border); + searchField.setBackground(JBUI.CurrentTheme.SearchEverywhere.searchFieldBackground()); + searchField.setFocusTraversalKeysEnabled(false); + + return searchField; + } + + private JPanel createSettingsPanel() { + JPanel res = new JPanel(); + BoxLayout bl = new BoxLayout(res, BoxLayout.X_AXIS); + res.setLayout(bl); + res.setOpaque(false); + + res.add(myNonProjectCB); + res.add(Box.createHorizontalStrut(JBUI.scale(19))); + + ToggleAction pinAction = new ToggleAction(null, null, AllIcons.General.AutohideOff) { + @Override + public boolean isSelected(AnActionEvent e) { + return UISettings.getInstance().getPinFindInPath(); + } + + @Override + public void setSelected(AnActionEvent e, boolean state) { + UISettings.getInstance().setPinFindInPath(state); + } + }; + ActionButton pinButton = new ActionButton(pinAction, pinAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); + res.add(pinButton); + res.add(Box.createHorizontalStrut(JBUI.scale(10))); + + AnAction emptyAction = new AnAction(AllIcons.General.Filter) { + @Override + public void actionPerformed(AnActionEvent e) {} + }; + ActionButton filterButton = new ActionButton(emptyAction, emptyAction.getTemplatePresentation(), ActionPlaces.UNKNOWN, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); + res.add(filterButton); + res.add(Box.createHorizontalStrut(JBUI.scale(10))); + + return res; + } + + @NotNull + private JPanel createTabPanel(List contributors, @Nullable SearchEverywhereContributor selected) { + JPanel contributorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); + contributorsPanel.setOpaque(false); + + SETab allTab = new SETab(null); + contributorsPanel.add(allTab); + myTabs.add(allTab); + + + contributors.forEach(contributor -> { + SETab tab = new SETab(contributor); + if (contributor == selected) { + switchToTab(tab); + } + contributorsPanel.add(tab); + myTabs.add(tab); + }); + + if (mySelectedTab == null) { + switchToTab(allTab); + } + + return contributorsPanel; + } + + private class SETab extends JLabel { + private final SearchEverywhereContributor myContributor; + + public SETab(SearchEverywhereContributor contributor) { + super(contributor == null ? IdeBundle.message("searcheverywhere.allelements.tab.name") : contributor.getGroupName()); + myContributor = contributor; + Insets insets = JBUI.CurrentTheme.SearchEverywhere.tabInsets(); + setBorder(JBUI.Borders.empty(insets.top, insets.left, insets.bottom, insets.right)); + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + switchToTab(SETab.this); + } + }); + } + + public String getID() { + return getContributor() + .map(SearchEverywhereContributor::getSearchProviderId) + .orElse(SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID); + } + + public Optional getContributor() { + return Optional.ofNullable(myContributor); + } + + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + size.height = JBUI.scale(29); + return size; + } + + @Override + public boolean isOpaque() { + return mySelectedTab == this; + } + + @Override + public Color getBackground() { + return mySelectedTab == this + ? JBUI.CurrentTheme.SearchEverywhere.selectedTabColor() + : super.getBackground(); + } + } + + private void rebuildList() { + assert EventQueue.isDispatchThread() : "Must be EDT"; + if (myCalcThread != null && !myCurrentWorker.isProcessed()) { + myCurrentWorker = myCalcThread.cancel(); + } + if (myCalcThread != null && !myCalcThread.isCanceled()) { + myCalcThread.cancel(); + } + + String pattern = mySearchField != null ? mySearchField.getText() : ""; + + MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); + MatcherHolder.associateMatcher(myResultsList, matcher); + + //assert project != null; + //myRenderer.myProject = project; + synchronized (myWorkerRestartRequestLock) { // this lock together with RestartRequestId should be enough to prevent two CalcThreads running at the same time + final int currentRestartRequest = ++myCalcThreadRestartRequestId; + myCurrentWorker.doWhenProcessed(() -> { + synchronized (myWorkerRestartRequestLock) { + if (currentRestartRequest != myCalcThreadRestartRequestId) { + return; + } + myCalcThread = new CalcThread(myProject, pattern, false); + + myCurrentWorker = myCalcThread.start(); + } + }); + } + } + + private void initSearchActions() { + mySearchField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_TAB && e.getModifiers() == 0) { + switchToNextTab(); + e.consume(); + } + } + }); + + AnAction escape = ActionManager.getInstance().getAction("EditorEscape"); + DumbAwareAction.create(__ -> searchFinishedHandler.run()) + .registerCustomShortcutSet(escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), this); + + mySearchField.getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + rebuildList(); + } + }); + + myNonProjectCB.addItemListener(e -> rebuildList()); + + myResultsList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + e.consume(); + final int i = myResultsList.locationToIndex(e.getPoint()); + if (i != -1) { + ApplicationManager.getApplication().invokeLater(() -> { + myResultsList.setSelectedIndex(i); + elementSelected(i); + }); + } + } + }); + + } + + private void elementSelected(int i) { + Map.Entry entry = myResultsRanges.entrySet().stream() + .filter(e -> e.getKey().containsIndex(i)) + .findAny() + .orElseThrow(() -> new IllegalStateException("Contributor for element is not specified")); + + Boolean isMoreElement = entry.getKey().getMoreElementIndex().map(moreIndex -> moreIndex.equals(i)).orElse(false); + if (isMoreElement) { + showMoreElements(entry.getValue()); + } else { + gotoSelectedItem(entry.getValue()); + } + } + + private void showMoreElements(SearchEverywhereContributor contributor) { + + } + + private void gotoSelectedItem(SearchEverywhereContributor contributor) { + Object value = myResultsList.getSelectedValue(); + stopSearching(); + searchFinishedHandler.run(); + contributor.processSelectedItem(value); + } + + private void stopSearching() { + myAlarm.cancelAllRequests(); + if (myCalcThread != null && !myCalcThread.isCanceled()) { + myCalcThread.cancel(); + } + } + + @SuppressWarnings("Duplicates") //todo remove suppress #UX-1 + private class CalcThread implements Runnable { + private final Project project; + private final String pattern; + private final ProgressIndicator myProgressIndicator = new ProgressIndicatorBase(); + private final ActionCallback myDone = new ActionCallback(); + private final SearchEverywhereAction.SearchListModel myListModel; //todo use usual model #UX-1 + + public CalcThread(Project project, String pattern, boolean reuseModel) { + this.project = project; + this.pattern = pattern; + myListModel = reuseModel ? (SearchEverywhereAction.SearchListModel) myResultsList.getModel() : new SearchEverywhereAction.SearchListModel(); + } + + @Override + public void run() { + try { + check(); + + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> { + // this line must be called on EDT to avoid context switch at clear().append("text") Don't touch. Ask [kb] + myResultsList.getEmptyText().setText("Searching..."); + + if (myResultsList.getModel() instanceof SearchEverywhereAction.SearchListModel) { + //noinspection unchecked + myAlarm.cancelAllRequests(); + myAlarm.addRequest(() -> { + if (!myDone.isRejected()) { + myResultsList.setModel(myListModel); + updatePopup(); + } + }, 50); + } else { + myResultsList.setModel(myListModel); + } + }); + + myResultsRanges.clear(); + SearchEverywhereContributor selectedContributor = mySelectedTab.getContributor().orElse(null); + if (selectedContributor != null) { + runReadAction(() -> addContributorItems(selectedContributor), true); + } else { + for (SearchEverywhereContributor contributor : allContributors) { + runReadAction(() -> addContributorItems(contributor), true); + } + } + updatePopup(); + } + catch (ProcessCanceledException ignore) { + myDone.setRejected(); + } + catch (Exception e) { + LOG.error(e); + myDone.setRejected(); + } + finally { + if (!isCanceled()) { + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> myResultsList.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT)); + updatePopup(); + } + if (!myDone.isProcessed()) { + myDone.setDone(); + } + } + } + + private void addContributorItems(SearchEverywhereContributor contributor) { + SearchEverywhereContributor.ContributorSearchResult + results = contributor.search(project, pattern, isUseNonProjectItems(), myProgressIndicator, ELEMENTS_LIMIT); + if (!results.isEmpty()) { + SwingUtilities.invokeLater(() -> { + if (isCanceled()) return; + + int start = myListModel.getSize(); + for (Object item : results.getItems()) { + myListModel.addElement(item); + } + int end = myListModel.getSize() - 1; + + if (results.hasMoreItems()) { + myListModel.addElement("more"); + } + ResultsRange range = results.hasMoreItems() ? new ResultsRange(start, end, end + 1) : new ResultsRange(start, end); + myResultsRanges.put(range, contributor); + }); + } + } + + private void runReadAction(Runnable action, boolean checkDumb) { + if (!checkDumb || !DumbService.getInstance(project).isDumb()) { + ApplicationManager.getApplication().runReadAction(action); + updatePopup(); + } + } + + protected void check() { + myProgressIndicator.checkCanceled(); + if (myDone.isRejected()) throw new ProcessCanceledException(); + if (!myShown) throw new ProcessCanceledException(); + assert myCalcThread == this : "There are two CalcThreads running before one of them was cancelled"; + } + + private boolean isCanceled() { + return myProgressIndicator.isCanceled() || myDone.isRejected(); + } + + @SuppressWarnings("SSBasedInspection") + private void updatePopup() { + check(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + myListModel.update(); + myResultsList.revalidate(); + myResultsList.repaint(); + + //myRenderer.recalculateWidth(); + if (!myShown) { + return; + } + if (myResultsPopup == null || !myResultsPopup.isVisible()) { + ScrollingUtil.installActions(myResultsList, getSearchField()); + JBScrollPane content = new JBScrollPane(myResultsList) { + { + if (UIUtil.isUnderDarcula()) { + setBorder(null); + } + } + @Override + public Dimension getPreferredSize() { + Dimension size = super.getPreferredSize(); + Dimension listSize = myResultsList.getPreferredSize(); + if (size.height > listSize.height || myResultsList.getModel().getSize() == 0) { + size.height = Math.max(JBUI.scale(30), listSize.height); + } + + if (size.width < getWidth()) { + size.width = getWidth(); + } + + return size; + } + }; + content.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + content.setMinimumSize(new Dimension(getWidth(), 30)); + final ComponentPopupBuilder builder = JBPopupFactory.getInstance() + .createComponentPopupBuilder(content, null); + myResultsPopup = builder + .setRequestFocus(false) + .setCancelKeyEnabled(false) + .setResizable(true) + .setCancelCallback(() -> { + final AWTEvent event = IdeEventQueue.getInstance().getTrueCurrentEvent(); + if (event instanceof MouseEvent) { + final Component comp = ((MouseEvent)event).getComponent(); + if (UIUtil.getWindow(comp) == UIUtil.getWindow(SearchEverywhereUI.this)) { + return false; + } + } + //final boolean canClose = balloon == null || balloon.isDisposed() || (!getSearchField().hasFocus() && !mySkipFocusGain); + //if (canClose) { + // PropertiesComponent.getInstance().setValue("search.everywhere.max.popup.width", Math.max(content.getWidth(), JBUI.scale(600)), JBUI.scale(600)); + //} + return true; + }) + .setShowShadow(false) + .setShowBorder(false) + .createPopup(); + project.putUserData(SEARCH_EVERYWHERE_POPUP, myResultsPopup); + //myResultsPopup.setMinimumSize(new Dimension(myBalloon.getSize().width, 30)); + myResultsPopup.getContent().setBorder(null); + Disposer.register(myResultsPopup, new Disposable() { + @Override + public void dispose() { + project.putUserData(SEARCH_EVERYWHERE_POPUP, null); + ApplicationManager.getApplication().executeOnPooledThread(() -> { + //noinspection SSBasedInspection + SwingUtilities.invokeLater(() -> ActionToolbarImpl.updateAllToolbarsImmediately()); + }); + } + }); + updateResultsPopupBounds(); + myResultsPopup.show(new RelativePoint(SearchEverywhereUI.this, new Point(0, getHeight()))); + + //ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() { + // @Override + // public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) { + // if (action instanceof TextComponentEditorAction) { + // return; + // } + // if (myResultsPopup != null) { + // myResultsPopup.cancel(); + // } + // } + //}, myResultsPopup); + } + else { + myResultsList.revalidate(); + myResultsList.repaint(); + } + ScrollingUtil.ensureSelectionExists(myResultsList); + if (myResultsList.getModel().getSize() > 0) { + updateResultsPopupBounds(); + } + } + }); + } + + public ActionCallback cancel() { + myProgressIndicator.cancel(); + //myDone.setRejected(); + return myDone; + } + + //public ActionCallback insert(final int index, final SearchEverywhereAction.WidgetID id) { + // ApplicationManager.getApplication().executeOnPooledThread(() -> runReadAction(() -> { + // try { + // + // check(); + // SwingUtilities.invokeLater(() -> { + // try { + // int shift = 0; + // int i = index+1; + // for (Object o : result) { + // //noinspection unchecked + // myListModel.insertElementAt(o, i); + // shift++; + // i++; + // } + // SearchEverywhereAction.MoreIndex moreIndex = myListModel.moreIndex; + // myListModel.titleIndex.shift(index, shift); + // moreIndex.shift(index, shift); + // + // if (!result.needMore) { + // switch (id) { + // case CLASSES: moreIndex.classes = -1; break; + // case FILES: moreIndex.files = -1; break; + // case ACTIONS: moreIndex.actions = -1; break; + // case SETTINGS: moreIndex.settings = -1; break; + // case SYMBOLS: moreIndex.symbols = -1; break; + // case RUN_CONFIGURATIONS: moreIndex.runConfigurations = -1; break; + // } + // } + // ScrollingUtil.selectItem(myResultsList, index); + // myDone.setDone(); + // } + // catch (Exception e) { + // myDone.setRejected(); + // } + // }); + // } + // catch (Exception e) { + // myDone.setRejected(); + // } + // }, true)); + // return myDone; + //} + + public ActionCallback start() { + ApplicationManager.getApplication().executeOnPooledThread(this); + return myDone; + } + } + + private class CompositeCellRenderer implements ListCellRenderer { + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + if (isMoreElement(index)) { + return moreRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + + Map.Entry delegateEntry = myResultsRanges.entrySet().stream() + .filter(entry -> entry.getKey().getElementsRange() + .isWithin(index, true)) + .findAny() + .orElseThrow(() -> new IllegalStateException("Contributor for element is not specified")); + + SearchEverywhereContributor contributor = delegateEntry.getValue(); + Component component = contributor.getElementsRenderer(myProject) + .getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + int rangeStart = delegateEntry.getKey().getElementsRange().getFrom(); + boolean allGroupSelected = SearchEverywhereContributor.ALL_CONTRIBUTORS_GROUP_ID.equals(getSelectedContributorID()); + if (allGroupSelected && rangeStart == index) { + return groupTitleRenderer.withDisplayedData(contributor.getGroupName(), component); + } + + return component; + } + + private boolean isMoreElement(int index) { + return myResultsRanges.entrySet().stream() + .map(entry -> entry.getKey().getMoreElementIndex().orElse(null)) + .filter(Objects::nonNull) + .anyMatch(i -> i.equals(index)); + } + } + + private static class ResultsRange { + private final Range elementsRange; + private final Integer moreElementIndex; + + private ResultsRange(int from, int to, Integer moreIndex) { + elementsRange = new Range<>(from, to); + moreElementIndex = moreIndex; + } + + public ResultsRange(int from, int to) { + this(from, to, null); + } + + public Range getElementsRange() { + return elementsRange; + } + + public Optional getMoreElementIndex() { + return Optional.ofNullable(moreElementIndex); + } + + public boolean containsIndex(int i) { + return elementsRange.isWithin(i, true) || (moreElementIndex != null && moreElementIndex.equals(i)); + } + } + + private static final MoreRenderer moreRenderer = new MoreRenderer(); + + public static class MoreRenderer extends JPanel implements ListCellRenderer { + final JLabel label; + + private MoreRenderer() { + super(new BorderLayout()); + label = groupInfoLabel(" ... more "); + add(label, BorderLayout.CENTER); + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + setBackground(UIUtil.getListBackground(isSelected)); + return this; + } + } + + private static final GroupTitleRenderer groupTitleRenderer = new GroupTitleRenderer(); + + public static class GroupTitleRenderer extends JPanel { + + private final JLabel titleLabel; + private final BorderLayout myLayout = new BorderLayout(); + + public GroupTitleRenderer() { + setLayout(myLayout); + setBackground(UIUtil.getListBackground(false)); + titleLabel = groupInfoLabel("Group"); + SeparatorComponent separatorComponent = new SeparatorComponent(titleLabel.getPreferredSize().height / 2, UIUtil.getLabelDisabledForeground(), null); + + + JPanel topPanel = JBUI.Panels.simplePanel(5, 0) + .addToCenter(separatorComponent) + .addToLeft(titleLabel) + .withBorder(JBUI.Borders.empty()) + .withBackground(UIUtil.getListBackground()); + add(topPanel, BorderLayout.NORTH); + } + + public GroupTitleRenderer withDisplayedData(String title, Component itemContent) { + titleLabel.setText(title); + Component prevContent = myLayout.getLayoutComponent(BorderLayout.CENTER); + if (prevContent != null) { + remove(prevContent); + } + add(itemContent, BorderLayout.CENTER); + return this; + } + } + + private static JLabel groupInfoLabel(String text) { + JLabel label = new JLabel(text); + label.setForeground(UIUtil.getLabelDisabledForeground()); + label.setFont(UIUtil.getLabelFont().deriveFont(UIUtil.getFontSize(UIUtil.FontSize.SMALL))); + label.setOpaque(false); + return label; + } + + private void updateResultsPopupBounds() { + int height = myResultsList.getPreferredSize().height + 2; + int width = getWidth(); + myResultsPopup.setSize(JBUI.size(width, height)); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java new file mode 100644 index 000000000000..b9969bab307a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/searcheverywhere/SymbolSearchEverywhereContributor.java @@ -0,0 +1,108 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.ide.actions.searcheverywhere; + +import com.intellij.codeInsight.navigation.NavigationUtil; +import com.intellij.ide.IdeBundle; +import com.intellij.ide.actions.SearchEverywhereClassifier; +import com.intellij.ide.util.NavigationItemListCellRenderer; +import com.intellij.ide.util.gotoByName.ChooseByNameItemProvider; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoSymbolModel2; +import com.intellij.navigation.PsiElementNavigationItem; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.ui.IdeUICustomization; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +public class SymbolSearchEverywhereContributor implements SearchEverywhereContributor { + @NotNull + @Override + public String getSearchProviderId() { + return getClass().getSimpleName(); + } + + @NotNull + @Override + public String getGroupName() { + return "Symbols"; + } + + @Override + public String includeNonProjectItemsText() { + return IdeBundle.message("checkbox.include.non.project.symbols", IdeUICustomization.getInstance().getProjectConceptName()); + } + + @Override + public int getSortWeight() { + return 300; + } + + @Override + public ContributorSearchResult search(Project project, + String pattern, + boolean everywhere, + ProgressIndicator progressIndicator, + int elementsLimit) { + final GlobalSearchScope scope = getProjectScope(project); + ChooseByNameModel model = new GotoSymbolModel2(project); + ChooseByNamePopup popup = ChooseByNamePopup.createPopup(project, model, (PsiElement)null); + final ChooseByNameItemProvider provider = popup.getProvider(); + + List symbols = new ArrayList<>(); + boolean[] hasMore = {false}; + provider.filterElements(popup, pattern, everywhere,progressIndicator, o -> { + if (SearchEverywhereClassifier.EP_Manager.isSymbol(o) && !symbols.contains(o)) { + PsiElement element = null; + if (o instanceof PsiElement) { + element = (PsiElement)o; + } + else if (o instanceof PsiElementNavigationItem) { + element = ((PsiElementNavigationItem)o).getTargetElement(); + } + VirtualFile virtualFile = SearchEverywhereClassifier.EP_Manager.getVirtualFile(o); + //some elements are non-physical like DB columns + boolean isElementWithoutFile = element != null && element.getContainingFile() == null; + boolean isFileInScope = virtualFile != null && (everywhere || scope.accept(virtualFile)); + boolean isSpecialElement = element == null && virtualFile == null; //all Rider elements don't have any psi elements within + if (isElementWithoutFile || isFileInScope || isSpecialElement) { + symbols.add(o); + } + } + hasMore[0] = symbols.size() >= elementsLimit; + return !hasMore[0]; + }); + + return new ContributorSearchResult(symbols, hasMore[0]); + } + + @NotNull + private static GlobalSearchScope getProjectScope(@NotNull Project project) { + final GlobalSearchScope scope = SearchEverywhereClassifier.EP_Manager.getProjectScope(project); + if (scope != null) return scope; + return GlobalSearchScope.projectScope(project); + } + + @Override + public ListCellRenderer getElementsRenderer(Project project) { + return new NavigationItemListCellRenderer(); + } + + @Override + public void processSelectedItem(Object selected) { + //todo maybe another elements types + if (selected instanceof PsiElement) { + NavigationUtil.activateFileWithPsiElement((PsiElement) selected, true); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java deleted file mode 100644 index b903e28dfa0e..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ClassSearchEverywhereContributor.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.util.gotoByName; - -import com.intellij.ide.actions.SearchEverywhereContributor; -import org.jetbrains.annotations.NotNull; - -/** - * @author Konstantin Bulenkov - */ -public class ClassSearchEverywhereContributor implements SearchEverywhereContributor { - @NotNull - @Override - public String getSearchProviderId() { - return "Class"; - } - - @NotNull - @Override - public String getGroupName() { - return "Classes"; - } - - @Override - public int getSortWeight() { - return 100; - } -} diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java deleted file mode 100644 index 99f75d3d7af5..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/FileSearchEverywhereContributor.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.util.gotoByName; - -import com.intellij.ide.actions.SearchEverywhereContributor; -import org.jetbrains.annotations.NotNull; - -/** - * @author Konstantin Bulenkov - */ -public class FileSearchEverywhereContributor implements SearchEverywhereContributor { - @NotNull - @Override - public String getSearchProviderId() { - return getClass().getSimpleName(); - } - - @NotNull - @Override - public String getGroupName() { - return "Files"; - } - - @Override - public int getSortWeight() { - return 200; - } -} diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java deleted file mode 100644 index b3399f114b15..000000000000 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/SymbolSearchEverywhereContributor.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -package com.intellij.ide.util.gotoByName; - -import com.intellij.ide.actions.SearchEverywhereContributor; -import org.jetbrains.annotations.NotNull; - -/** - * @author Konstantin Bulenkov - */ -public class SymbolSearchEverywhereContributor implements SearchEverywhereContributor { - @NotNull - @Override - public String getSearchProviderId() { - return getClass().getSimpleName(); - } - - @NotNull - @Override - public String getGroupName() { - return "Symbols"; - } - - @Override - public int getSortWeight() { - return 300; - } -} diff --git a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java index 43b759999056..0503376e05d7 100644 --- a/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java +++ b/platform/lang-impl/src/com/intellij/openapi/paths/PathReferenceProviderBase.java @@ -25,6 +25,8 @@ public abstract class PathReferenceProviderBase implements PathReferenceProvider int offset = range.getStartOffset(); int endOffset = range.getEndOffset(); final String elementText = psiElement.getText(); + if (elementText == null) + return false; for (DynamicContextProvider provider: Extensions.getExtensions(DynamicContextProvider.EP_NAME)) { final int dynamicOffset = provider.getOffset(psiElement, offset, elementText); if (dynamicOffset == -1) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java index 805f6889a816..dc22436cfcb8 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java @@ -29,7 +29,6 @@ import com.intellij.openapi.options.Configurable; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.lineIndent.LineIndentProvider; import com.intellij.psi.codeStyle.lineIndent.LineIndentProviderEP; import org.jetbrains.annotations.NotNull; @@ -78,11 +77,6 @@ public class CodeStyleFacadeImpl extends CodeStyleFacade { return CodeStyle.getProjectOrDefaultSettings(myProject).getLineSeparator(); } - @Override - public boolean projectUsesOwnSettings() { - return myProject != null && CodeStyleSettingsManager.getInstance(myProject).USE_PER_PROJECT_SETTINGS; - } - @Override public boolean isUnsuitableCodeStyleConfigurable(final Configurable c) { return false; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index 7450a4b8b02d..17400fcde29e 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -51,14 +51,11 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting private final ThreadLocal myCurrentFormattingMode = ThreadLocal.withInitial(() -> FormattingMode.REFORMAT); - private final FormatterTagHandler myTagHandler; - private final Project myProject; @NonNls private static final String DUMMY_IDENTIFIER = "xxx"; public CodeStyleManagerImpl(Project project) { myProject = project; - myTagHandler = new FormatterTagHandler(getSettings()); } @Override @@ -83,35 +80,38 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } ASTNode treeElement = element.getNode(); - final PsiElement formatted = new CodeFormatterFacade(getSettings(), element.getLanguage(), canChangeWhiteSpacesOnly).processElement(treeElement).getPsi(); + final PsiFile file = element.getContainingFile(); + final PsiElement formatted = + new CodeFormatterFacade(getSettings(file), element.getLanguage(), canChangeWhiteSpacesOnly) + .processElement(treeElement).getPsi(); if (!canChangeWhiteSpacesOnly) { - return postProcessElement(formatted); + return postProcessElement(file, formatted); } return formatted; } - private PsiElement postProcessElement(@NotNull final PsiElement formatted) { + private static PsiElement postProcessElement(@NotNull PsiFile file, @NotNull final PsiElement formatted) { PsiElement result = formatted; - if (getSettings().FORMATTER_TAGS_ENABLED && formatted instanceof PsiFile) { - postProcessEnabledRanges((PsiFile) formatted, formatted.getTextRange(), getSettings()); + if (getSettings(file).FORMATTER_TAGS_ENABLED && formatted instanceof PsiFile) { + postProcessEnabledRanges((PsiFile) formatted, formatted.getTextRange(), getSettings(file)); } else { for (PostFormatProcessor postFormatProcessor : Extensions.getExtensions(PostFormatProcessor.EP_NAME)) { - result = postFormatProcessor.processElement(result, getSettings()); + result = postFormatProcessor.processElement(result, getSettings(file)); } } return result; } - private void postProcessText(@NotNull final PsiFile file, @NotNull final TextRange textRange) { - if (!getSettings().FORMATTER_TAGS_ENABLED) { + private static void postProcessText(@NotNull final PsiFile file, @NotNull final TextRange textRange) { + if (!getSettings(file).FORMATTER_TAGS_ENABLED) { TextRange currentRange = textRange; for (final PostFormatProcessor myPostFormatProcessor : Extensions.getExtensions(PostFormatProcessor.EP_NAME)) { - currentRange = myPostFormatProcessor.processText(file, currentRange, getSettings()); + currentRange = myPostFormatProcessor.processText(file, currentRange, getSettings(file)); } } else { - postProcessEnabledRanges(file, textRange, getSettings()); + postProcessEnabledRanges(file, textRange, getSettings(file)); } } @@ -180,7 +180,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(file); transformAllChildren(treeElement); - final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(), file.getLanguage()); + final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(file), file.getLanguage()); codeFormatter.setReformatContext(reformatContext); LOG.assertTrue(file.isValid(), "File name: " + file.getName() + " , class: " + file.getClass().getSimpleName()); @@ -191,7 +191,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting CaretPositionKeeper caretKeeper = null; if (editor != null) { - caretKeeper = new CaretPositionKeeper(editor, getSettings(), file.getLanguage()); + caretKeeper = new CaretPositionKeeper(editor, getSettings(file), file.getLanguage()); } if (FormatterUtil.isFormatterCalledExplicitly()) { @@ -259,10 +259,10 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } } - private PsiElement reformatRangeImpl(final @NotNull PsiElement element, - final int startOffset, - final int endOffset, - boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException { + private static PsiElement reformatRangeImpl(final @NotNull PsiElement element, + final int startOffset, + final int endOffset, + boolean canChangeWhiteSpacesOnly) throws IncorrectOperationException { LOG.assertTrue(element.isValid()); CheckUtil.checkWritable(element); if( !SourceTreeToPsiMap.hasTreeElement( element ) ) @@ -271,10 +271,11 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } ASTNode treeElement = element.getNode(); - final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(), element.getLanguage()); + final PsiFile file = element.getContainingFile(); + final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(file), element.getLanguage()); final PsiElement formatted = codeFormatter.processRange(treeElement, startOffset, endOffset).getPsi(); - return canChangeWhiteSpacesOnly ? formatted : postProcessElement(formatted); + return canChangeWhiteSpacesOnly ? formatted : postProcessElement(file, formatted); } @@ -290,6 +291,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting if (fileViewProvider instanceof MultiplePsiFilesPerDocumentFileViewProvider) { containingFile = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage()); } + assert containingFile != null; TextRange textRange = addedElement.getTextRange(); final Document document = fileViewProvider.getDocument(); @@ -300,8 +302,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(containingFile); if (builder != null) { - final FormattingModel model = CoreFormatterUtil.buildModel(builder, containingFile, getSettings(), FormattingMode.REFORMAT); - FormatterEx.getInstanceEx().formatAroundRange(model, getSettings(), containingFile, textRange); + final FormattingModel model = CoreFormatterUtil.buildModel(builder, containingFile, getSettings(containingFile), FormattingMode.REFORMAT); + FormatterEx.getInstanceEx().formatAroundRange(model, getSettings(containingFile), containingFile, textRange); } adjustLineIndent(containingFile, textRange); @@ -411,6 +413,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } @Override + @Deprecated public boolean isLineToBeIndented(@NotNull PsiFile file, int offset) { if (!SourceTreeToPsiMap.hasTreeElement(file)) { return false; @@ -440,7 +443,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting return false; } */ - if (getSettings().getCommonSettings(file.getLanguage()).KEEP_FIRST_COLUMN_COMMENT && isCommentToken(element)) { + if (getSettings(file).getCommonSettings(file.getLanguage()).KEEP_FIRST_COLUMN_COMMENT && isCommentToken(element)) { if (IndentHelper.getInstance().getIndent(myProject, file.getFileType(), element, true) == 0) { return false; } @@ -568,20 +571,23 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } @Override + @Deprecated public Indent getIndent(String text, FileType fileType) { int indent = IndentHelperImpl.getIndent(CodeStyle.getSettings(myProject).getIndentOptions(fileType), text, true); int indentLevel = indent / IndentHelperImpl.INDENT_FACTOR; int spaceCount = indent - indentLevel * IndentHelperImpl.INDENT_FACTOR; - return new IndentImpl(getSettings(), indentLevel, spaceCount, fileType); + return new IndentImpl(CodeStyle.getSettings(myProject), indentLevel, spaceCount, fileType); } @Override + @Deprecated public String fillIndent(Indent indent, FileType fileType) { IndentImpl indent1 = (IndentImpl)indent; int indentLevel = indent1.getIndentLevel(); int spaceCount = indent1.getSpaceCount(); + final CodeStyleSettings settings = CodeStyle.getSettings(myProject); if (indentLevel < 0) { - spaceCount += indentLevel * getSettings().getIndentSize(fileType); + spaceCount += indentLevel * settings.getIndentSize(fileType); indentLevel = 0; if (spaceCount < 0) { spaceCount = 0; @@ -589,9 +595,9 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } else { if (spaceCount < 0) { - int v = (-spaceCount + getSettings().getIndentSize(fileType) - 1) / getSettings().getIndentSize(fileType); + int v = (-spaceCount + settings.getIndentSize(fileType) - 1) / settings.getIndentSize(fileType); indentLevel -= v; - spaceCount += v * getSettings().getIndentSize(fileType); + spaceCount += v * settings.getIndentSize(fileType); if (indentLevel < 0) { indentLevel = 0; } @@ -601,14 +607,15 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } @Override + @Deprecated public Indent zeroIndent() { - return new IndentImpl(getSettings(), 0, 0, null); + return new IndentImpl(CodeStyle.getSettings(myProject), 0, 0, null); } @NotNull - private CodeStyleSettings getSettings() { - return CodeStyleSettingsManager.getSettings(myProject); + private static CodeStyleSettings getSettings(@NotNull PsiFile file) { + return CodeStyle.getSettings(file); } @Override @@ -729,7 +736,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting RangeMarker myBeforeCaretRangeMarker; String myCaretIndentToRestore; int myVisualColumnToRestore = -1; - boolean myBlankLineIndentPreserved = true; + boolean myBlankLineIndentPreserved; CaretPositionKeeper(@NotNull Editor editor, @NotNull CodeStyleSettings settings, @NotNull Language language) { myEditor = editor; @@ -749,11 +756,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting private static boolean isBlankLineIndentPreserved(@NotNull CodeStyleSettings settings, @NotNull Language language) { CommonCodeStyleSettings langSettings = settings.getCommonSettings(language); - if (langSettings != null) { - CommonCodeStyleSettings.IndentOptions indentOptions = langSettings.getIndentOptions(); - return indentOptions != null && indentOptions.KEEP_INDENTS_ON_EMPTY_LINES; - } - return false; + CommonCodeStyleSettings.IndentOptions indentOptions = langSettings.getIndentOptions(); + return indentOptions != null && indentOptions.KEEP_INDENTS_ON_EMPTY_LINES; } private void initRestoreInfo(int caretOffset) { @@ -857,8 +861,8 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting } } - private void postProcessEnabledRanges(@NotNull final PsiFile file, @NotNull TextRange range, CodeStyleSettings settings) { - List enabledRanges = myTagHandler.getEnabledRanges(file.getNode(), range); + private static void postProcessEnabledRanges(@NotNull final PsiFile file, @NotNull TextRange range, CodeStyleSettings settings) { + List enabledRanges = new FormatterTagHandler(getSettings(file)).getEnabledRanges(file.getNode(), range); int delta = 0; for (TextRange enabledRange : enabledRanges) { enabledRange = enabledRange.shiftRight(delta); diff --git a/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java b/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java index 826f8800f09b..1103bc808397 100644 --- a/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java +++ b/platform/platform-api/src/com/intellij/codeStyle/CodeStyleFacade.java @@ -106,7 +106,5 @@ public abstract class CodeStyleFacade { */ public abstract String getLineSeparator(); - public abstract boolean projectUsesOwnSettings(); - public abstract boolean isUnsuitableCodeStyleConfigurable(Configurable c); } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties index f0e3cbcfa9ea..03fcb9e9c6eb 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/darcula.properties @@ -214,4 +214,9 @@ Popup.Header.inactiveBackground=434649 Popup.Border.color=616161 Popup.Border.inactiveColor=565656 Popup.Toolbar.background=3c3f41 -Popup.Toolbar.Border.color=4a4e52 \ No newline at end of file +Popup.Toolbar.Border.color=4a4e52 + +SearchEverywhere.Dialog.background=45494a +SearchEverywhere.Tab.selected.background=555a5e +SearchEverywhere.SearchField.background=3c3f41 +SearchEverywhere.SearchField.Border.color=646464 \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties index a7fb9fcf58a9..0415eebbd1fb 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties @@ -202,4 +202,9 @@ Popup.Header.inactiveBackground=ededed Popup.Border.color=808080 Popup.Border.inactiveColor=aaaaaa Popup.Toolbar.background=f7f7f7 -Popup.Toolbar.Border.color=f7f7f7 \ No newline at end of file +Popup.Toolbar.Border.color=f7f7f7 + +SearchEverywhere.Dialog.background=f2f2f2 +SearchEverywhere.Tab.selected.background=dedede +SearchEverywhere.SearchField.background=ffffff +SearchEverywhere.SearchField.Border.color=bdbdbd \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties index fb3ab913a1f9..a4ef6675a19e 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf_native.properties @@ -224,4 +224,9 @@ Popup.Header.inactiveBackground=ededed Popup.Border.color=808080 Popup.Border.inactiveColor=aaaaaa Popup.Toolbar.background=f7f7f7 -Popup.Toolbar.Border.color=f7f7f7 \ No newline at end of file +Popup.Toolbar.Border.color=f7f7f7 + +SearchEverywhere.Dialog.background=f2f2f2 +SearchEverywhere.Tab.selected.background=dedede +SearchEverywhere.SearchField.background=ffffff +SearchEverywhere.SearchField.Border.color=bdbdbd \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java index c9d3a9907d97..81795744337f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java @@ -16,6 +16,7 @@ package com.intellij.ide.ui.search; +import com.intellij.application.options.CodeStyle; import com.intellij.codeStyle.CodeStyleFacade; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManagerConfigurable; @@ -415,7 +416,7 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { @Override public Map> findPossibleExtension(@NotNull String prefix, final Project project) { loadHugeFilesIfNecessary(); - final boolean perProject = CodeStyleFacade.getInstance(project).projectUsesOwnSettings(); + final boolean perProject = CodeStyle.usesOwnSettings(project); final Map> result = new THashMap<>(); int count = 0; final Set prefixes = getProcessedWordsWithoutStemming(prefix); diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index f01777bd2dfe..726fb88f6663 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1276,6 +1276,9 @@ change.color.command.text=Change color warning.use.rest.api=''{0}'' API is requested. Do you trust ''{1}''? title.use.rest.api=Using REST API +searcheverywhere.allelements.tab.name=All +searcheverywhere.switch.scope.hint=Tab to switch scope + run.anything.command.empty.list.title=Press ENTER to execute input command run.anything.console.process.finished=\nProcess finished with exit code {0}. run.anything.console.title=Run anything command diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index a76ea38f14f6..2c7a39144fce 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -287,7 +287,8 @@ interface="com.intellij.navigation.ChooseByNameContributor"/> - + diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 6fb709997fd7..882117f5396d 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -1097,9 +1097,13 @@ - - - + + + + + + - + diff --git a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java index 4c09cd1e7311..102c15439138 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/module/impl/ModuleManagerImpl.java @@ -14,10 +14,7 @@ import com.intellij.openapi.components.ServiceKt; import com.intellij.openapi.components.impl.stores.ModuleStore; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.*; -import com.intellij.openapi.progress.EmptyProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.*; import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectBundle; @@ -300,6 +297,8 @@ public abstract class ModuleManagerImpl extends ModuleManager implements Disposa catch (IOException e) { reportError(errors, modulePath, e); } + catch (ProcessCanceledException ignore) { + } catch (Exception e) { LOG.error(e); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java index b82e9489046a..47cfbfe2535e 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/MatchOptions.java @@ -68,14 +68,6 @@ public class MatchOptions implements JDOMExternalizable { variableConstraints.put(constraint.getName(), constraint); } - public boolean hasVariableConstraints() { - return !variableConstraints.isEmpty(); - } - - public void clearVariableConstraints() { - variableConstraints.clear(); - } - public void retainVariableConstraints(Collection names) { if (variableConstraints.isEmpty()) { return; @@ -140,6 +132,7 @@ public class MatchOptions implements JDOMExternalizable { } public void fillSearchCriteria(String criteria) { + if (!variableConstraints.isEmpty()) variableConstraints.clear(); StringToConstraintsTransformer.transformCriteria(criteria, this); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java index 1f1e86dd02d2..2c49c33bfcc1 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/StructuralSearchProfile.java @@ -294,12 +294,23 @@ public abstract class StructuralSearchProfile { */ public boolean isApplicableConstraint(String constraintName, @Nullable PsiElement variableNode, boolean completePattern, boolean target) { switch (constraintName) { - case UIUtil.TEXT: case UIUtil.MINIMUM_ZERO: if (target) return false; case UIUtil.MAXIMUM_UNLIMITED: + case UIUtil.TEXT: case UIUtil.REFERENCE: return !completePattern; } return false; } + + public final boolean isApplicableConstraint(String constraintName, List nodes, boolean completePattern, boolean target) { + if (nodes.isEmpty()) { + return isApplicableConstraint(constraintName, (PsiElement)null, completePattern, target); + } + boolean result = true; + for (PsiElement node : nodes) { + result &= isApplicableConstraint(constraintName, node, completePattern, target); + } + return result; + } } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java index 314b543ee438..03e59e361ec1 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/impl/matcher/compiler/PatternCompiler.java @@ -116,11 +116,7 @@ public class PatternCompiler { element.accept(new PsiRecursiveElementWalkingVisitor() { @Override public void visitElement(PsiElement element) { - final Object userData = element.getUserData(CompiledPattern.HANDLER_KEY); - if (userData != null) { - if (userData instanceof SubstitutionHandler) { - pattern.putVariableNode(((SubstitutionHandler)userData).getName(), element); - } + if (element.getUserData(CompiledPattern.HANDLER_KEY) != null) { return; } super.visitElement(element); @@ -137,10 +133,24 @@ public class PatternCompiler { } return; } - MatchingHandler handler = pattern.getHandler(pattern.getTypedVarString(element)); + final MatchingHandler handler = pattern.getHandler(pattern.getTypedVarString(element)); if (handler == null) { throw new MalformedPatternException(); } + } + }); + element.accept(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + collectNode(element, element.getUserData(CompiledPattern.HANDLER_KEY)); + super.visitElement(element); + + if (element instanceof LeafElement) { + collectNode(element, pattern.getHandler(pattern.getTypedVarString(element))); + } + } + + private void collectNode(PsiElement element, Object handler) { if (handler instanceof DelegatingHandler) { handler = ((DelegatingHandler)handler).getDelegate(); } diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java index 26e7ae8c410d..d9efe409d3c1 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/replace/impl/Replacer.java @@ -75,7 +75,6 @@ public class Replacer { replaceOptions.setReplacement(by); final MatchOptions matchOptions = replaceOptions.getMatchOptions(); - matchOptions.clearVariableConstraints(); matchOptions.fillSearchCriteria(what); Matcher.validate(project, matchOptions); diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java index 5c241425e3e0..6e4c1a07ef49 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/EditVarConstraintsDialog.java @@ -336,14 +336,13 @@ class EditVarConstraintsDialog extends DialogWrapper { return; } else { final List nodes = myCompiledPattern.getVariableNodes(varName); - final PsiElement node = nodes.size() == 1 ? nodes.get(0) : null; final boolean completePattern = Configuration.CONTEXT_VAR_NAME.equals(varName); - final boolean text = myProfile.isApplicableConstraint(UIUtil.TEXT, node, completePattern, false); + final boolean text = myProfile.isApplicableConstraint(UIUtil.TEXT, nodes, completePattern, false); textConstraintsPanel.setVisible(text); - applyWithinTypeHierarchy.setVisible(text && myProfile.isApplicableConstraint(UIUtil.TEXT_HIERARCHY, node, completePattern, false)); - final boolean minZero = myProfile.isApplicableConstraint(UIUtil.MINIMUM_ZERO, node, completePattern, false); - final boolean maxUnlimited = myProfile.isApplicableConstraint(UIUtil.MAXIMUM_UNLIMITED, node, completePattern, false); + applyWithinTypeHierarchy.setVisible(text && myProfile.isApplicableConstraint(UIUtil.TEXT_HIERARCHY, nodes, completePattern, false)); + final boolean minZero = myProfile.isApplicableConstraint(UIUtil.MINIMUM_ZERO, nodes, completePattern, false); + final boolean maxUnlimited = myProfile.isApplicableConstraint(UIUtil.MAXIMUM_UNLIMITED, nodes, completePattern, false); if (minZero || maxUnlimited) { occurencePanel.setVisible(true); minoccurs.setMinValue(minZero ? 0 : 1); @@ -356,11 +355,11 @@ class EditVarConstraintsDialog extends DialogWrapper { else { occurencePanel.setVisible(false); } - final boolean typeComponent = myProfile.isApplicableConstraint(UIUtil.TYPE, node, completePattern, false); + final boolean typeComponent = myProfile.isApplicableConstraint(UIUtil.TYPE, nodes, completePattern, false); expressionConstraints.setVisible(typeComponent); - expectedTypeConstraints.setVisible(typeComponent && myProfile.isApplicableConstraint(UIUtil.EXPECTED_TYPE, node, completePattern, - false)); - referenceTargetConstraints.setVisible(myProfile.isApplicableConstraint(UIUtil.REFERENCE, node, completePattern, false)); + expectedTypeConstraints.setVisible(typeComponent && + myProfile.isApplicableConstraint(UIUtil.EXPECTED_TYPE, nodes, completePattern, false)); + referenceTargetConstraints.setVisible(myProfile.isApplicableConstraint(UIUtil.REFERENCE, nodes, completePattern, false)); containedInConstraints.setVisible(completePattern); scriptConstraints.setVisible(Registry.is("ssr.enable.script.constraint.on.all.variables") || completePattern); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java index b184e84f1404..aa5e7643569f 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/OptimizedSearchScanTest.java @@ -30,13 +30,13 @@ public class OptimizedSearchScanTest extends StructuralSearchTestCase { public void testOptionalMethodWithThrowsClause() { final String plan = findWordsToBeUsedWhenSearchingFor( "class C {" + - " void 'm{0,1} () throws OMGWTFBBQException {}" + + " void '_m{0,1} () throws OMGWTFBBQException {}" + "}"); assertEquals("exception should not be in plan", "[in code:class|in code:enum|in code:interface][in code:C]", plan); final String plan2 = findWordsToBeUsedWhenSearchingFor( "class C {" + - " String m() throws 'E{0,1} {" + + " String m() throws '_E{0,1} {" + " System.out.println();" + " return null;" + " }" + diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 3cc37f8ea6a9..0d26272d8768 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -304,7 +304,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "processInheritors(1,2,3,4,5,6);" + "}}"; assertEquals("no smart detection of search target", 3, - findMatchesCount(in, "'instance?.processInheritors('_param1{1,6});")); + findMatchesCount(in, "'_instance?.processInheritors('_param1{1,6});")); String someCode = "class X {{ a *= 2; a+=2; }}"; assertEquals("Improper *= 2 search", 1, findMatchesCount(someCode, "a *= 2;")); @@ -316,7 +316,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " }\n" + "}" + "}}"; - assertEquals("Find inner class parameters", 2, findMatchesCount(s1, "new Thread('args*) { '_Other* }")); + assertEquals("Find inner class parameters", 2, findMatchesCount(s1, "new Thread('args+) { '_Other* }")); String s3 = "class X {{" + "Thread t = new Thread(\"my thread\") {\n" + @@ -420,7 +420,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { findMatchesCount(s9, "new int []{ '_* }")); assertEquals("Find new int array expressions, including array initializer expressions using variable ", 2, - findMatchesCount(s9, "new 'a?:int [] { '_* }")); + findMatchesCount(s9, "new '_a?:int [] { '_* }")); assertEquals("Find all new array expressions, including array initializers", 8, findMatchesCount(s9, "new '_? []{ '_* }")); @@ -474,7 +474,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; assertEquals("match literal contents", 1, findMatchesCount(s2, "\"'String:[regex( alpha )]\"")); assertEquals("negate match literal contents", 2, findMatchesCount(s2, "\"'String:[!regex( alpha )]\"")); - assertEquals("match literal contents and all types", 1, findMatchesCount(s2, "\"'String:[regex( alpha ) && exprtype( .* )]\"")); + assertEquals("match literal contents combined with other constraint", 1, findMatchesCount(s2, "\"'String:[regex( alpha ) && script( true )]\"")); String s3 = "class A {" + " int i = 0x20;" + @@ -636,7 +636,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "try { a(); } catch(Exception ex) {}" + "}}"; assertEquals("catch parameter matching", 3, - findMatchesCount(s10031, "try { a(); } catch('_Type+ 'Arg+) { '_Statements*; }\n")); + findMatchesCount(s10031, "try { a(); } catch('_Type 'Arg+) { '_Statements*; }\n")); String s10033 = "class X {{ " + "return x;\n" + @@ -782,7 +782,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; final String s136 = "class 'm {\n" + " void f();\n" + - " '_type '_method{0,0} ('_paramtype* '_paramname* );\n" + + " '_type '_method{0,0} ('_paramtype '_paramname* );\n" + "}"; assertEquals("reject method with 0 max occurence", 1, findMatchesCount(s135,s136)); @@ -826,7 +826,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "class D { void method() {} }\n" + "class E {}"; assertEquals("parameterless constructor search", 3, - findMatchesCount(s143, "class '_a { '_d{0,0}:[ script( \"__context__.constructor\" ) ]('_b+ '_c+); }")); + findMatchesCount(s143, "class '_a { '_d{0,0}:[ script( \"__context__.constructor\" ) ]('_b '_c+); }")); assertEquals("parameterless constructor search 2", 2, findMatchesCount(s143, "'_Constructor() { '_st*; }")); } @@ -999,7 +999,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " void a(String in, String pattern) {}\n" + " }"; String s1001 = "class '_Class { \n" + - " '_ReturnType+ 'MethodName+ ('_ParameterType* '_Parameter* );\n" + + " '_ReturnType 'MethodName+ ('_ParameterType '_Parameter* );\n" + "}"; assertEquals("handling of no match", 2, findMatchesCount(s1000,s1001)); } @@ -1034,7 +1034,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("parameterized cast match", 1, findMatchesCount(s81, "( '_Type<'_Parameter+> ) '_Expr")); assertEquals("parameterized symbol without variables matching", 2, findMatchesCount(s81, "S")); assertEquals("parameterized definition match", 3, findMatchesCount(s81, "'_Type<'_Parameter+> 'a = '_Init?;")); - assertEquals("parameterized method match", 1, findMatchesCount(s81, "class '_ { <'_+> '_Type 'Method('_* '_*); }")); + assertEquals("parameterized method match", 1, findMatchesCount(s81, "class '_ { <'_+> '_Type 'Method('_ '_*); }")); assertEquals("parameterized constraint match", 2, findMatchesCount(s81_2, "class '_<'_+ extends 'res+> {}")); String s82_7 = "'Type"; @@ -1049,7 +1049,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " public T[] toArray(T[] a) {return c.toArray(a);}\n" + " }\n" + "}"; - assertEquals("typed symbol symbol", 2, findMatchesCount(s81_3, "class '_ { <'_+> '_Type 'Method('_* '_*); }")); + assertEquals("typed symbol symbol", 2, findMatchesCount(s81_3, "class '_ { <'_+> '_Type 'Method('_ '_*); }")); String s81_4="class A { \n" + " static void c(D f) throws R {\n" + @@ -1191,9 +1191,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("find nested class by special pattern", 1, findMatchesCount(s63_2, "class '_ { class 'T { public void '_T2:run () {} } }")); - assertEquals("* regexp for typed var", 5, findMatchesCount(s61, "{ 'T*; }")); assertEquals("+ regexp for typed var", 4, findMatchesCount(s61, "{ 'T+; }")); - assertEquals("? regexp for typed var", 2, findMatchesCount(s61, "{ 'T?; }")); + assertEquals("? regexp for typed var", 2, findMatchesCount(s61, "{ '_T?; }")); assertEquals("cast in method arguments", 1, findMatchesCount(s67, " (VirtualFile)'T")); assertEquals("searching for static field in static call", 2, findMatchesCount(s69, " System.out ")); assertEquals("searching for static field in static call, 2", 2, findMatchesCount(s69, " java.lang.System.out ")); @@ -1267,14 +1266,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " static final long serialVersionUID = 4383685877147921099L;" + "}"; String s134 = "class '_ implements '_:*Serializable {\n" + - " static final long 'VersionField?:serialVersionUID = '_?;\n" + + " static final long 'VersionField:serialVersionUID = '_?;\n" + " private static final ObjectStreamField[] '_?:serialPersistentFields = '_?; \n" + " private void '_SerializationWriteHandler?:writeObject (ObjectOutputStream s) throws IOException;\n" + " private void '_SerializationReadHandler?:readObject (ObjectInputStream s) throws IOException, ClassNotFoundException;\n" + " Object '_SpecialSerializationReadHandler?:readResolve () throws ObjectStreamException;" + " Object '_SpecialSerializationWriteHandler?:writeReplace () throws ObjectStreamException;" + "}"; - assertEquals("serialization match", 2, findMatchesCount(s133,s134)); + assertEquals("serialization match", 2, findMatchesCount(s133, s134)); String s135 = "class SimpleStudentEventActionImpl extends Action { " + " public ActionForward execute(ActionMapping mapping,\n" + @@ -1285,7 +1284,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "} " + "public class DoEnrollStudent extends SimpleStudentEventActionImpl { }" + "public class DoCancelStudent extends SimpleStudentEventActionImpl { }"; - String s136 = "public class 'StrutsActionClass extends '_*:Action {" + + String s136 = "public class 'StrutsActionClass extends '_:*Action {" + " public ActionForward '_AnActionMethod:*execute (ActionMapping '_,\n" + " ActionForm '_,\n" + " HttpServletRequest '_,\n" + @@ -1303,7 +1302,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " private static NodeFilter instance;\n" + "}"; final String s124 = "class 'Class {\n" + - " private 'Class('_* '_*) {\n" + + " private 'Class('_ '_*) {\n" + " '_*;\n" + " }\n" + " private static '_Class2:* '_Instance;\n" + @@ -1524,8 +1523,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String s111 = "class A { void getManager() { getManager(); } };\n" + "class B { void getManager() { getManager(); getManager(); } };"; - assertEquals("caring about missing qualifier type", 2, findMatchesCount(s111, "'Instance?:[exprtype( B )].getManager()")); - assertEquals("static query should not match instance method", 0, findMatchesCount(s111, "'Instance?:[regex( B )].getManager()")); + assertEquals("caring about missing qualifier type", 2, findMatchesCount(s111, "'_Instance?:[exprtype( B )].getManager()")); + assertEquals("static query should not match instance method", 0, findMatchesCount(s111, "'_Instance?:[regex( B )].getManager()")); assertEquals("static query should not match instance method 2", 0, findMatchesCount(s111, "B.getManager()")); String s113 = "class A { static void a() { a(); }}\n" + @@ -1663,14 +1662,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " public String otherField;\n" + "}"; String s4 = "class '_a {\n" + - " @'_Annotation+ ( 'AnnotationMember*:name = '_AnnotationValue* )\n" + + " @'_Annotation+ ( 'AnnotationMember+:name = '_AnnotationValue )\n" + " String '_field* ;\n" + "}"; assertEquals("Find annotation members of annotated field class", 4, findMatchesCount(s3, s4)); String s4_2 = "class '_a {\n" + " @'_Annotation+ ()\n" + - " String 'field* ;\n" + + " String 'field+ ;\n" + "}"; assertEquals("Find annotation fields", 3, findMatchesCount(s3, s4_2)); @@ -1680,9 +1679,9 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; assertEquals("Find annotated methods", 2, - findMatchesCount(s5, "class '_c {@NotNull '_rt 'method* ('_pt* '_p*){ '_inst*; } }")); + findMatchesCount(s5, "class '_c {@NotNull '_rt 'method+ ('_pt '_p*){ '_inst*; } }")); assertEquals("Find annotated methods, 2", 2, - findMatchesCount(s5, "class '_c {@'_:NotNull '_rt 'method* ('_pt* '_p*){ '_inst*; } }")); + findMatchesCount(s5, "class '_c {@'_:NotNull '_rt 'method+ ('_pt '_p*){ '_inst*; } }")); String s7 = "class A { void message(@NonNls String msg); }\n" + "class B { void message2(String msg); }\n" + @@ -1698,11 +1697,11 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " @NonNls Object[] method3() {}\n" + "}"; assertEquals("Find not annotated methods, 2", 2, - findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object\\[\\] 'b+( '_pt* '_p* ); }")); + findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object\\[\\] 'b+( '_pt '_p* ); }")); assertEquals("Find not annotated methods, 2", 2, - findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type [] 'b+( '_pt* '_p* ); }")); + findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type [] 'b+( '_pt '_p* ); }")); assertEquals("Find not annotated methods, 2", 2, - findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object [] 'b+( '_pt* '_p* ); }")); + findMatchesCount(s9, "class '_A { @'_Ann{0,0}:NonNls '_Type:Object [] 'b+( '_pt '_p* ); }")); String s11 = "class A {\n" + " @Foo(value=baz) int a;\n" + @@ -1732,7 +1731,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Match anno parameter name 2", 3, findMatchesCount(s11, "@Foo(value='_value)")); assertEquals("Match value anno parameter only", 2, findMatchesCount(s11, "@Foo(baz2)")); assertEquals("Match value anno parameters", 3, findMatchesCount(s11, "@Foo('_value)")); - assertEquals("Match all annotations", 10, findMatchesCount(s11, "@Foo('_value*)")); + assertEquals("Match all annotations", 10, findMatchesCount(s11, "@Foo('_value?)")); + assertEquals("Match all annotations 2", 10, findMatchesCount(s11, "@Foo")); assertEquals("Match annotations without parameters", 1, findMatchesCount(s11, "@Foo('_name{0,0}='_v)")); String s12 = "@X(value=1, x=2) @Y(1) @Z(x=0, y=0, z=0) @W(2) @V(x=0, y=0, z=0) class One {}"; @@ -1787,7 +1787,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("Find SuppressWarnings annotations", 2, findMatchesCount(source6, "@SuppressWarnings")); assertEquals("Find SuppressWarnings annotations", 2, findMatchesCount(source6, "@SuppressWarnings(value='_any)")); assertEquals("Find annotation with 3 value array initializer", 1, findMatchesCount(source6, "@SuppressWarnings({'_value{3,3} })")); - } public void testBoxingAndUnboxing() { @@ -1973,9 +1972,9 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " static { int b = 1; }" + " { int c = 2; }" + "}"; - assertEquals("Static / instance initializers", 2, findMatchesCount(s1, "static { 't*; }")); - assertEquals("Static / instance initializers", 1, findMatchesCount(s1, "@Modifier(\"Instance\") { 't*; }")); - assertEquals("Static / instance initializers", 3, findMatchesCount(s1, "{ 't*; }")); + assertEquals("Static / instance initializers", 2, findMatchesCount(s1, "static { '_t*; }")); + assertEquals("Static / instance initializers", 1, findMatchesCount(s1, "@Modifier(\"Instance\") { '_t*; }")); + assertEquals("Static / instance initializers", 3, findMatchesCount(s1, "{ '_t*; }")); } @NotNull @@ -1988,7 +1987,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { String s1 = loadFile(getTestName(false) + ".java"); String s2 = "ApplicationManager.getApplication().runReadAction(new Runnable() {\n" + " public void run() {\n" + - " 't*:[ !regex( .*return.* ) ];\n" + + " '_t*:[ !regex( .*return.* ) ];\n" + " }});"; assertEquals(0, findMatchesCount(s1,s2)); } @@ -2036,7 +2035,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { results.clear(); - options.clearVariableConstraints(); options.fillSearchCriteria("try { '_st*; } catch('Type:Type2 '_t) { '_st2*; }"); for(PsiVariable var:vars) { @@ -2183,22 +2181,22 @@ public class StructuralSearchTest extends StructuralSearchTestCase { "}"; String pattern1 = "class '_A {" + - " '_type+ 'method+ () throws '_E{0,0};" + + " '_type 'method+ () throws '_E{0,0};" + "}"; assertEquals(1, findMatchesCount(source, pattern1)); String pattern2 = "class '_A {" + - " '_type+ 'method+ () throws '_E{1,2};" + + " '_type 'method+ () throws '_E{1,2};" + "}"; assertEquals(2, findMatchesCount(source, pattern2)); String pattern3 = "class '_A {" + - " '_type+ 'method+ () throws '_E{2,2};" + + " '_type 'method+ () throws '_E{2,2};" + "}"; assertEquals(1, findMatchesCount(source, pattern3)); String pattern4 = "class '_A {" + - " '_type+ 'method+ () throws '_E{0,0}:[ regex( E2 )];" + + " '_type 'method+ () throws '_E{0,0}:[ regex( E2 )];" + "}"; assertEquals(2, findMatchesCount(source, pattern4)); } @@ -2336,10 +2334,10 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " void m();" + "}"; - String pattern1 = "interface '_Class { default '_ReturnType+ 'MethodName+('_ParameterType* '_Parameter*);}"; + String pattern1 = "interface '_Class { default '_ReturnType 'MethodName+('_ParameterType '_Parameter*);}"; assertEquals("should find default method", 1, findMatchesCount(source, pattern1)); - String pattern2 = "interface 'Class { default '_ReturnType+ '_MethodName{0,0}('_ParameterType* '_Parameter*);}"; + String pattern2 = "interface 'Class { default '_ReturnType '_MethodName{0,0}('_ParameterType '_Parameter*);}"; assertEquals("should find interface without default methods", 1, findMatchesCount(source, pattern2)); } @@ -2389,7 +2387,6 @@ public class StructuralSearchTest extends StructuralSearchTestCase { fail("malformed pattern warning expected"); } catch (MalformedPatternException ignored) {} - findMatchesCount(source, "'_ReturnType '_Method*('_ParameterType '_Parameter);"); } public void testInvalidPatternWarnings() { @@ -2431,6 +2428,14 @@ public class StructuralSearchTest extends StructuralSearchTestCase { } catch (MalformedPatternException ignored) {} } + public void testNotApplicableConstraints() { + options.fillSearchCriteria("class A extends '_B* {}"); + assertEquals("MAXIMUM UNLIMITED not applicable for B", checkApplicableConstraints()); + + options.fillSearchCriteria("'_a?.'_b?"); + assertEquals("MINIMUM ZERO not applicable for b", checkApplicableConstraints()); + } + public void testFindInnerClass() { String source = "class Foo {\n" + " static class Bar {}\n" + @@ -2583,7 +2588,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase { " }" + "}"; assertEquals("find assert statements", 3, findMatchesCount(source, "assert '_a;")); - assertEquals("find assert statements 2", 3, findMatchesCount(source, "assert '_a : 'b*;")); + assertEquals("find assert statements 2", 3, findMatchesCount(source, "assert '_a : '_b?;")); assertEquals("find assert statement with messages", 1, findMatchesCount(source, "assert '_a : '_b;")); assertEquals("find assert statement without messages", 2, findMatchesCount(source, "assert 'a : '_b{0,0};")); } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java index 8864da307c29..c7097f98bc7e 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTestCase.java @@ -7,8 +7,14 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.PsiElement; +import com.intellij.structuralsearch.impl.matcher.CompiledPattern; +import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler; +import com.intellij.structuralsearch.plugin.ui.UIUtil; +import com.intellij.util.SmartList; import java.io.File; import java.io.IOException; @@ -46,15 +52,53 @@ public abstract class StructuralSearchTestCase extends LightQuickFixTestCase { FileType sourceFileType, String sourceExtension, boolean physicalSourceFile) { - options.clearVariableConstraints(); options.fillSearchCriteria(pattern); options.setFileType(patternFileType); options.setDialect(patternLanguage); - Matcher.validate(getProject(), options); + final String message = checkApplicableConstraints(); + assertNull(message, message); return testMatcher.testFindMatches(in, options, true, sourceFileType, sourceExtension, physicalSourceFile); } + public String checkApplicableConstraints() { + final CompiledPattern compiledPattern = PatternCompiler.compilePattern(getProject(), options); + final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(options.getFileType()); + assert profile != null; + for (String varName : options.getVariableConstraintNames()) { + final List nodes = compiledPattern.getVariableNodes(varName); + final MatchVariableConstraint constraint = options.getVariableConstraint(varName); + final List usedConstraints = new SmartList<>(); + if (!StringUtil.isEmpty(constraint.getRegExp())) { + usedConstraints.add(UIUtil.TEXT); + } + if (constraint.isWithinHierarchy()) { + usedConstraints.add(UIUtil.TEXT_HIERARCHY); + } + if (constraint.getMinCount() == 0) { + usedConstraints.add(UIUtil.MINIMUM_ZERO); + } + if (constraint.getMaxCount() > 1) { + usedConstraints.add(UIUtil.MAXIMUM_UNLIMITED); + } + if (!StringUtil.isEmpty(constraint.getNameOfExprType())) { + usedConstraints.add(UIUtil.TYPE); + } + if (!StringUtil.isEmpty(constraint.getNameOfFormalArgType())) { + usedConstraints.add(UIUtil.EXPECTED_TYPE); + } + if (!StringUtil.isEmpty(constraint.getReferenceConstraint())) { + usedConstraints.add(UIUtil.REFERENCE); + } + for (String usedConstraint : usedConstraints) { + if (!profile.isApplicableConstraint(usedConstraint, nodes, false, constraint.isPartOfSearchResults())) { + return usedConstraint + " not applicable for " + varName; + } + } + } + return null; + } + protected List findMatches(String in, String pattern, FileType patternFileType) { return findMatches(in, pattern, patternFileType, null, patternFileType, null, false); } diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java index 412a537aca82..051963ea7430 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/XmlStructuralSearchTest.java @@ -90,7 +90,7 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase { String s3 = " content \n" + " another content \n" + "another zzzcontent "; - String s4 = "<'_tag>'Content*"; + String s4 = "<'_tag>'Content+"; assertEquals("Content match", 6, findMatchesCount(s3, s4, StdFileTypes.HTML)); assertEquals("Content match", 6, findMatchesCount(s3, s4, StdFileTypes.XML)); } @@ -171,7 +171,7 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase { public void testXmlSearch2() { String s1 = "

AAA

ZZZ

"; - String s2 = "

'content?

"; + String s2 = "

'_content?

"; assertEquals(5, findMatchesCount(s1, s2, StdFileTypes.XML)); } diff --git a/platform/util/src/com/intellij/util/ui/JBUI.java b/platform/util/src/com/intellij/util/ui/JBUI.java index 2578af13ba04..261fb74f57ea 100644 --- a/platform/util/src/com/intellij/util/ui/JBUI.java +++ b/platform/util/src/com/intellij/util/ui/JBUI.java @@ -1587,6 +1587,33 @@ public class JBUI { JBColor.namedColor("Focus.inactiveWarningBorderColor", new JBColor(0xffd385, 0x6e5324)); } } + + //todo #UX-1 maybe move to popup + public static class SearchEverywhere { + public static Color dialogBackground() { + return JBColor.namedColor("SearchEverywhere.Dialog.background", 0xf2f2f2); + } + + public static Insets tabInsets() { + return insets(0, 12); + } + + public static Color selectedTabColor() { + return JBColor.namedColor("SearchEverywhere.Tab.selected.background", 0xdedede); + } + + public static Color searchFieldBackground() { + return JBColor.namedColor("SearchEverywhere.SearchField.background", 0xffffff); + } + + public static Color searchFieldBorderColor() { + return JBColor.namedColor("SearchEverywhere.SearchField.Border.color", 0xbdbdbd); + } + + public static Insets searchFieldInsets() { + return insets(0, 12, 0, 10); + } + } }