From 404c80311c242442db3af9acaffdc2a3370761f3 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Jan 2015 20:04:25 +0100 Subject: [PATCH] an API to contribute searchable options from plugins --- .../ex/InspectionManagerEx.java | 42 --------------- ...InspectionSearchableOptionContributor.java | 49 ++++++++++++++++++ .../header/InspectionToolsConfigurable.java | 7 --- .../search/SearchableOptionContributor.java | 31 +++++++++++ .../ui/search/SearchableOptionProcessor.java | 51 +++++++++++++++++++ .../options/SearchableConfigurable.java | 8 +++ .../SearchableOptionsRegistrarImpl.java | 32 +++++++++++- .../actionSystem/impl/ActionManagerImpl.java | 2 + .../src/META-INF/LangExtensions.xml | 2 + .../src/META-INF/PlatformExtensionPoints.xml | 2 + 10 files changed, 176 insertions(+), 50 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionSearchableOptionContributor.java create mode 100644 platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionContributor.java create mode 100644 platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionProcessor.java diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java index 2484e1e71d58..47815f3eecf0 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java @@ -25,9 +25,7 @@ package com.intellij.codeInspection.ex; import com.intellij.codeInspection.*; import com.intellij.icons.AllIcons; import com.intellij.ide.impl.ContentManagerWatcher; -import com.intellij.ide.ui.search.SearchableOptionsRegistrar; import com.intellij.lang.Language; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyValue; @@ -35,30 +33,23 @@ import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.profile.codeInspection.ui.header.InspectionToolsConfigurable; import com.intellij.psi.PsiElement; import com.intellij.ui.content.ContentFactory; import com.intellij.ui.content.ContentManager; import com.intellij.ui.content.TabbedPaneContentUI; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Pattern; public class InspectionManagerEx extends InspectionManagerBase { - private static final Pattern HTML_PATTERN = Pattern.compile("<[^<>]*>"); private final NotNullLazyValue myContentManager; private final Set myRunningContexts = new HashSet(); - private final AtomicBoolean myToolsAreInitialized = new AtomicBoolean(false); private GlobalInspectionContextImpl myGlobalInspectionContext; - public InspectionManagerEx(final Project project) { super(project); if (ApplicationManager.getApplication().isHeadlessEnvironment()) { @@ -114,15 +105,6 @@ public class InspectionManagerEx extends InspectionManagerBase { }); } - private static void processText(@NotNull @NonNls String descriptionText, - @NotNull InspectionToolWrapper tool, - @NotNull SearchableOptionsRegistrar myOptionsRegistrar) { - if (ApplicationManager.getApplication().isDisposed()) return; - final Set words = myOptionsRegistrar.getProcessedWordsWithoutStemming(descriptionText); - for (String word : words) { - myOptionsRegistrar.addOption(word, tool.getShortName(), tool.getDisplayName(), InspectionToolsConfigurable.ID, InspectionToolsConfigurable.DISPLAY_NAME); - } - } @NotNull public ProblemDescriptor createProblemDescriptor(@NotNull final PsiElement psiElement, @@ -182,28 +164,4 @@ public class InspectionManagerEx extends InspectionManagerBase { return myContentManager; } - public void buildInspectionSearchIndexIfNecessary() { - if (!myToolsAreInitialized.getAndSet(true)) { - final SearchableOptionsRegistrar myOptionsRegistrar = SearchableOptionsRegistrar.getInstance(); - final InspectionToolRegistrar toolRegistrar = InspectionToolRegistrar.getInstance(); - final Application app = ApplicationManager.getApplication(); - if (app.isUnitTestMode() || app.isHeadlessEnvironment()) return; - - app.executeOnPooledThread(new Runnable(){ - @Override - public void run() { - List tools = toolRegistrar.createTools(); - for (InspectionToolWrapper toolWrapper : tools) { - processText(toolWrapper.getDisplayName().toLowerCase(), toolWrapper, myOptionsRegistrar); - - final String description = toolWrapper.loadDescription(); - if (description != null) { - @NonNls String descriptionText = HTML_PATTERN.matcher(description).replaceAll(" "); - processText(descriptionText, toolWrapper, myOptionsRegistrar); - } - } - } - }); - } - } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionSearchableOptionContributor.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionSearchableOptionContributor.java new file mode 100644 index 000000000000..7e581b8dbea8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionSearchableOptionContributor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInspection.ex; + +import com.intellij.ide.ui.search.SearchableOptionContributor; +import com.intellij.ide.ui.search.SearchableOptionProcessor; +import com.intellij.profile.codeInspection.ui.header.InspectionToolsConfigurable; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +import java.util.regex.Pattern; + +/** + * @author peter + */ +public class InspectionSearchableOptionContributor extends SearchableOptionContributor { + private static final Pattern HTML_PATTERN = Pattern.compile("<[^<>]*>"); + + @Override + public void processOptions(@NotNull SearchableOptionProcessor processor) { + for (InspectionToolWrapper toolWrapper : InspectionToolRegistrar.getInstance().createTools()) { + String hit = toolWrapper.getDisplayName(); + processor.addOptions(toolWrapper.getDisplayName(), toolWrapper.getShortName(), hit, + InspectionToolsConfigurable.ID, + InspectionToolsConfigurable.DISPLAY_NAME, false); + + final String description = toolWrapper.loadDescription(); + if (description != null) { + @NonNls String descriptionText = HTML_PATTERN.matcher(description).replaceAll(" "); + processor.addOptions(descriptionText, toolWrapper.getShortName(), hit, InspectionToolsConfigurable.ID, + InspectionToolsConfigurable.DISPLAY_NAME, false); + } + } + + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java index 747f00297b75..881f4a31ecd1 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java @@ -24,9 +24,7 @@ package com.intellij.profile.codeInspection.ui.header; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; -import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ModifiableModel; -import com.intellij.codeInspection.ex.InspectionManagerEx; import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.codeInspection.ex.InspectionToolRegistrar; import com.intellij.codeInspection.ex.InspectionToolWrapper; @@ -57,13 +55,10 @@ import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.ui.ErrorsConfigurable; import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; -import com.intellij.ui.JBColor; import com.intellij.ui.ListCellRendererWrapper; import com.intellij.util.Alarm; import com.intellij.util.Consumer; -import com.intellij.util.Function; import com.intellij.util.SystemProperties; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jdom.Document; import org.jdom.Element; @@ -388,8 +383,6 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable toolbar.add(myAuxiliaryRightPanel.getHintLabel(), new GridBagConstraints(3, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(0, 15, 6, 0), 0, 0)); toolbar.add(myAuxiliaryRightPanel, new GridBagConstraints(3, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 15, 0, 0), 0, 0)); - - ((InspectionManagerEx)InspectionManager.getInstance(projectProfileManager.getProject())).buildInspectionSearchIndexIfNecessary(); myProjectProfileManager = projectProfileManager; myProfileManager = profileManager; } diff --git a/platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionContributor.java b/platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionContributor.java new file mode 100644 index 000000000000..abcfe2745677 --- /dev/null +++ b/platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionContributor.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.ui.search; + +import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.NotNull; + +/** + * An extension allowing plugins to provide the data at runtime for the setting search to work on. + * + * @author peter + */ +public abstract class SearchableOptionContributor { + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.search.optionContributor"); + + public abstract void processOptions(@NotNull SearchableOptionProcessor processor); + +} diff --git a/platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionProcessor.java b/platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionProcessor.java new file mode 100644 index 000000000000..85025bf88fda --- /dev/null +++ b/platform/platform-api/src/com/intellij/ide/ui/search/SearchableOptionProcessor.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.ui.search; + +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.SearchableConfigurable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +/** + * A place for {@link SearchableOptionContributor} implementations to feed the searchable options to. + * + * @author peter + */ +public abstract class SearchableOptionProcessor { + /** + * Take text that can be found on a setting page, split it into words and add them to the internal setting search index. + * + * @param text the text that appears on a setting page and can be searched for + * @param path for complex settings pages, identifies the subpage where the option is to be found. + * For example, it can be the name of tab on the settings page that should be opened when showing search results. + * Can be null for simple configurables. + * @param hit the string that's presented to the user when showing found results in a list, e.g. in Goto Action. + * @param configurableId the id of the topmost configurable containing the search result. See {@link SearchableConfigurable#getId()} + * @param configurableDisplayName display name of the configurable containing the search result + * @param applyStemming whether only word stems should be indexed or the full words. Porter stemmer is used. + */ + public abstract void addOptions(@NotNull String text, + @Nullable String path, + @Nullable String hit, + @NotNull final String configurableId, + @Nullable final String configurableDisplayName, + boolean applyStemming); + + +} diff --git a/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java b/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java index 2ed7ef4a47a3..f8ebe2ac84e0 100644 --- a/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java +++ b/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java @@ -16,6 +16,7 @@ package com.intellij.openapi.options; +import com.intellij.ide.ui.search.SearchableOptionContributor; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -26,11 +27,18 @@ import javax.swing.JComponent; /** * SearchableConfigurable instances would be instantiated on buildSearchableOptions step during Installer's build to index of all available options. * {@link #com.intellij.ide.ui.search.TraverseUIStarter} + * + * @see SearchableOptionContributor */ public interface SearchableConfigurable extends Configurable { @NotNull @NonNls String getId(); + /** + * @param option setting search query + * @return an action to perform when this configurable is opened when a search filter query is entered by the user in setting dialog. + * This action, for example, can select something in a tree or a list embedded in this setting page that matches the query. + */ @Nullable Runnable enableSearch(String option); interface Parent extends SearchableConfigurable, Composite { diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java index 2daae1ae7da6..fd1a8d0c576f 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchableOptionsRegistrarImpl.java @@ -87,6 +87,36 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { catch (IOException e) { LOG.error(e); } + + loadExtensions(); + } + + private void loadExtensions() { + final SearchableOptionProcessor processor = new SearchableOptionProcessor() { + @Override + public void addOptions(@NotNull String text, + @Nullable String path, + @Nullable String hit, + @NotNull String configurableId, + @Nullable String configurableDisplayName, + boolean applyStemming) { + Set words = applyStemming ? getProcessedWords(text) : getProcessedWordsWithoutStemming(text); + for (String word : words) { + addOption(word, path, hit, configurableId, configurableDisplayName); + } + } + + }; + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + //todo what if application is disposed? + for (SearchableOptionContributor contributor : SearchableOptionContributor.EP_NAME.getExtensions()) { + contributor.processOptions(processor); + } + } + }); } private void loadHugeFilesIfNecessary() { @@ -180,7 +210,7 @@ public class SearchableOptionsRegistrarImpl extends SearchableOptionsRegistrar { } } - private synchronized void putOptionWithHelpId(String option, final String id, final String groupName, String hit, final String path) { + private synchronized void putOptionWithHelpId(@NotNull String option, @NotNull final String id, @Nullable final String groupName, @Nullable String hit, @Nullable final String path) { if (isStopWord(option)) return; String stopWord = PorterStemmerUtil.stem(option); if (stopWord == null) return; diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java index 88569b18ae33..4406c6da5d12 100644 --- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java @@ -23,6 +23,7 @@ import com.intellij.ide.DataManager; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.ide.ui.search.SearchableOptionsRegistrar; import com.intellij.idea.IdeaLogger; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; @@ -1279,6 +1280,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat @Override public void run() { try { + SearchableOptionsRegistrar.getInstance(); // load inspection descriptions etc. to be used in Goto Action, Search Everywhere doPreloadActions(); } catch (RuntimeInterruptedException ignore) { } diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index c3554a3ff5ee..5d7c2aba66eb 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -891,6 +891,8 @@ + + diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml index a26f4ca56cd5..b41fb2656c72 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml @@ -217,6 +217,8 @@ + +