diff --git a/platform/platform-api/src/com/intellij/ui/SearchTextField.java b/platform/platform-api/src/com/intellij/ui/SearchTextField.java index ec19717b4319..770d3e20b149 100644 --- a/platform/platform-api/src/com/intellij/ui/SearchTextField.java +++ b/platform/platform-api/src/com/intellij/ui/SearchTextField.java @@ -255,7 +255,7 @@ public class SearchTextField extends JPanel { } } - private boolean toClearTextOnEscape() { + protected boolean toClearTextOnEscape() { return ApplicationManager.getApplication() != null; } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNew.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNew.java index eecba1bc539c..0937da9cdada 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNew.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNew.java @@ -8,10 +8,7 @@ import com.intellij.ide.IdeBundle; import com.intellij.ide.plugins.newui.*; import com.intellij.ide.util.PropertiesComponent; import com.intellij.idea.IdeaApplication; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.application.ModalityState; @@ -143,6 +140,9 @@ public class PluginManagerConfigurableNew if (keyCode == KeyEvent.VK_ENTER || event.getKeyChar() == '\n') { if (id == KeyEvent.KEY_PRESSED && (myCurrentSearchPanel.controller == null || !myCurrentSearchPanel.controller.handleEnter(event))) { + if (myCurrentSearchPanel.controller != null) { + myCurrentSearchPanel.controller.hidePopup(); + } showSearchPanel(mySearchTextField.getText()); } return true; @@ -154,6 +154,31 @@ public class PluginManagerConfigurableNew return super.preprocessEventForTextField(event); } + @Override + protected boolean toClearTextOnEscape() { + new AnAction() { + { + setEnabledInModalContext(true); + } + + @Override + public void update(@NotNull AnActionEvent e) { + e.getPresentation().setEnabled(!getText().isEmpty()); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + if (myCurrentSearchPanel.controller != null && myCurrentSearchPanel.controller.isPopupShow()) { + myCurrentSearchPanel.controller.hidePopup(); + } + else { + setText(""); + } + } + }.registerCustomShortcutSet(CommonShortcuts.ESCAPE, this); + return false; + } + @Override protected void onFieldCleared() { hideSearchPanel(); @@ -825,6 +850,8 @@ public class PluginManagerConfigurableNew createPopup(new CollectionListModel<>(result), SearchPopup.Type.SearchQuery); } + myPopup.data = query; + if (update) { myPopup.update(); return; @@ -839,7 +866,14 @@ public class PluginManagerConfigurableNew @Override protected void customizeCellRenderer(@NotNull JList list, Object value, int index, boolean selected, boolean hasFocus) { IdeaPluginDescriptor descriptor = (IdeaPluginDescriptor)value; - append(descriptor.getName()); + + String splitter = (String)myPopup.data; + for (String partName : SearchQueryParser.split(descriptor.getName(), splitter)) { + append(partName, partName.equalsIgnoreCase(splitter) + ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES + : SimpleTextAttributes.REGULAR_ATTRIBUTES); + } + if (isJBPlugin(descriptor)) { append(" by JetBrains", SimpleTextAttributes.GRAY_ATTRIBUTES); } @@ -856,14 +890,36 @@ public class PluginManagerConfigurableNew } @NotNull - private List localSearchPlugins(String query) { - List descriptors = new ArrayList<>(); + private List localSearchPlugins(@NotNull String query) { + IdeaPluginDescriptor descriptorEquals = null; + List descriptorsStartWith = new ArrayList<>(); + List descriptorsContains = new ArrayList<>(); + for (IdeaPluginDescriptor descriptor : getJBRepositoryList()) { - if (StringUtil.containsIgnoreCase(descriptor.getName(), query)) { - descriptors.add(descriptor); + String name = descriptor.getName(); + if (descriptorEquals == null && name.equalsIgnoreCase(query)) { + descriptorEquals = descriptor; + } + else if (StringUtil.startsWithIgnoreCase(name, query)) { + descriptorsStartWith.add(descriptor); + } + else if (StringUtil.containsIgnoreCase(name, query)) { + descriptorsContains.add(descriptor); } } - return descriptors; + + List result = new ArrayList<>(); + if (descriptorEquals != null) { + result.add(descriptorEquals); + } + + PluginsGroup.sortByName(descriptorsStartWith); + result.addAll(descriptorsStartWith); + + PluginsGroup.sortByName(descriptorsContains); + result.addAll(descriptorsContains); + + return result; } }; myTrendingSearchPanel = diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginsGroup.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginsGroup.java index 81e5d751c0c1..ee2eb2c1b30b 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginsGroup.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/PluginsGroup.java @@ -67,6 +67,10 @@ public class PluginsGroup { } public void sortByName() { + sortByName(descriptors); + } + + public static void sortByName(@NotNull List descriptors) { ContainerUtil.sort(descriptors, (o1, o2) -> StringUtil.compare(o1.getName(), o2.getName(), true)); } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopup.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopup.java index 0d9fedd6c495..0f00d80a64fb 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopup.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopup.java @@ -34,6 +34,8 @@ public class SearchPopup implements CaretListener { public boolean skipCaretEvent; + public Object data; + public enum Type { AttributeName, AttributeValue, SearchQuery } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopupController.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopupController.java index e755842297b6..99beed81b849 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopupController.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchPopupController.java @@ -227,6 +227,10 @@ public abstract class SearchPopupController { protected void handleAppendAttributeValue() { } + public boolean isPopupShow() { + return myPopup != null && myPopup.isValid(); + } + public void hidePopup() { if (myPopup != null) { myPopup.hide(); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java index a89fad48dbb7..fa0286b1bd1e 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/newui/SearchQueryParser.java @@ -1,6 +1,7 @@ // 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.plugins.newui; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.io.URLUtil; import org.jetbrains.annotations.NotNull; @@ -15,6 +16,31 @@ import java.util.Set; public abstract class SearchQueryParser { public String searchQuery; + @NotNull + public static List split(@NotNull String name, @NotNull String query) { + List result = new ArrayList<>(); + + int length = name.length(); + int queryLength = query.length(); + int index = 0; + + while (true) { + int end = StringUtil.indexOfIgnoreCase(name, query, index); + if (end == -1) { + break; + } + result.add(name.substring(index, end)); + index = end + queryLength; + result.add(name.substring(end, index)); + } + + if (index < length) { + result.add(name.substring(index)); + } + + return result; + } + @NotNull private static List splitQuery(@NotNull String query) { List words = new ArrayList<>();