mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+91
-59
@@ -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) {
|
||||
|
||||
+1
-2
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<SearchEverywhereContributor> EP_NAME = ExtensionPointName.create("com.intellij.searchEverywhereContributor");
|
||||
@NotNull
|
||||
String getSearchProviderId();
|
||||
|
||||
@NotNull
|
||||
String getGroupName();
|
||||
|
||||
int getSortWeight();
|
||||
|
||||
static List<SearchEverywhereContributor> getProvidersSorted() {
|
||||
return Arrays.stream(EP_NAME.getExtensions())
|
||||
.sorted(Comparator.comparingInt(SearchEverywhereContributor::getSortWeight))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+82
@@ -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<SearchEverywhereContributor> 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<Object> 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<SearchEverywhereContributor> getProvidersSorted() {
|
||||
return Arrays.stream(EP_NAME.getExtensions())
|
||||
.sorted(Comparator.comparingInt(SearchEverywhereContributor::getSortWeight))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
class ContributorSearchResult {
|
||||
private final List<Object> items;
|
||||
private final boolean hasMoreItems;
|
||||
|
||||
public ContributorSearchResult(List<Object> items, boolean hasMoreItems) {
|
||||
this.items = items;
|
||||
this.hasMoreItems = hasMoreItems;
|
||||
}
|
||||
|
||||
public List<Object> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public boolean hasMoreItems() {
|
||||
return hasMoreItems;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return items.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<Object> {
|
||||
public static class SearchResult extends ArrayList<Object> {
|
||||
boolean needMore;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static class SearchListModel extends DefaultListModel<Object> {
|
||||
public static class SearchListModel extends DefaultListModel<Object> {
|
||||
@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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -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<Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+90
@@ -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<Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -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);
|
||||
|
||||
}
|
||||
+117
@@ -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<SearchEverywhereContributor> 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();
|
||||
}
|
||||
}
|
||||
+826
@@ -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<SearchEverywhereContributor> allContributors;
|
||||
private final Project myProject;
|
||||
|
||||
private boolean myShown;
|
||||
|
||||
private SETab mySelectedTab;
|
||||
private final JTextField mySearchField;
|
||||
private final JCheckBox myNonProjectCB;
|
||||
private final List<SETab> myTabs = new ArrayList<>();
|
||||
|
||||
private JBPopup myResultsPopup;
|
||||
private final JBList<Object> myResultsList = new JBList<>();
|
||||
|
||||
private final Map<ResultsRange, SearchEverywhereContributor> 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<SearchEverywhereContributor> 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<SearchEverywhereContributor> 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<SearchEverywhereContributor> 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<ResultsRange, SearchEverywhereContributor> 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<ResultsRange, SearchEverywhereContributor> 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<Integer> 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<Integer> getElementsRange() {
|
||||
return elementsRange;
|
||||
}
|
||||
|
||||
public Optional<Integer> 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<Object> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
+108
@@ -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<Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-27
@@ -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;
|
||||
}
|
||||
}
|
||||
-27
@@ -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;
|
||||
}
|
||||
}
|
||||
-27
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+43
-39
@@ -51,14 +51,11 @@ public class CodeStyleManagerImpl extends CodeStyleManager implements Formatting
|
||||
|
||||
private final ThreadLocal<FormattingMode> 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<TextRange> enabledRanges = myTagHandler.getEnabledRanges(file.getNode(), range);
|
||||
private static void postProcessEnabledRanges(@NotNull final PsiFile file, @NotNull TextRange range, CodeStyleSettings settings) {
|
||||
List<TextRange> enabledRanges = new FormatterTagHandler(getSettings(file)).getEnabledRanges(file.getNode(), range);
|
||||
int delta = 0;
|
||||
for (TextRange enabledRange : enabledRanges) {
|
||||
enabledRange = enabledRange.shiftRight(delta);
|
||||
|
||||
@@ -106,7 +106,5 @@ public abstract class CodeStyleFacade {
|
||||
*/
|
||||
public abstract String getLineSeparator();
|
||||
|
||||
public abstract boolean projectUsesOwnSettings();
|
||||
|
||||
public abstract boolean isUnsuitableCodeStyleConfigurable(Configurable c);
|
||||
}
|
||||
@@ -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
|
||||
Popup.Toolbar.Border.color=4a4e52
|
||||
|
||||
SearchEverywhere.Dialog.background=45494a
|
||||
SearchEverywhere.Tab.selected.background=555a5e
|
||||
SearchEverywhere.SearchField.background=3c3f41
|
||||
SearchEverywhere.SearchField.Border.color=646464
|
||||
@@ -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
|
||||
Popup.Toolbar.Border.color=f7f7f7
|
||||
|
||||
SearchEverywhere.Dialog.background=f2f2f2
|
||||
SearchEverywhere.Tab.selected.background=dedede
|
||||
SearchEverywhere.SearchField.background=ffffff
|
||||
SearchEverywhere.SearchField.Border.color=bdbdbd
|
||||
@@ -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
|
||||
Popup.Toolbar.Border.color=f7f7f7
|
||||
|
||||
SearchEverywhere.Dialog.background=f2f2f2
|
||||
SearchEverywhere.Tab.selected.background=dedede
|
||||
SearchEverywhere.SearchField.background=ffffff
|
||||
SearchEverywhere.SearchField.Border.color=bdbdbd
|
||||
+2
-1
@@ -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<String, Set<String>> findPossibleExtension(@NotNull String prefix, final Project project) {
|
||||
loadHugeFilesIfNecessary();
|
||||
final boolean perProject = CodeStyleFacade.getInstance(project).projectUsesOwnSettings();
|
||||
final boolean perProject = CodeStyle.usesOwnSettings(project);
|
||||
final Map<String, Set<String>> result = new THashMap<>();
|
||||
int count = 0;
|
||||
final Set<String> prefixes = getProcessedWordsWithoutStemming(prefix);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -287,7 +287,8 @@
|
||||
interface="com.intellij.navigation.ChooseByNameContributor"/>
|
||||
<extensionPoint name="anonymousElementProvider"
|
||||
interface="com.intellij.navigation.AnonymousElementProvider"/>
|
||||
<extensionPoint name="searchEverywhereContributor" interface="com.intellij.ide.actions.SearchEverywhereContributor"/>
|
||||
<extensionPoint name="searchEverywhereContributor"
|
||||
interface="com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor"/>
|
||||
|
||||
<extensionPoint name="gotoRelatedProvider" interface="com.intellij.navigation.GotoRelatedProvider"/>
|
||||
|
||||
|
||||
@@ -1097,9 +1097,13 @@
|
||||
<refactoring.moveHandler implementation="com.intellij.refactoring.move.moveFilesOrDirectories.MoveRelatedFilesHandler"
|
||||
order="before moveFileOrDir"/>
|
||||
|
||||
<searchEverywhereContributor implementation="com.intellij.ide.util.gotoByName.ClassSearchEverywhereContributor" />
|
||||
<searchEverywhereContributor implementation="com.intellij.ide.util.gotoByName.FileSearchEverywhereContributor" />
|
||||
<searchEverywhereContributor implementation="com.intellij.ide.util.gotoByName.SymbolSearchEverywhereContributor" />
|
||||
<!-- Search everywhere services/objects -->
|
||||
<projectService serviceInterface="com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager"
|
||||
serviceImplementation="com.intellij.ide.actions.searcheverywhere.SearchEverywhereManagerImpl"/>
|
||||
|
||||
<searchEverywhereContributor implementation="com.intellij.ide.actions.searcheverywhere.ClassSearchEverywhereContributor" />
|
||||
<searchEverywhereContributor implementation="com.intellij.ide.actions.searcheverywhere.FileSearchEverywhereContributor" />
|
||||
<searchEverywhereContributor implementation="com.intellij.ide.actions.searcheverywhere.SymbolSearchEverywhereContributor" />
|
||||
|
||||
<!-- Project tasks execution (delegation of the build/run actions) -->
|
||||
<projectService serviceInterface="com.intellij.task.ProjectTaskManager"
|
||||
|
||||
@@ -212,8 +212,8 @@
|
||||
<action id="GotoClass" class="com.intellij.ide.actions.GotoClassAction"/>
|
||||
<action id="GotoFile" class="com.intellij.ide.actions.GotoFileAction"/>
|
||||
<action id="GotoSymbol" class="com.intellij.ide.actions.GotoSymbolAction"/>
|
||||
<action id="GotoCustomRegion" class="com.intellij.lang.customFolding.GotoCustomRegionAction"/>
|
||||
|
||||
<action id="GotoCustomRegion" class="com.intellij.lang.customFolding.GotoCustomRegionAction"/>
|
||||
<add-to-group group-id="GoToMenu" anchor="first"/>
|
||||
</group>
|
||||
|
||||
|
||||
+3
-4
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<String> 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);
|
||||
}
|
||||
|
||||
|
||||
+12
-1
@@ -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<PsiElement> 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;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-6
@@ -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();
|
||||
}
|
||||
|
||||
-1
@@ -75,7 +75,6 @@ public class Replacer {
|
||||
replaceOptions.setReplacement(by);
|
||||
|
||||
final MatchOptions matchOptions = replaceOptions.getMatchOptions();
|
||||
matchOptions.clearVariableConstraints();
|
||||
matchOptions.fillSearchCriteria(what);
|
||||
|
||||
Matcher.validate(project, matchOptions);
|
||||
|
||||
+8
-9
@@ -336,14 +336,13 @@ class EditVarConstraintsDialog extends DialogWrapper {
|
||||
return;
|
||||
} else {
|
||||
final List<PsiElement> 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);
|
||||
|
||||
|
||||
+2
-2
@@ -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;" +
|
||||
" }" +
|
||||
|
||||
+45
-40
@@ -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<T>"));
|
||||
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> 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<B> { \n" +
|
||||
" static <C> void c(D<E> f) throws R<S> {\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};"));
|
||||
}
|
||||
|
||||
+46
-2
@@ -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<PsiElement> nodes = compiledPattern.getVariableNodes(varName);
|
||||
final MatchVariableConstraint constraint = options.getVariableConstraint(varName);
|
||||
final List<String> 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<MatchResult> findMatches(String in, String pattern, FileType patternFileType) {
|
||||
return findMatches(in, pattern, patternFileType, null, patternFileType, null, false);
|
||||
}
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ public class XmlStructuralSearchTest extends StructuralSearchTestCase {
|
||||
String s3 = "<a> content </a>\n" +
|
||||
"<b> another content </b>\n" +
|
||||
"<c>another <aaa>zzz</aaa>content </c>";
|
||||
String s4 = "<'_tag>'Content*</'_tag>";
|
||||
String s4 = "<'_tag>'Content+</'_tag>";
|
||||
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 = "<body><p class=\"11\"> AAA </p><p class=\"22\"></p> <p> ZZZ </p> <p/> <p/> <p/> </body>";
|
||||
String s2 = "<p '_a{0,0}=\"'_t:[ regex( 11 ) ]\"> 'content? </p>";
|
||||
String s2 = "<p '_a{0,0}=\"'_t:[ regex( 11 ) ]\"> '_content? </p>";
|
||||
|
||||
assertEquals(5, findMatchesCount(s1, s2, StdFileTypes.XML));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user