Merge remote-tracking branch 'origin/master'

This commit is contained in:
graann
2018-05-07 17:15:05 +03:00
43 changed files with 1802 additions and 385 deletions
@@ -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) {
@@ -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());
}
}
@@ -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();
}
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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);
}
@@ -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();
}
}
@@ -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));
}
}
@@ -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);
}
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
@@ -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
@@ -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>
@@ -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);
}
@@ -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;
}
}
@@ -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();
}
@@ -75,7 +75,6 @@ public class Replacer {
replaceOptions.setReplacement(by);
final MatchOptions matchOptions = replaceOptions.getMatchOptions();
matchOptions.clearVariableConstraints();
matchOptions.fillSearchCriteria(what);
Matcher.validate(project, matchOptions);
@@ -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);
@@ -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;" +
" }" +
@@ -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};"));
}
@@ -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);
}
@@ -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);
}
}
}