mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
layout-fixing matcher for got-to-action; less garbage
This commit is contained in:
@@ -85,7 +85,10 @@ 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.*;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Iconable;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -1962,10 +1965,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
|
||||
private GotoActionItemProvider createActionProvider() {
|
||||
GotoActionModel model = new GotoActionModel(project, myFocusComponent, myEditor, myFile) {
|
||||
@Override
|
||||
protected MatchMode actionMatches(@NotNull String pattern, @NotNull AnAction anAction) {
|
||||
String text = anAction.getTemplatePresentation().getText();
|
||||
return text != null && NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE)
|
||||
.matches(text) ? MatchMode.NAME : MatchMode.NONE;
|
||||
protected MatchMode actionMatches(@NotNull String pattern, MinusculeMatcher matcher, @NotNull AnAction anAction) {
|
||||
MatchMode mode = super.actionMatches(pattern, matcher, anAction);
|
||||
return mode == MatchMode.NAME ? mode : MatchMode.NONE;
|
||||
}
|
||||
};
|
||||
return new GotoActionItemProvider(model);
|
||||
|
||||
+47
-54
@@ -28,11 +28,14 @@ import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.codeStyle.MinusculeMatcher;
|
||||
import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.util.CollectConsumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -65,7 +68,7 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider {
|
||||
boolean everywhere,
|
||||
@NotNull ProgressIndicator cancelled,
|
||||
@NotNull final Processor<Object> consumer) {
|
||||
return filterElements(pattern, everywhere, value -> consumer.process(value));
|
||||
return filterElements(pattern, everywhere, consumer::process);
|
||||
}
|
||||
|
||||
public boolean filterElements(String pattern, boolean everywhere, Processor<MatchedValue> consumer) {
|
||||
@@ -81,20 +84,20 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider {
|
||||
}
|
||||
|
||||
private boolean processAbbreviations(final String pattern, Processor<MatchedValue> consumer, DataContext context) {
|
||||
List<String> actions = AbbreviationManager.getInstance().findActions(pattern);
|
||||
if (actions.isEmpty()) return true;
|
||||
List<ActionWrapper> wrappers = ContainerUtil.newArrayListWithCapacity(actions.size());
|
||||
for (String actionId : actions) {
|
||||
AnAction action = myActionManager.getAction(actionId);
|
||||
wrappers.add(new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context));
|
||||
}
|
||||
return ContainerUtil.process(ContainerUtil.map(wrappers, (Function<ActionWrapper, MatchedValue>)w -> new MatchedValue(w, pattern) {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getValueText() {
|
||||
return pattern;
|
||||
}
|
||||
}), consumer);
|
||||
List<String> actionIds = AbbreviationManager.getInstance().findActions(pattern);
|
||||
JBIterable<MatchedValue> wrappers = JBIterable.from(actionIds)
|
||||
.transform(actionId -> {
|
||||
AnAction action = myActionManager.getAction(actionId);
|
||||
ActionWrapper wrapper = new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context);
|
||||
return new MatchedValue(wrapper, pattern) {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getValueText() {
|
||||
return pattern;
|
||||
}
|
||||
};
|
||||
});
|
||||
return processItems(pattern, wrappers, consumer);
|
||||
}
|
||||
|
||||
private static boolean processTopHits(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
|
||||
@@ -109,14 +112,8 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider {
|
||||
}
|
||||
provider.consumeTopHits(pattern, collector, project);
|
||||
}
|
||||
final Collection<Object> result = collector.getResult();
|
||||
final List<Comparable> c = new ArrayList<Comparable>();
|
||||
for (Object o : result) {
|
||||
if (o instanceof Comparable) {
|
||||
c.add((Comparable)o);
|
||||
}
|
||||
}
|
||||
return processItems(pattern, c, consumer);
|
||||
Collection<Object> result = collector.getResult();
|
||||
return processItems(pattern, JBIterable.from(result).filter(Comparable.class), consumer);
|
||||
}
|
||||
|
||||
private boolean processOptions(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
|
||||
@@ -163,49 +160,45 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
return processItems(pattern, options, consumer);
|
||||
return processItems(pattern, JBIterable.from(options), consumer);
|
||||
}
|
||||
|
||||
private boolean processActions(String pattern, boolean everywhere, Processor<MatchedValue> consumer, DataContext dataContext) {
|
||||
List<AnAction> actions = ContainerUtil.newArrayList();
|
||||
JBIterable<AnAction> actions;
|
||||
if (everywhere) {
|
||||
for (String id : ((ActionManagerImpl)myActionManager).getActionIds()) {
|
||||
ProgressManager.checkCanceled();
|
||||
ContainerUtil.addIfNotNull(actions, myActionManager.getAction(id));
|
||||
}
|
||||
} else {
|
||||
actions.addAll(myModel.myActionGroups.keySet());
|
||||
Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
|
||||
actions = JBIterable.from(ids).transform(myActionManager::getAction).filter(Condition.NOT_NULL);
|
||||
}
|
||||
|
||||
List<ActionWrapper> actionWrappers = ContainerUtil.newArrayList();
|
||||
for (AnAction action : actions) {
|
||||
ProgressManager.checkCanceled();
|
||||
MatchMode mode = myModel.actionMatches(pattern, action);
|
||||
if (mode != MatchMode.NONE) {
|
||||
actionWrappers.add(new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext));
|
||||
}
|
||||
else {
|
||||
actions = JBIterable.from(myModel.myActionGroups.keySet());
|
||||
}
|
||||
MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE);
|
||||
JBIterable<ActionWrapper> actionWrappers = actions.transform(action -> {
|
||||
MatchMode mode = myModel.actionMatches(pattern, matcher, action);
|
||||
if (mode == MatchMode.NONE) return null;
|
||||
return new ActionWrapper(action, myModel.myActionGroups.get(action), mode, dataContext);
|
||||
}).filter(Condition.NOT_NULL);
|
||||
return processItems(pattern, actionWrappers, consumer);
|
||||
}
|
||||
|
||||
private boolean processIntentions(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
|
||||
List<ActionWrapper> intentions = ContainerUtil.newArrayList();
|
||||
for (String intentionText : myModel.myIntentions.keySet()) {
|
||||
final ApplyIntentionAction intentionAction = myModel.myIntentions.get(intentionText);
|
||||
if (myModel.actionMatches(pattern, intentionAction) != MatchMode.NONE) {
|
||||
intentions.add(new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext));
|
||||
}
|
||||
}
|
||||
MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE);
|
||||
JBIterable<ActionWrapper> intentions = JBIterable.from(myModel.myIntentions.keySet())
|
||||
.transform(intentionText -> {
|
||||
ApplyIntentionAction intentionAction = myModel.myIntentions.get(intentionText);
|
||||
if (myModel.actionMatches(pattern, matcher, intentionAction) == MatchMode.NONE) return null;
|
||||
return new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext);
|
||||
})
|
||||
.filter(Condition.NOT_NULL);
|
||||
return processItems(pattern, intentions, consumer);
|
||||
}
|
||||
|
||||
private static boolean processItems(final String pattern, Collection<? extends Comparable> items, Processor<MatchedValue> consumer) {
|
||||
List<MatchedValue> matched = ContainerUtil.map(items, new Function<Comparable, MatchedValue>() {
|
||||
@Override
|
||||
public MatchedValue fun(Comparable comparable) {
|
||||
return new MatchedValue(comparable, pattern);
|
||||
}
|
||||
});
|
||||
private static boolean processItems(String pattern, JBIterable<? extends Comparable> items, Processor<MatchedValue> consumer) {
|
||||
ArrayList<MatchedValue> matched = ContainerUtil.newArrayList();
|
||||
items.transform(o -> {
|
||||
ProgressManager.checkCanceled();
|
||||
return o instanceof MatchedValue ? (MatchedValue)o : new MatchedValue(o, pattern);
|
||||
}).addAllTo(matched);
|
||||
Collections.sort(matched);
|
||||
return ContainerUtil.process(matched, consumer);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.MinusculeMatcher;
|
||||
import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.OnOffButton;
|
||||
@@ -49,7 +51,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.ContainerUtilRt;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.apache.oro.text.regex.*;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -60,13 +61,14 @@ import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.intellij.ui.SimpleTextAttributes.STYLE_PLAIN;
|
||||
import static com.intellij.ui.SimpleTextAttributes.STYLE_SEARCH_MATCH;
|
||||
|
||||
@SuppressWarnings("TestOnlyProblems")
|
||||
public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, Comparator<Object>, EdtSortingModel, DumbAware {
|
||||
@NotNull private static java.util.regex.Pattern INNER_GROUP_WITH_IDS = java.util.regex.Pattern.compile("(.*) \\(\\d+\\)");
|
||||
private static final Pattern INNER_GROUP_WITH_IDS = Pattern.compile("(.*) \\(\\d+\\)");
|
||||
|
||||
@Nullable private final Project myProject;
|
||||
private final Component myContextComponent;
|
||||
@@ -75,8 +77,6 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
|
||||
|
||||
private static final Icon EMPTY_ICON = EmptyIcon.ICON_18;
|
||||
|
||||
private Pattern myCompiledPattern;
|
||||
|
||||
protected final SearchableOptionsRegistrar myIndex;
|
||||
protected final Map<AnAction, String> myActionGroups = ContainerUtil.newHashMap();
|
||||
|
||||
@@ -235,7 +235,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
|
||||
|
||||
@Override
|
||||
public ListCellRenderer getListCellRenderer() {
|
||||
return new GotoActionListCellRenderer(description -> getGroupName(description));
|
||||
return new GotoActionListCellRenderer(this::getGroupName);
|
||||
}
|
||||
|
||||
protected String getActionId(@NotNull AnAction anAction) {
|
||||
@@ -402,36 +402,28 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
|
||||
public boolean matches(@NotNull String name, @NotNull String pattern) {
|
||||
AnAction anAction = myActionManager.getAction(name);
|
||||
if (anAction == null) return true;
|
||||
return actionMatches(pattern, anAction) != MatchMode.NONE;
|
||||
MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE);
|
||||
return actionMatches(pattern, matcher, anAction) != MatchMode.NONE;
|
||||
}
|
||||
|
||||
protected MatchMode actionMatches(@NotNull String pattern, @NotNull AnAction anAction) {
|
||||
Pattern compiledPattern = getPattern(pattern);
|
||||
protected MatchMode actionMatches(@NotNull String pattern, MinusculeMatcher matcher, @NotNull AnAction anAction) {
|
||||
Presentation presentation = anAction.getTemplatePresentation();
|
||||
String text = presentation.getText();
|
||||
String description = presentation.getDescription();
|
||||
String groupName = myActionGroups.get(anAction);
|
||||
PatternMatcher matcher = getMatcher();
|
||||
if (text != null && matcher.matches(text, compiledPattern)) {
|
||||
if (text != null && matcher.matches(text)) {
|
||||
return MatchMode.NAME;
|
||||
}
|
||||
else if (description != null && !description.equals(text) && matcher.matches(description, compiledPattern)) {
|
||||
else if (description != null && !description.equals(text) && matcher.matches(description)) {
|
||||
return MatchMode.DESCRIPTION;
|
||||
}
|
||||
if (text == null) {
|
||||
return MatchMode.NONE;
|
||||
}
|
||||
if (groupName == null) {
|
||||
return matches(pattern, compiledPattern, matcher, text) ? MatchMode.NON_MENU : MatchMode.NONE;
|
||||
}
|
||||
if (matches(pattern, compiledPattern, matcher, groupName + " " + text)) {
|
||||
if (matcher.matches(groupName + " " + text)) {
|
||||
return anAction instanceof ToggleAction ? MatchMode.NAME : MatchMode.GROUP;
|
||||
}
|
||||
return matches(pattern, compiledPattern, matcher, text + " " + groupName) ? MatchMode.GROUP : MatchMode.NONE;
|
||||
}
|
||||
|
||||
private static boolean matches(@NotNull String pattern, Pattern compiledPattern, @NotNull PatternMatcher matcher, @NotNull String str) {
|
||||
return StringUtil.containsIgnoreCase(str, pattern) || matcher.matches(str, compiledPattern);
|
||||
return matcher.matches(text + " " + groupName) ? MatchMode.GROUP : MatchMode.NONE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -443,25 +435,6 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
|
||||
return myContextComponent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Pattern getPattern(@NotNull String pattern) {
|
||||
String converted = convertPattern(pattern.trim());
|
||||
Pattern compiledPattern = myCompiledPattern;
|
||||
if (compiledPattern != null && !Comparing.strEqual(converted, compiledPattern.getPattern())) {
|
||||
compiledPattern = null;
|
||||
}
|
||||
if (compiledPattern == null) {
|
||||
try {
|
||||
myCompiledPattern = compiledPattern = new Perl5Compiler().compile(converted, Perl5Compiler.READ_ONLY_MASK);
|
||||
}
|
||||
catch (MalformedPatternException e) {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
|
||||
return compiledPattern;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SortedSet<Object> sort(@NotNull Set<Object> elements) {
|
||||
@@ -474,93 +447,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
|
||||
NONE, INTENTION, NAME, DESCRIPTION, GROUP, NON_MENU
|
||||
}
|
||||
|
||||
static String convertPattern(@NotNull String pattern) {
|
||||
int eol = pattern.indexOf('\n');
|
||||
if (eol != -1) {
|
||||
pattern = pattern.substring(0, eol);
|
||||
}
|
||||
if (pattern.length() >= 80) {
|
||||
pattern = pattern.substring(0, 80);
|
||||
}
|
||||
|
||||
@NonNls StringBuilder buffer = new StringBuilder();
|
||||
|
||||
boolean allowToLower = true;
|
||||
if (containsOnlyUppercaseLetters(pattern)) {
|
||||
allowToLower = false;
|
||||
}
|
||||
|
||||
if (allowToLower) {
|
||||
buffer.append(".*");
|
||||
}
|
||||
|
||||
boolean firstIdentifierLetter = true;
|
||||
for (int i = 0; i < pattern.length(); i++) {
|
||||
char c = pattern.charAt(i);
|
||||
if (Character.isLetterOrDigit(c)) {
|
||||
// This logic allows to use uppercase letters only to catch the name like PDM for PsiDocumentManager
|
||||
if (Character.isUpperCase(c) || Character.isDigit(c)) {
|
||||
|
||||
if (!firstIdentifierLetter) {
|
||||
buffer.append("[^A-Z]*");
|
||||
}
|
||||
|
||||
buffer.append("[");
|
||||
buffer.append(c);
|
||||
if (allowToLower || i == 0) {
|
||||
buffer.append('|');
|
||||
buffer.append(Character.toLowerCase(c));
|
||||
}
|
||||
buffer.append("]");
|
||||
}
|
||||
else if (Character.isLowerCase(c)) {
|
||||
buffer.append('[');
|
||||
buffer.append(c);
|
||||
buffer.append('|');
|
||||
buffer.append(Character.toUpperCase(c));
|
||||
buffer.append(']');
|
||||
}
|
||||
else {
|
||||
buffer.append(c);
|
||||
}
|
||||
|
||||
firstIdentifierLetter = false;
|
||||
}
|
||||
else if (c == '*') {
|
||||
buffer.append(".*");
|
||||
firstIdentifierLetter = true;
|
||||
}
|
||||
else if (c == '.') {
|
||||
buffer.append("\\.");
|
||||
firstIdentifierLetter = true;
|
||||
}
|
||||
else if (c == ' ') {
|
||||
buffer.append(".*\\ ");
|
||||
firstIdentifierLetter = true;
|
||||
}
|
||||
else {
|
||||
firstIdentifierLetter = true;
|
||||
// for standard RegExp engine
|
||||
// buffer.append("\\u");
|
||||
// buffer.append(Integer.toHexString(c + 0x20000).substring(1));
|
||||
|
||||
// for OROMATCHER RegExp engine
|
||||
buffer.append("\\x");
|
||||
buffer.append(Integer.toHexString(c + 0x20000).substring(3));
|
||||
}
|
||||
}
|
||||
|
||||
buffer.append(".*");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private static boolean containsOnlyUppercaseLetters(@NotNull String s) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c != '*' && c != ' ' && !Character.isUpperCase(c)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willOpenEditor() {
|
||||
@@ -572,17 +459,6 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
|
||||
return true;
|
||||
}
|
||||
|
||||
private final ThreadLocal<PatternMatcher> myMatcher = new ThreadLocal<PatternMatcher>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PatternMatcher initialValue() {
|
||||
return new Perl5Matcher();
|
||||
}
|
||||
};
|
||||
PatternMatcher getMatcher() {
|
||||
return myMatcher.get();
|
||||
}
|
||||
|
||||
public static class ActionWrapper implements Comparable<ActionWrapper> {
|
||||
@NotNull private final AnAction myAction;
|
||||
@NotNull private final MatchMode myMode;
|
||||
|
||||
Reference in New Issue
Block a user