Help Search Enhancements in Eclipse 3.2

Dejan Glozic, 12/10/2005

Background

This document describes enhancements for the Eclipse search added in the 3.2 time frame. The enhancements will first appear in 3.2 milestone 4 and will be subsequently refined until the final release. Consequently, we will update this document until the API freeze in M5 to reflect these refinements.

The problem

There were several new developments in Eclipse 3.2 that prompted us to beef up the search story in Eclipse.

Dynamic Content Serving

One of the major new additions to the help system in 3.2 release is dynamic content serving. Prior to 3.2, documents were considered static and the role of the Eclipse help system was to serve these documents to the web browser as-is. Since the content was static, it could not adapt to the workbench context (the operating system, active plug-ins, user role etc.). Content that was supposed to appear in several document could not be shared, and content could not be injected/contributed into existing documents via extensions.

Since 3.2, it will be possible to contribute XHTML documents enhanced with the additional Eclipse-specific grammar that provides for dynamic content filtering, reuse and contribution. The use of XHTML documents

User Assistance content outside of the TOC

Apart from the help system, there are other user assistance vehicles that serve content (e.g. cheat sheets and Welcome). This content was not indexed and therefore not part of the search. In addition to indexing it, it was important to preserve the fact that the search hits would need to be opened in a different way from regular help topics.

Federated search engines with delegation of the 'open' command

In 3.1, the assumption was that federated search engines are responsible for collecting search results and providing hrefs for the help system to open. However, experience has shown that some search engines have a different idea of what 'open' means to them and would like to handle that command.

The solution

As a solution for the above mentioned problems, we introduced a notion of search participants and tweaked the existing search APIs to be more flexible.

Search participants

Search participants are extensions to the Lucene indexing mechanism responsible for adding documents into the overall index that are out of reach of the current mechanism:

<extension point="org.eclipse.help.base.luceneSearchParticipant">
   <searchParticipant id="org.eclipse.myGlobalParticipant"
     name="Global Participant"
     icon="icons/mydoc.gif"
     participant="org.eclipse.myPlugin.myPackage.MyGlobalParticipant"/>
   <searchParticipant id="org.eclipse.myXYZParticipant"
     extensions="xyz"
     participant="org.eclipse.myPlugin.myPackage.MyXYZParticipant"/>
  </extension>

The example above shows two kinds of search participants. The first example registers a global participant responsible for introducing new documents into the index. These documents are not part of the TOC and would otherwise never be indexed. Cheat sheet and Intro plug-ins now both provide a global search participant that indexes cheat sheets and Intro pages. Name of the participant is used as a result category and also for scope settings in the search engine scope dialog. Optional icon attribute is used to render search results differently if the come from this search participant.

The second example shows content type search participant. It is used for documents that are part of the Help's TOC but have a format that Help cannot handle. These participants do not need to declare a different image or name, but must specify a comma-separated list of file extensions they will handle. Help system provides XHTML search participant that can be used by document plug-ins to complement the dynamic content producer that handles XHMTL TOC documents and transforms them dynamically.

Global search participants have global scope. In contrast, search participants declared for file extensions only work with content coming from their contributing plug-in. In order to use services of a content-sensitive search participant, other plug-ins must declare an explicit binding to them:

<extension point="org.eclipse.help.base.luceneSearchParticipant">
    <binding participantId="org.eclipse.myXYZParticipant"/>
</extension>

This overhead was important to prevent viral effect of content-sensitive participants. Since they are given a chance to index a document of the extension they are registered for before the default help indexer, they can potentially take over indexing of all documents in the product. The notion of binding adds a degree of protection by only extending the visibility of these participants to plug-ins that allowed them in this way.

The attribute participant must has a value that represents a fully qualified name of the Java class that extends abstract class LuceneSearchParticipant. An abstract class rather than an interface has been selected in order to provide for an easier API evolution and also to provide some helper protected methods that subclasses can use. A very useful class for extenders will be XMLSearchParticipant that greatly simplifies indexing of XML source files. It makes

Enhancements to the existing classes

New interfaces have been added to extend the existing ISearchEngine and ISearchEngineResult:

public interface ISearchEngineResult2 extends ISearchEngineResult {
	String getId();
	URL getIconURL();
	boolean canOpen();
}
public interface ISearchEngine2 extends ISearchEngine {
	boolean open(String id);
}

Engine results that implement ISearchEngineResult2 have additional methods that give more freedom to search engines. A search result can now return a URL of the icon image to render the result. It can also return a unique id as an alternative to href. Finally, if it returns true from the canOpen method, the help system will not try to open it itself. Instead, if the contributing search engine implements ISearchEngine2, it will delegate opening to the engine itself by passing the id of the result.

Notice how we chose to pass the id to the search engine rather than search result directly. This indirection makes bookmarking these types of hit results possible. If a search result returns true to canOpen, we don't store its href any more. Instead, we store the engine id and result id. This allows us to delegate bookmark opening to the contributing engine in the same way we do when opening from the search result view.