2
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
7
The contents of this file are subject to the terms of either the GNU
8
General Public License Version 2 only ("GPL") or the Common
9
Development and Distribution License("CDDL") (collectively, the
10
"License"). You may not use this file except in compliance with the
11
License. You can obtain a copy of the License at
12
http://www.netbeans.org/cddl-gplv2.html
13
or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
14
specific language governing permissions and limitations under the
15
License. When distributing the software, include this License Header
16
Notice in each file and include the License file at
17
nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
18
particular file as subject to the "Classpath" exception as provided
19
by Sun in the GPL Version 2 section of the License file that
20
accompanied this code. If applicable, add the following below the
21
License Header, with the fields enclosed by brackets [] replaced by
22
your own identifying information:
23
"Portions Copyrighted [year] [name of copyright owner]"
27
The Original Software is NetBeans. The Initial Developer of the Original
28
Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
29
Microsystems, Inc. All Rights Reserved.
31
If you wish your version of this file to be governed by only the CDDL
32
or only the GPL Version 2, indicate your decision by adding
33
"[Contributor] elects to include this software in this distribution
34
under the [CDDL or GPL Version 2] license." If you do not indicate a
35
single choice of license, a recipient has the option to distribute
36
your version of this file under either the CDDL, the GPL Version 2 or
37
to extend the choice of license to its licensees as provided above.
38
However, if you add GPL Version 2 code and therefore, elected the GPL
39
Version 2 license, then the option applies only if the new code is
40
made subject to such option by the copyright holder.
43
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
47
<title>org.netbeans.spi.editor.lib2.highlighting</title>
52
The Highlighting SPI is a new way of influencing how text in an editor component
53
is rendered. The editor framework in Netbeans is an extension of the Swing Text SPI
54
framework and as such it uses things like <code>Element</code>s and <code>View</code>s
55
to render a <code>Document</code> on a screen.
59
Since the editor framework is primarily designed to support various different
60
types of files in the IDE it has to give module a chance to participate in documents
61
rendering. Modules providing support for different languages usually need to influence
62
colors and fonts of different parts of a source file depending on what code it
63
contains (i.e. syntax coloring) or what other information the module needs presenting
64
to a user (e.g. text annotations, hyperlinking, etc.). This all and more can
65
be achieved by using the Highlighting SPI.
69
<h3>Key parts of the SPI</h3>
72
The very basic idea behind the SPI is to render a document as a sandwich of
73
independent layers, which will say what colors and font should be used for rendering
74
particular parts of the document. These parts of the document together with their
75
<i>rendering attributes</i> (i.e. colors or font) are called <i>highlighted areas</i>
76
or <i>highlights</i>. Each layer can provide as many non-overlapping highlights
77
as it likes and each module can provide as many layers as it needs. The implementation
78
behind the SPI will collect all layers registered for a particular document type
79
(i.e. mime type), ask each of them for its highlights, merge those highlights
80
together and finally send them to the draw engine, which will render the document.
84
The whole SPI is organized around the
85
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/HighlightsLayer.html">HighlightsLayer</a></code>
86
class, which is the ultimate thing that modules need to implement in order to provide
87
a list of highlights for a document. The <code>HighlightsLayer</code>s are created
88
by <code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html">HighlightsLayerFactory</a></code>,
89
which should be registered in <code>MimeLookup</code> under the mime-type of a document
90
that the layer should be used for. All layers registered for one type of a document
91
are ordedred according to the
92
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/ZOrder.html">ZOrder</a></code>
93
they provide. Besides of <code>ZOrder</code> the layers provide additional information
94
about nature of highlights they maintain.
98
The <code>HighlightsLayer</code> class implements
99
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/HighlightsContainer.html">HighlightsContainer</a></code>
100
interface, which is the fundamental part of the SPI.
101
The <code>HighlightsContainer</code> interface allows to get a list of highlighs
102
and to listen on changes in highlights that it contains.
103
Besides of <code>HighlightsLayer</code> there are two other implementations of
104
this interface and they are
105
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/support/OffsetsBag.html">OffsetsBag</a></code>
107
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/support/PositionsBag.html">PositionsBag</a></code>.
108
Both <code>OffsetsBag</code> and <code>PositionsBag</code> classes allow adding
109
and removing highlights dynamically. The highlights can be added either one-by-one
110
or in chunks; each change is reported to listeners.
114
<h3>HighlightsLayer registration</h3>
117
The registration of <code>HighlightsLayer</code>s has to be done through an
118
instance of the <code>HighlightsLayerFactory</code> class. The factory should
119
be registered in <code>MimeLookup</code> under the mime-type of documents, which
120
the <code>HighlightsLayer</code> should be used for. For example, if a module
121
wants to provide <code>HighlightsLayer</code> for <code>text/x-something</code> documents
122
it should implement its own <code>HighlightsLayerFactory</code> (e.g.
123
<code>org.some.module.HLFactory</code> class) and register it in <code>MimeLookup</code>
124
using its XML layer as it is shown on the example below.
128
<folder name="Editors">
129
<folder name="text">
130
<folder name="x-something">
131
<file name="org-some-module-HLFactory.instance" />
138
The <code>HLFactory</code> class will simply return a new instance of
139
the module's implementation of the <code>HighlightsLayer</code> class from its
140
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/HighlightsLayerFactory.html#createLayers(org.netbeans.spi.editor.highlighting.HighlightsLayerFactory.Context)">createLayers</a></code>
141
method. The parameter of the <code>createLayers</code> method provides access to
142
a <code>JTextComponent</code> and its <code>Document</code>, which the layer
143
is being created for. The method can create and return multiple <code>HighlightsLayer</code>s.
147
<h3>HighlightsLayer lifecycle</h3>
149
<p>The lifecycle of <code>HighlightsLayer</code>s is tied to the lifecycle of
150
<code>Document</code>. The infrastructure creates new instances of layers by calling
151
registered <code>HighlightsLayerFactory</code> objects every time it needs to
152
visualize a new <code>Document</code>. The layers created for one <code>Document</code>
153
are not cached or resused in any way. This means that the layers themselvs do not have to take
154
care about a potential change of a <code>Document</code> instance in
155
<code>JTextComponent</code>. The infrastructre will always create a new set of
156
layers if the <code>Document</code> instance changes. Therefore the layers can
157
simply hold their instance of <code>JTextComponent</code> and/or <code>Document</code>
158
and treat them as invariants.
162
<h3>Locking and <code>Document</code> changes</h3>
165
The basics of the locking and events model of Swing documents is
166
described in the javadoc of the
167
<a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/AbstractDocument.html">javax.swing.text.AbstractDocument</a>
168
class. Netbeans documents use the same patterns and so does the Highlighting SPI,
169
because of its tight relation to documents. The fundamentals of the Swing documents
170
locking model are that any changes to a document are done under the
171
document's write lock, the document's listeners are notified synchronously on the
172
mutating thread and have full read access to the document, but can't modify it.
176
The main functionality of the Highlighting SPI is to maintain highlights
177
of certain areas of a document. These highlights are specified as a triple of
178
starting offset, ending offset and a set of attributes. The offsets are usually passed
179
in and out accross the SPI boundaries in form of <code>int</code>s and even though
180
some implementations (e.g. <code>PositionsBag</code>) use
181
<code><a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/text/Position.html">Position</a></code>s
182
the esential rule is that any calls in and out from the SPI have to be made
183
under the document's read lock. Let's have a look on a few examples demonstrating
189
Any calls from the infrastructure to <code>HighlightsLayer.getHighlights()</code>
190
have to be carried on under the read lock of the document, which the <code>HighlightsLayer</code>
194
When <code>HighlightsLayer</code> needs to notify its listeneres that some
195
of its highlights have changed all the events have to be fired under the
196
layer's document's read lock. Obviously, the listeners are not allowed to
197
modify the document from the event notification methods.
200
Any calls to <code>OffsetsBag</code> or <code>PositionsBag</code> that modify
201
their content have to be done under the read lock of the document, which the bag
202
was created for. Both bags makes all the
203
changes synchronously on the caller's thread and this even includes firing
204
notification events. Therefore all events fired from <code>OffsetsBag</code>
205
or <code>PositionsBag</code>
206
will be fired under the document's read lock if the mutating thread holds the
212
The Highlighting SPI does not use any special threads and any processing it
213
does is always done on the caller's thread. This means that the above described
214
constraints hardly cause any limitation for practical use. The majority of
215
things happening around a document are done from within
216
<code><a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/event/DocumentListener.html">DocumentListener</a></code>s,
217
which hold the document's read lock anyway.
221
The Highlighting SPI is generally thread-safe meaning that any implementation
222
behind the SPI can be used simultaneously from multiple threads if not stated
223
otherwise. This doesn't change in any way the rule of acquiring a read lock
224
before calling the SPI. Swing documents generally allow access for multiple
225
readers that can run concurrently.
231
Since there can be multiple layers suplying highlights for one document and the
232
highlights can generally overlap it is important to sort the layers according
233
to their Z-order. For this purpose each layer has to supply an appropriate
234
<code><a href="@org-netbeans-modules-editor-lib2@/org/netbeans/spi/editor/highlighting/ZOrder.html">ZOrder</a></code>.
238
<code>ZOrder</code> maintains a position of a layer
239
relatively to other layers as a simple integer number. The higher the number
240
the higher (more visible) the layer is in the z-order hierarchy.
241
Instances of the <code>ZOrder</code> class are immutable making it
242
impossible to dynamically change a position of a layer in the z-order stack
243
created for a document.
247
The <code>ZOrder</code> class contains several predefined constants,
248
which can be used as well-known positions. These constants are called z-order
249
racks and are meant to be used as a starting point for positioning a layer. An
250
exact z-order can then be specified by choosing an integer position of the layer
251
within a rack. The racks are listed below in their respective z-order.
255
<li><code>TOP_RACK</code> - the top most rack</li>
257
<code>SHOW_OFF_RACK</code> - layers providing short-lived highlights that
258
can temporarily override highlights from other layers. An example can be
259
text selection or text search layers.
261
<li><code>DEFAULT_RACK</code> - the rack for general layers</li>
262
<li><code>CARET_RACK</code> - layers that highlight a caret</li>
264
<code>SYNTAX_RACK</code> - layers providing syntax or semantic
265
highlighting of text</li>
266
<li><code>BOTOM_RACK</code> - the bottom rack</li>
270
- different types of layers - block highlights vs. text highlights, highlights altering metrics
274
<h3>Using <code>AttributeSet</code></h3>
276
The Highlighting SPI uses <code>javax.swing.text.AttributeSet</code> to define
277
attributes for particular highlights. These attributes can be anything,
278
which the editor's drawing engine understands and can render. Usually the
279
attribute names are constants from <code>javax.swing.StyleConstants</code> or
280
<code>org.netbeans.api.editor.settings.EditorStyleConstants</code>. The values
281
depend on the meaning of each particular attribute, but they usually are instances
282
of <code>java.awt.Color</code>, <code>java.lang.Integer</code>, <code>Boolean.TRUE</code>
283
or <code>Boolean.FALSE</code> and similar.
287
Since there can be more highlighting layers participating on one document and
288
they can provide highlights that overlap the infrastructure will merge attributes
289
from all <code>AttributeSet</code>s provided for areas with overlapping highlights.
290
The merging is done in the order defined by <code>ZOrder</code>s of the participating
291
layers, which means that if two layers provide an attribute with the same name
292
then the merged <code>AttributeSet</code> will contain the attribute from the
293
layer, which is placed higher in the z-order hierarchy.
297
There are two important rules for using <code>AttributeSet</code>s, which should
298
be carefully followed by all highlighting layer implementations. Violating these
299
rules may potentialy break the rendering of a document or may cause performance
304
<li><b>Immutability</b> - All instances of <code>AttributeSet</code>s should
305
always be treated as immutable objects. Once you create an <code>AttibuteSet</code>
306
and use it for a highlight you should not modify it. Your modification is
307
most likely to be ignored or can have unpredictable results.
309
<li><b>One instance only</b> - There can be thousands of highlights supplied
310
by layers for one document and a lot of them will be the same (e.g. all
311
keywords in a java document are highlighted with the same color and font).
312
It would be unreasonable to create a new <code>AttributeSet</code> for
313
each of those highlights when all of them would in fact be the same. Instead
314
you should always create one instance of <code>AttributeSet</code> and share
315
it among all highlights that render the same text category (e.g. token or
316
token category, etc.).
321
The <code>AttributeSet</code>s used for highlighting are often created by calling
322
<code><a href="@org-netbeans-modules-editor-settings@/org/netbeans/api/editor/settings/FontColorSettings.html">FontColorSettings</a></code>
323
and it is a responsibility of this class to prevent excesive creation of
324
<code>AttributeSet</code>s it provides. However, if your highlighting layer creates
325
its own <code>AttributeSet</code>s they should always be cached and reused. You can
327
<code><a href="@org-netbeans-modules-editor-settings@/org/netbeans/api/editor/settings/AttributesUtilities.html">AttributesUtilities</a></code>
328
class for creating immutable <code>AttributeSet</code>s.
332
<h3><a name="usecases">Use cases</a></h3>
334
<h4>Use case 1. - Caret selection</h4>
337
The Netbeans editor as any other modern editor allows selecting blocks of text
338
and highlighting them to a user for easier identification. We call this functionality
339
caret selection services and it includes things as simple as marking a block of text
340
that the user selected for copy/paste operation or highlighting a line where
341
the caret is placed to more complex ones such as highlighting occurences of a text
342
that the user search for using the 'Find dialog', etc.
346
This functionality usually only needs to create one highlight and update it
347
depending on the caret movements/selection notified from <code>JTextComponent</code>.
348
The more complex cases may need to create several highlights (e.g. to show the
349
text being searched for). Generally, the highlights are created independently on the
350
text changes in the document itself (e.g. the caret move or searching for a text).
351
However, they have to survive editing the document (e.g. the highlighted occurences
352
of the searched text have to remain highlighted when other parts of the document
357
The caret selection highlights are generally short-lived and have higher importance
358
than other highlights (e.g. syntax or semantic coloring). They usually change
359
the background color to highlight the selection, but also retain as much of
360
a visual appearance of the highlighted text as possible.
363
<h4>Use case 2. - Syntax highlighting</h4>
366
This type of a document coloring shows 'words' or characters in different colors
367
to indicate their meaning in the structure of the text document. This is very
368
popular with highly structured documents such as source code files, scripts,
369
SGML-like documents, etc. It's usually not used for plain text documents containing
370
text in a human language.
374
Syntax highlighting in Netbeans editor is based on a lexical analysis done by
375
lexer plug-ins registered for various types of documents. The lexers are written
376
using the APIs provided by the <a href="http://lexer.netbeans.org">Lexer module</a>.
377
During the lexical analysis text gets split into tokens of different types and
378
categories. Each token type or category can have defined its own coloring information
379
such as font and foreground and background colors, etc. Tokens know their position
380
in text (i.e. offset and length), which information can then be used for creating
385
Decoupling the lexers
386
and making them pluggable lets the syntax highlighting be very flexible. A single
387
layer based on the Lexer API can colorify all sorts of documents providing that
388
there is a lexer registered for each type of a document.
392
Generally a syntax analysis is very fast and syntax highlighting immediately
393
reflects changes done in text. The syntax highlighting layer is usually at
394
the bottom of the hierarchy of highlighting layers.
397
<h4>Use case 3. - Semantic highlighting</h4>
400
In fact semantic coloring regardless of the language it is provided for is
401
very similar to syntax coloring. Words or groups of characters are highlighted
402
depending on their meaning in the text. The difference is in the amount of
403
information that is needed to make this type of coloring meaningful. While with
404
syntax coloring all the information needed is in the text itself in semantic
405
coloring parts of text can be colored depending on information found in a
406
completely different document (e.g. in another source file, library, project, etc.).
410
Semantic highlighting is highly dependent on the type of a document and therefore
411
is usually provided on case-by-case basis and only for the most important types
412
of documents (i.e. those most frequenty used such as java files in Netbeans). Also,
413
semantic coloring is generally not very fast, because of the amount of information
414
that is sometimes needed to gather before a document can be colored. Therefore,
415
while all the effort is made to make semantic coloring reflect text changes as
416
soon as possible, it is generally done asynchronously outside of the documents
417
event model and highlights are created as soon as they are available. The tokens
418
created during the semantic analysis always contain token's position within
419
the text in some form (i.e. either offset or <code>Position</code>). If <code>Position</code>s
420
are available they should be accepted and re-used by the Highlighting SPI.
423
<h4>Use case 4. - Embedded languages</h4>
426
An embedded language is a language of a part of a document that is different
427
than the main language of the document. An example can be a java scriplet in
428
a JSP page or JavaScript in an HTML document. The main language of a JSP page
429
is 'text/x-jsp' and the emebedded language in the case of a java scriplet is
430
'text/x-java'. For the HTML document the main language is 'text/html' and if
431
a JavaScript part is included in the document the 'text/x-javascript' is the
436
The language embedding is supported by Lexer API and therefore there is no
437
problem with supporting it for syntax coloring. For semantic coloring all the
438
work lies on the highlighting layers providing semantic coloring support for
439
a particular language. These layers have to be prepared to provide highlights
440
for parts of a document, which does not contain text in the language they support,
441
but which contains some embedded parts in that language. The Highlighting
442
infrastructure will scan the document for all languages it contains and then
443
it will create appropriate highlighting layers. The layers can be added dynamically
444
as user inserts parts of text in a new language. The layers, however, may not be
445
removed immediately when the last part of text in a language they suppor is removed.
446
Therefore the layers should be prepared to provide no highlights if there is
447
no text they recognize.
450
<h4><a name="usecase5">Use case 5. - Filtering layers used for JTextComponent</a></h4>
453
In certain situations <code>JTextComponent</code> or <code>JEditorPane</code>
454
are used for other purposes than editing. For example debugger may want to show
455
<code>JEditorPane</code> for adding a new watch, where a user could write a piece
456
of java code that should evaluated. This pane should use basically the same layers
457
so that the entered code looks like properly colored and formatted java code.
458
However, it is not desirable to use exactly the same layers as for an ordinary
459
java editor, because some highlightings have a little value in this context or
460
could even be disturbing. There is no point in highlighting the row with the caret,
461
because watches are essentially one-line expressions. There is also a little point
462
in showing text-search related highlights, because hardly anybody will use text
463
search in these simple expressions anyway. On the other hand it makes sense to
464
highlight selected text if user selects some.
468
There can be a whole range of usecases where modules need to show an editor
469
pane, but do not want to use a particular set of highlighting layers, which are
470
registered for the mime type of text that the module is trying to display and
471
which would normally be used for an ordinary editor pane. These usecases are
472
very specific for each module and its way of implementing some features.
476
The editor insfrastructure supports this usecase through allowing modules to
477
set special properties on the editor pane that they want to use for displaying text.
478
The properties are called <code>HighlightsLayerIncludes</code> and <code>HighlightsLayerExcludes</code>.
479
The value of those properties can be <code>String</code> or <code>String []</code>
480
of regular expressions that will be used for finding the matching layers by evaluating
481
each regular expression against the layer's type id. The exact interpretation of those
482
two properties is described below.
487
<code>HighlightsLayerIncludes</code> - Defines the set of layers that
488
<b>will</b> be used for rendering text in an editor pane that defines this property.
489
Every layer, which type Id matches at least one of the regular expressions
490
defined by this property, will be <b>included</b> for rendering. The default value
491
is <code>null</code>, which means that all registered layers will be used.
494
<code>HighlightsLayerExcludes</code> - Defines the set of layers that
495
<b>will not</b> be used for rendering. Every layer, which type Id matches
496
at least one of the regular expressions defined by this property, will be
497
<b>excluded</b> from rendering. The default value is <code>null</code>,
498
which means that no layer will be excluded.
503
The filters defined by those two properties are used in the same order as they
504
were listed above. That is the includes are used first and whatever layers they
505
includ are then filtered by the excludes filter. The result is then used for
506
rendering text in an editor component, which defined those properties.
510
The example below shows how to disable the caret row highlighting layer
511
on <code>JEditorPane</code>.
515
JEditorPane pane = new JEditorPane();
516
pane.putClientProperty(
517
"HighlightsLayerExcludes",
518
"^org\\.netbeans\\.modules\\.editor\\.lib2\\.highlighting\\.CaretRowHighlighting$"
523
<h4>Other usecases</h4>
526
The main usecases described above are certainly not the only usecases of the
527
Highlighting SPI. In general the SPI can be used for binding any type of
528
information to parts of text in a document. While this information should have
529
limited size to keep a good performance of Netbeans editor it can be pretty much
530
anything. Information provided in highlights is currently used only by the editor's
531
drawing engine, which provides a limited set of features useful mostly for
532
rendering text. Some other uses could be for example text annotations, hyperlinking,
533
showing icons in text, etc.