mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ui: do not show duplicated entries in "Go To Action" completion
This commit is contained in:
@@ -1,22 +1,34 @@
|
||||
// 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.ui.search.BooleanOptionDescription
|
||||
import com.intellij.ide.ui.search.OptionDescription
|
||||
import com.intellij.ide.util.gotoByName.GotoActionModel.ActionWrapper
|
||||
import com.intellij.ide.util.gotoByName.GotoActionModel.MatchMode
|
||||
import com.intellij.ide.util.gotoByName.GotoActionModel.MatchedValue
|
||||
import com.intellij.java.navigation.ChooseByNameTest
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
import groovy.transform.CompileStatic
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
@CompileStatic
|
||||
class GotoActionTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
void "test shorter actions first despite ellipsis"() {
|
||||
def pattern = 'Rebas'
|
||||
def fork = 'Rebase my GitHub fork'
|
||||
def rebase = 'Rebase...'
|
||||
def items = [matchedValue(fork, pattern),
|
||||
matchedValue(rebase, pattern)].sort()
|
||||
def items = [matchedAction(fork, pattern),
|
||||
matchedAction(rebase, pattern)].sort()
|
||||
assert [rebase, fork] == items.collect { it.valueText }
|
||||
}
|
||||
|
||||
@@ -24,8 +36,8 @@ class GotoActionTest extends LightCodeInsightFixtureTestCase {
|
||||
def pattern = 'by'
|
||||
def byName = 'By Name'
|
||||
def byDesc = 'By Desc'
|
||||
def items = [matchedValue(byName, pattern),
|
||||
matchedValue(byDesc, pattern, GotoActionModel.MatchMode.DESCRIPTION)].sort()
|
||||
def items = [matchedAction(byName, pattern),
|
||||
matchedAction(byDesc, pattern, MatchMode.DESCRIPTION)].sort()
|
||||
assert [byName, byDesc] == items.collect { it.valueText }
|
||||
}
|
||||
|
||||
@@ -38,36 +50,123 @@ class GotoActionTest extends LightCodeInsightFixtureTestCase {
|
||||
def eclaire = 'eclaire'
|
||||
def cut = 'Cut'
|
||||
def c = 'c'
|
||||
def items = [matchedValue(boom, pattern), matchedValue(aardvark, pattern), matchedValue(copy, pattern),
|
||||
matchedValue(eclaire, pattern), matchedValue(deaf, pattern), matchedValue(cut, pattern), matchedValue(c, pattern)].sort()
|
||||
def items = [matchedAction(boom, pattern),
|
||||
matchedAction(aardvark, pattern),
|
||||
matchedAction(copy, pattern),
|
||||
matchedAction(eclaire, pattern),
|
||||
matchedAction(deaf, pattern),
|
||||
matchedAction(cut, pattern),
|
||||
matchedAction(c, pattern)].sort()
|
||||
assert [c, copy, cut, aardvark, eclaire, boom, deaf] == items.collect { it.valueText }
|
||||
}
|
||||
|
||||
void "test match action by parent and grandparent group name"() {
|
||||
def extractMethod = ActionManager.instance.getAction("ExtractMethod")
|
||||
assert actionMatches('method', extractMethod) == GotoActionModel.MatchMode.NAME
|
||||
assert actionMatches('extract method', extractMethod) == GotoActionModel.MatchMode.GROUP
|
||||
assert actionMatches('refactor method', extractMethod) == GotoActionModel.MatchMode.GROUP
|
||||
assert actionMatches('method', extractMethod) == MatchMode.NAME
|
||||
assert actionMatches('extract method', extractMethod) == MatchMode.GROUP
|
||||
assert actionMatches('refactor method', extractMethod) == MatchMode.GROUP
|
||||
}
|
||||
|
||||
def actionMatches(String pattern, AnAction action) {
|
||||
void "test matched value comparator"() {
|
||||
def pattern = 'Text'
|
||||
def names = ['Text', 'Text completion', 'Completion Text', 'Add text', 'Retextovize mapping', 'Value', 'A', 'Z']
|
||||
|
||||
def items = new ArrayList<MatchedValue>()
|
||||
names.forEach { String name ->
|
||||
items += matchedAction(name, pattern, MatchMode.NAME, true)
|
||||
items += matchedAction(name, pattern, MatchMode.NAME, false)
|
||||
items += matchedAction(name, pattern, MatchMode.DESCRIPTION, true)
|
||||
items += matchedAction(name, pattern, MatchMode.DESCRIPTION, false)
|
||||
items += matchedOption(name, pattern)
|
||||
items += matchedOption(name, pattern)
|
||||
items += matchedBooleanOption(name, pattern)
|
||||
items += new MatchedValue(name, pattern)
|
||||
}
|
||||
|
||||
PlatformTestUtil.assertComparisonContractNotViolated(items,
|
||||
{ def item1, def item2 -> (item1 <=> item2) },
|
||||
{ def item1, def item2 -> item1 == item2 })
|
||||
|
||||
// order can be different on EDT and pooled threads
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
PlatformTestUtil.assertComparisonContractNotViolated(items,
|
||||
{ def item1, def item2 -> (item1 <=> item2) },
|
||||
{ def item1, def item2 -> item1 == item2 })
|
||||
}.get(20000, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
void "test same action is not reported twice"() {
|
||||
def patterns = ["Patch", "Add", "Delete", "Show", "Toggle"]
|
||||
|
||||
def model = new GotoActionModel(project, null, null)
|
||||
def provider = new GotoActionItemProvider(model);
|
||||
|
||||
def popup = ChooseByNamePopup.createPopup(project, model, provider)
|
||||
try {
|
||||
patterns.forEach { String pattern ->
|
||||
def result = ChooseByNameTest.calcPopupElements(popup, pattern, true)
|
||||
def actions = result.findResults {
|
||||
if (it instanceof MatchedValue) {
|
||||
def value = it.value
|
||||
if (value instanceof ActionWrapper) {
|
||||
return (value as ActionWrapper).action;
|
||||
}
|
||||
if (value instanceof OptionDescription) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
assert actions.size() == actions.toSet().size()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
popup.close(false)
|
||||
}
|
||||
}
|
||||
|
||||
private def actionMatches(String pattern, AnAction action) {
|
||||
return new GotoActionModel(project, null, null).actionMatches(pattern, GotoActionItemProvider.buildMatcher(pattern), action)
|
||||
}
|
||||
|
||||
def matchedValue(String fork, String pattern) {
|
||||
matchedValue(fork, pattern, GotoActionModel.MatchMode.NAME)
|
||||
|
||||
private MatchedValue matchedAction(String text, String pattern, MatchMode mode = MatchMode.NAME, boolean isAvailable = true) {
|
||||
return matchedAction(createAction(text), pattern, mode, isAvailable)
|
||||
}
|
||||
|
||||
def matchedValue(String fork, String pattern, GotoActionModel.MatchMode mode) {
|
||||
new GotoActionModel.MatchedValue(createAction(fork, mode), pattern)
|
||||
private MatchedValue matchedAction(AnAction action, String pattern, MatchMode mode = MatchMode.NAME, boolean isAvailable = true) {
|
||||
def model = new GotoActionModel(project, null, null)
|
||||
def wrapper = new ActionWrapper(action, "", mode, DataContext.EMPTY_CONTEXT, model) {
|
||||
@Override
|
||||
boolean isAvailable() {
|
||||
return isAvailable
|
||||
}
|
||||
}
|
||||
new MatchedValue(wrapper, pattern)
|
||||
}
|
||||
|
||||
def createAction(String text, GotoActionModel.MatchMode mode) {
|
||||
def action = new AnAction(text) {
|
||||
private static AnAction createAction(String text) {
|
||||
new AnAction(text) {
|
||||
@Override
|
||||
void actionPerformed(AnActionEvent e) {
|
||||
}
|
||||
}
|
||||
new GotoActionModel.ActionWrapper(action, "", mode, DataContext.EMPTY_CONTEXT, new GotoActionModel(project, null, null))
|
||||
}
|
||||
|
||||
private static MatchedValue matchedOption(String text, String pattern) {
|
||||
return new MatchedValue(new OptionDescription(text), pattern)
|
||||
}
|
||||
|
||||
private static MatchedValue matchedBooleanOption(String text, String pattern) {
|
||||
def option = new BooleanOptionDescription(text, text) {
|
||||
@Override
|
||||
boolean isOptionEnabled() {
|
||||
return false
|
||||
}
|
||||
|
||||
@Override
|
||||
void setOptionState(boolean enabled) {
|
||||
}
|
||||
}
|
||||
return new MatchedValue(option, pattern)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,6 +242,20 @@ public class GotoActionModel implements ChooseByNameModel, Comparator<Object>, D
|
||||
|
||||
return o.hashCode() - hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MatchedValue value1 = (MatchedValue)o;
|
||||
return Objects.equals(value, value1.value) &&
|
||||
Objects.equals(pattern, value1.pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ public abstract class ToolbarUpdater implements Activatable {
|
||||
final Runnable updateRunnable = new MyUpdateRunnable(this, transparentOnly, forced);
|
||||
final Application app = ApplicationManager.getApplication();
|
||||
|
||||
if (now || app.isUnitTestMode()) {
|
||||
if (now || (app.isUnitTestMode() && app.isDispatchThread())) {
|
||||
updateRunnable.run();
|
||||
}
|
||||
else {
|
||||
|
||||
Reference in New Issue
Block a user