Problems generating searchableOptions.xml

Hi all,

I'm trying to generate a searchableOptions.xml for my plugin, but it's proving difficult to find the correct magic incantation. This is what I have right now:

In my run config, I have:

Main class: com.intellij.idea.Main
VM options: -Djava.awt.headless=true -Xmx800m -XX:ReservedCodeCacheSize=64m -XX:MaxPermSize=250m -XX:+HeapDumpOnOutOfMemoryError -ea -Didea.is.internal=true -Didea.debug.mode=true -Didea.system.path=../clojure-system -Didea.config.path=../clojure-config -Dplugin.path=/Users/colin/dev/cursive/out/artifacts/Clojure
Program arguments: traverseUI /Users/colin/dev/cursive/searchableOptions.xml

I've tried various combinations of com.intellij.rt.execution.CommandLineWrapper etc as in the community build file but I can't get it to work. The error I'm getting is:

Starting searchable options index builder
Searchable options index builder failed
[  11679]  ERROR - openapi.options.ConfigurableEP - cursive.compiler.ClojureCompilerConfigurable has unsatisfied dependency: class cursive.compiler.ClojureCompilerSettings among unsatisfiable dependencies: [[class cursive.compiler.ClojureCompilerSettings, interface com.intellij.openapi.project.Project]] where AreaPicoContainer[Project (Default) Default (Template) Project] was the leaf container being asked for dependencies.
org.picocontainer.defaults.UnsatisfiableDependenciesException: cursive.compiler.ClojureCompilerConfigurable has unsatisfied dependency: class cursive.compiler.ClojureCompilerSettings among unsatisfiable dependencies: [[class cursive.compiler.ClojureCompilerSettings, interface com.intellij.openapi.project.Project]] where AreaPicoContainer[Project (Default) Default (Template) Project] was the leaf container being asked for dependencies.
    at com.intellij.util.pico.ConstructorInjectionComponentAdapter.getGreediestSatisfiableConstructor(ConstructorInjectionComponentAdapter.java:100)
    at org.picocontainer.defaults.ConstructorInjectionComponentAdapter$1.run(ConstructorInjectionComponentAdapter.java:210)
    at org.picocontainer.defaults.ThreadLocalCyclicDependencyGuard.observe(ThreadLocalCyclicDependencyGuard.java:53)
    at org.picocontainer.defaults.ConstructorInjectionComponentAdapter.getComponentInstance(ConstructorInjectionComponentAdapter.java:248)
    at com.intellij.openapi.extensions.AbstractExtensionPointBean.instantiate(AbstractExtensionPointBean.java:75)
    at com.intellij.openapi.options.ConfigurableEP$NewInstanceFactory.create(ConfigurableEP.java:213)
    at com.intellij.openapi.options.ConfigurableEP$NewInstanceFactory.create(ConfigurableEP.java:211)
<snip etc etc>


I can't understand why it can't instantiate cursive.compiler.ClojureCompilerSettings - it does look like the classpath is correctly picking up my plugin since it's picking up cursive.compiler.ClojureCompilerConfigurable. Here's how they're defined in plugin.xml:

<projectConfigurable instance="cursive.compiler.ClojureCompilerConfigurable" id="Clojure Compiler"
                     displayName="Clojure Compiler" parentId="project.propCompiler"
/>


<component>
  <implementation-class>cursive.compiler.ClojureCompilerSettings</implementation-class>
</component>

Any pointers as to what I'm doing wrong here? Is this the correct way to create searchable options for my plugin?

4 comments
Comment actions Permalink

searchableOptions.xml is not a file that can be contributed by a plugin; each IDE can have only one instance of that file, generated at IDE build time. There is some new API in 14.1 (SearchableOptionsContributor) that allows third-party plugins to work better with options search, but right now there is no automated way to generate an implementation of such a contributor.

0
Comment actions Permalink

So in versions prior to v14.1, is it even possible for a plugin to have its options searchable? Can I use SearchableOptionsRegistrar.addOption()? If so, what should the parameters be? It's hard to figure out the API and there are few examples that don't just load from the XML files. I also can't see any way that this would highlight the usage of the word in the settings UI - is that only available to core settings via the XML?

