Skip navigation links
org.netbeans.modules.editor.lib2/1 2.30.1 55

Package org.netbeans.spi.editor.typinghooks

The Typing Hooks SPI allows modules to intercept various key typed events handled by the editor infrastructure.

See: Description

Package org.netbeans.spi.editor.typinghooks Description

The Typing Hooks SPI allows modules to intercept various key typed events handled by the editor infrastructure. Historically, this was possible by subclassing editor actions such as DefaultKeyTypedAction or InsertBrakeAction and overwriting their performAction method. This however is not very flexible approach. It's main drawback is that modules can't easily intercept key typed events handled in editors (eg. EditorKits) that are provided by other modules. The Typing Hooks SPI addresses these drawbacks while providing semantically compatible functionality with what used to be possible by subclassing editor actions.

The editor actions superceded by Typing Hooks SPI are still available and the code that uses them should still work. But they will be deprecated and eventually removed.

Keyboard input processing

Netbeans editor panes are ordinary JTextComponents and therefore they fully follow keyboard events processing scheme defined by Swing (please read more about Text Input in JTextComponent's javadoc). For the purpose of understanding Typing Hooks SPI it is important to note that the SPI interceptors are at the very end of the KeyEvent processing pipeline, which means that some KeyEvents may never reach them. However, in a typical environment these events will not present printable characters that could be inserted in an edited document. Typically they are shortcuts bound to special actions in the editor's Keymap (newly a pair of InputMap, ActionMap).

In general the SPI provides several different types of interceptors (interfaces) that clients can implement and register for a document type (mimetype) of their interest. Each interceptor type is meant to process different types of keyboard input. The interceptor types currently available are listed below.

Registering interceptors

Interceptors are created by calling a factory implementation registered in MimeLookup. For example an implementation of TypedTextInterceptor can be plugged in by registering TypedTextInterceptor.Factory instance for the appropriate mimetype in MimeLookup. The snippet below shows how this registration could look.

<folder name="Editors">
  <folder name="text">
    <folder name="x-something">
        <file name="org-some-module-TTIFactory.instance" />

The TTIFactory class will simply return a new instance of the module's implementation of TypedTextInterceptor interface from its createTypedTextInterceptor method.

Interceptors lifecycle

In general interceptors are created as they are needed. However, unlike in other editor SPIs where SPI implementation objects are short lived and get all their information in the form of a context object from the factory that created them, the interceptors are long lived objects that are created with a minimal context and reused many times. The reason for this is mostly performance considerations. Typically there are many keyboard events as users type and their processing has to be as fast as possible.

The interceptors are created for a document type or more precisely for a MimePath of the document fragment, where a user is typing. This allows to call different interceptors depending on where in the document a particular keyboard event happens. Therefore embedded sections can use different interceptors than the main document.

The MimePath is the only context that the interceptor factory gets from the infrastructure and it is the only context that it is supposed to pass to interceptor instances that it creates. All the other information needed for a particular interceptor type to do its job will be provided at the time when an event happens and the interceptor is called to process it. This makes it possible to reuse one interceptor implementation many times for processing different events in different documents.

Threading and synchronization

As explained earlier Netbeans editors follow swing concepts for handling keyboard events. All keyboard events processing and editor actions invocation in swing editors is done in the AWT thread, which means that events are processed in one thread only and in the order as they happened. The same applies for interceptors and Typing Hooks SPI in general.

In particular it is guaranteed that only one interceptor is used at a time and it's always called from AWT thread. Therefore a typical interceptor does not have to use any explicit synchronization code (unless it accesses a resource that can be simultaneously accessed from other threads of course).

However, interceptor types may define a specific protocol, which determines how interceptors of that type are chained, what methods are called first, if and what document locks are acquired prior calling the interceptor, conditions when the event processing can be interrupted, what happens with the rest of the queued interceptors, etc. Please see documentation of each interceptor type interface for detailed information.

Use cases

Use case 1. - Automated indentation

Many languages need to automatically reindent lines as user types certain statements. For example in java language the 'case' statements in a 'switch' block should be aligned to the same column similarly as in the code snippet below. The java editor helps users to do that by automatically indenting the lines that contain 'case' statements as soon as a user types the double colon at the end of the statement.

    switch(price) {
      case 100:
        // do something cheap

      case 1000:
        // do something more expensive

This can easily be done by implementing TypedTextInterceptor and its afterInsert method. The implementation can check the text inserted in the document as a result of the key typed event processing and reindent the line if its text matches required pattern.

Moreover, the Editor Indentation API provides an implementation of TypedTextInterceptor, which reindents lines that match provided regular expressions. Please see AutomatedIndenting class for more details.

Use case 2. - Pair characters completion

It can safe a lot of typing if the editor correctly completes pair characters such as (), {}, "", '', etc. For example when one of the pair character is typed or deleted the editor automatically adds or removes its couterpart. Additionally, the editor may wrap selected text in the pair characters such as quotes "" if one of them is typed (eg. in java producing a string literal).

These features can be implemented by providing specialized TypedTextInterceptor and DeletedTextInterceptor implementations.

Skip navigation links
org.netbeans.modules.editor.lib2/1 2.30.1 55