The platform text framework defines a document model for text and provides a viewer that displays text using this model. We will start by looking at the Java editor example and how it uses this model. We will not focus on the basic mechanics of registering an editor extension, since we've already seen this in the section discussing org.eclipse.ui.editors. Instead, we'll look at the specifics of how the editor class is implemented in the example.
In the workbench, an editor is typically opened when the user selects a domain element (such as a file or an element stored inside an archive file) and opens it. When the editor is created, it is associated with an editor input (IEditorInput), which describes the object being edited.
The Java editor example opens when the user opens a file with the "*.jav" extension. In this case, the input to the editor is an IFileEditorInput. The platform text framework assumes little about the editor input itself. It works with a presentation model, called an IDocument, for the input, so that it can effectively display and manipulate text.
This means that there must be a way to map from an expected domain model (the editor input) to the presentation model. This mapping is defined in an IDocumentProvider. Given an editor input, the document provider returns an appropriate IDocument.
The Java editor example inherits the TextFileDocumentProvider defined by the plug-in org.eclipse.ui.editors. The extension org.eclipse.ui.editors.documentProviders is used to define mappings between editor input types (or file extensions) and document providers. The editors plug-in defines its document provider as follows:
<extension point="org.eclipse.ui.editors.documentProviders"> <provider class="org.eclipse.ui.editors.text.TextFileDocumentProvider" inputTypes="org.eclipse.ui.IStorageEditorInput" id="org.eclipse.ui.editors.text.StorageDocumentProvider"> </provider> </extension>
This extension point allows plug-ins to register document providers and associate them with either a file extension or an editor input class. Since the Java editor example does not define its own document provider extension, it inherits the generic document provider specified for all input types that are IStorageEditorInput. When the user opens a file for editing, the platform manages the details of creating the proper document provider instance. If a specific document provider is registered for the file extension, that one will be used. If there is no specific document provider for the file extension, then the editor input type will be used to find the appropriate provider.
By using the generic platform document provider, the Java editor example can take advantage of all of the features of the document provider, such as file buffering and other optimizations.
Since the Java editor uses the platform text document provider, how can it supply any specialized behavior for handling Java files?
The extension org.eclipse.core.filebuffers.documentSetup is used to define mappings between file extensions and an IDocumentSetupParticipant. The setup participant will set up the document with any special features once it has been provided to the editor.
<extension id="ExampleJavaDocumentSetupParticipant" name="%documentSetupParticipantName" point="org.eclipse.core.filebuffers.documentSetup"> <participant extensions="jav" class="org.eclipse.ui.examples.javaeditor.JavaDocumentSetupParticipant"> </participant> </extension>
This extension definition is what gives the example a chance to setup the document for Java specific tasks. So what does JavaDocumentSetupParticipant do? We'll look at a simplified version of the setup method.
public void setup(IDocument document) { ... IDocumentPartitioner partitioner= new FastPartitioner(JavaEditorExamplePlugin.getDefault().getJavaPartitionScanner(), JavaPartitionScanner.JAVA_PARTITION_TYPES); partitioner.connect(document); ... }
The setup code configures an object called a partitioner.
The partitioner (IDocumentPartitioner) is responsible for dividing the document into non-overlapping regions called partitions. Partitions (represented by ITypedRegion) are useful for treating different sections of the document differently with respect to features like syntax highlighting or formatting.
In the case of the Java editor example, the document is divided into partitions that represent the javadoc comments, multi line comments, and everything else. Each region is assigned a content type and its position in the document. Positions are updated as the user edits text.
It is up to each editor to determine the appropriate implementation for a document partitioner. Support is provided in org.eclipse.jface.text.rules for rule-based document scanning. Using a rule-based scanner allows an editor to use the FastPartitioner provided by the framework.
IDocumentPartitioner partitioner= new FastPartitioner(JavaEditorExamplePlugin.getDefault().getJavaPartitionScanner(), JavaPartitionScanner.JAVA_PARTITION_TYPES);
RuleBasedPartitionScanner is the superclass for rule based scanners. Subclasses are responsible for enumerating and implementing the rules that should be used to distinguish tokens such as line delimiters, white space, and generic patterns when scanning a document. The example's JavaPartitionScanner defines rules for distinguishing single line comments, character constants, javadoc, multi line comments, and words. This is done in the scanner's constructor:
public JavaPartitionScanner() { super(); IToken javaDoc= new Token(JAVA_DOC); IToken comment= new Token(JAVA_MULTILINE_COMMENT); List rules= new ArrayList(); // Add rule for single line comments. rules.add(new EndOfLineRule("//", Token.UNDEFINED)); // Add rule for strings and character constants. rules.add(new SingleLineRule("\"", "\"", Token.UNDEFINED, '\\')); rules.add(new SingleLineRule("'", "'", Token.UNDEFINED, '\\')); // Add special case word rule. rules.add(new WordPredicateRule(comment)); // Add rules for multi-line comments and javadoc. rules.add(new MultiLineRule("/**", "*/", javaDoc, (char) 0, true)); rules.add(new MultiLineRule("/*", "*/", comment, (char) 0, true)); IPredicateRule[] result= new IPredicateRule[rules.size()]; rules.toArray(result); setPredicateRules(result); }
See the classes in org.eclipse.jface.text.rules for more details about defining rules and the types of rules availables. We'll look at the scanners again when we look at syntax coloring.