0
Comment actions Permalink

In case anyone is interested, here's how I did this. searchableOptions.xml basically contains a list of words for each Configurable instance, associated with the full text of the string where the word is encountered - this is the "hit". I created a ProjectComponent called OptionsSearchRegisterer which manually registers these at startup - I tried to use an application component but had deadlock problems at startup due to the need to call SearchableOptionsRegistrar.getInstance(). I identify all the text strings in my configurable UIs by extracting them as constants and then having a SEARCHABLE static field which is an array of all searchable strings for a particular Configurable. Here's an example:

public final class ClojureIdeConfigurable implements Configurable {

  public static final String COMPONENT_ID = "Clojure.IDE";
  public static final String COMPONENT_NAME = "Clojure";

  public static final String RAINBOW_PARENTHESES = "Rainbow parentheses";
  public static final String VISUALLY_SEPARATE_REPL = "Visually separate REPL evaluations";
  public static final String HIGHLIGHT_UNRESOLVED = "Highlight unresolved symbols";
  public static final String UP_DOWN_ARROWS_HISTORY = "Up/Down arrow keys move between history items";
  public static final String LOAD_TRANSITIVE_DEPS = "Load out-of-date file dependencies transitively";
  public static final String USE_REPL_NS = "Load forms in REPL namespace";
  public static final String APPEARANCE_OPTIONS = "Appearance options";
  public static final String EDITOR_TAB_STYLE = "Editor tab style: ";
  public static final String REPL_OPTIONS = "REPL options";
  public static final String REPL_HISTORY_SIZE = "REPL history size: ";
  public static final String REPL_STARTUP_TIMEOUT = "REPL startup timeout (seconds): ";

  public static final String[] SEARCHABLE = {RAINBOW_PARENTHESES, VISUALLY_SEPARATE_REPL, HIGHLIGHT_UNRESOLVED,
      UP_DOWN_ARROWS_HISTORY, LOAD_TRANSITIVE_DEPS, USE_REPL_NS, APPEARANCE_OPTIONS, EDITOR_TAB_STYLE,
      REPL_OPTIONS, REPL_HISTORY_SIZE, REPL_STARTUP_TIMEOUT};


Then in OptionsSearchRegisterer looks like this:

public class OptionsSearchRegisterer implements ProjectComponent {

  @Override
  public void
initComponent() {
    SearchableOptionsRegistrar registrar = SearchableOptionsRegistrar.getInstance();
    processConfigurable(registrar,
                        ClojureIdeConfigurable.COMPONENT_ID,
                        ClojureIdeConfigurable.COMPONENT_NAME,
                        ClojureIdeConfigurable.SEARCHABLE);
    ...etc etc for each configurable...
  }

  public void processConfigurable(SearchableOptionsRegistrar registrar,
                                  String componentId,
                                  String componentName,
                                  String[] searchable) {
    processUILabel(registrar, componentId, componentName, componentName);
    for (String item : searchable) {
      processUILabel(registrar, componentId, componentName, item);
    }
  }

  private static void processUILabel(SearchableOptionsRegistrar registrar,
                                     String componentId,
                                     String componentName,
                                     String text) {
    for (String option : SearchableOptionsRegistrar.getInstance().getProcessedWordsWithoutStemming(text)) {
      registrar.addOption(option, null, text, componentId, componentName);
    }
  }


This basically does by hand what the XML process does automatically. It works well for me because I code the UIs by hand, it would be a pain if I were using forms. It seems odd to have this as a project component, but registering the options multiple times (each time a project is initialised) doesn't seem to matter - all the strings are interned and the options are stored in a set.

Hope that helps someone! AFAIK this should work in any recent IntelliJ version.

0
Comment actions Permalink

Thanks Colin. I'd been trying for a while to get SearchableConfigurable working. Doing that final post 3 years ago has enabled me to do this:
https://github.com/intellij-dlanguage/intellij-dlanguage/issues/401

0

Please sign in to leave a comment.