Go to content Go to navigation Go to search

A simple Eclipse editor plug-in - just-one-space

There are a few editor commands I use frequently in Emacs that have no equivalent in Eclipse. The first is just-one-space (M-space). All spaces and tabs surrounding the cursor are replaced with a single space. This is great for joining two lines and removing all the extra indentation space that comes along. I also miss open-line (C-o). This moves the remainder of the current line to the next line, leaving the cursor where it is.

I decided to put in the effort to write my first Eclipse plug-in to do the equivalent of just-one-space. The Eclipse API is massive, and working my way through the different interfaces and plug-in definition files definitely took some time. I was almost scared off by an article in the Eclipse wiki when I read

...Text editors have no public API to insert text… Therefore, inserting text in the currently active editor is not trivial.

hmmm. In the end it turned out to be very doable and worth learning.

Eclipse is built around the the concept of extension points, hooks throughout the system that can be extended by plug-ins. Plug-ins in turn can define more extension points that can be extended. The platform core itself manages plug-ins and extensions and provides basic runtime services. The IDE is written as a set of plug-ins around the core.

To add actions to the editor, a plug-in needs to extend the org.eclipse.ui.editorActions extension point. These plug-ins can add menu items and named actions that are available to the desired editors. The action itself is a class that implements IEditorActionDelegate. This interface has two methods – one to specify the editor where the action was invoked (setActiveEditor) and another, run, that is called when the action is triggered by a key press, button press, or menu item selection.

The action I wanted to perform (just-one-space) was to search back from the cursor for the first non-space, then forward for the next non-space, replacing the range with a single space character. The cursor also had to be positioned correctly after the modifications were made.

First you need to get from the IEditorPart interface passed into the action to an ITextEditor (the base of most text based editors) and an IDocument (the interface representing the text itself).

      ITextEditor editor = (ITextEditortargetEditor;
      IDocumentProvider dp = editor.getDocumentProvider();
      IDocument doc = dp.getDocument(editor.getEditorInput());

Next, figure out the current offset of the cursor within the document:

      ISelectionProvider selProvider = editor.getSelectionProvider();
      ITextSelection selection = (ITextSelectionselProvider.getSelection();
  
      // current offset
      int offset = selection.getOffset();

Now, the main function of the code – find the beginning and end of the spaces and tabs around the current offset. (It’s definitely possible there’s a easier way that I don’t know to do this with the IDocument).

      // find the first space behind the cursor on this line 
      int startSpace = offset - 1;
      while (startSpace >= 0) {
        char ch = doc.getChar(startSpace);
        if (ch != ' ' && ch != '\t'break;
        --startSpace;
      }
      // currently pointing to a non-space character.
      // adjust to point to the space
      ++startSpace;

      // find the last space after the cursor
      int endSpace = offset;
      int end = doc.getLength();
      while (endSpace < end) {
        char ch = doc.getChar(endSpace);
        if (ch != ' ' && ch != '\t'break;
        ++endSpace;
      }

Now that the run of spaces has been found, replace them with a single space, and position the cursor correctly – after the new space.

      // replace with a single space
      doc.replace(startSpace, endSpace - startSpace, " ");

      // move to the beginning of the space, plus one
      // (past the space inserted)
      editor.selectAndReveal(startSpace + 10);

The Eclipse plug-in development environment makes the edit-test cycle easy enough. To debug the plug-in, Eclipse launches a copy of itself, configured to use the plug-in. You execute the action through the debugger, modify code in place while it’s running, then exit the cloned Eclipse and make another iteration.

I’ve just scratched the surface and need to try some of the different extension points. At some point I’ll package up the just-one-space implementation and publish the project.

  Textile Help