Markers and Annotations in Eclipse for Error Feedback

Motto:

Ninety per cent of most magic merely consists of knowing one extra fact.
Terry Pratchett, Night Watch

Development in Eclipse keeps fascinating me, as there are a lot of very thoroughly designed services and features integrated to allow detailed customization – on the other hand, “with big power comes big responsibility”, but at least a steep learning curve. I had such an experience with the problem handling support not long ago.

We developed our own textual language, that provided error markers and editor annotations as error feedback. The problem was that the editor annotations were sometimes missing: our planned functionality worked like we like to add an annotation each time our marker was added, but the annotations were not always updated (so we got an inconsistent state between markers and annotations – but not every time).

Of course that was caused by the fact that we were rolling out our own implementation of marker/annotation synchronization – we were not aware that the JFace TextEditor provides such a service out of the box – and I did not found it documented on the various locations (that’s why this blog post is born 🙂 ).

Our requirements

First of all, lets assemble the various ways Eclipse editors can provide error feedback:

  • The most basic (and least usable) way is the use of pop-up windows – they are annoying, and not persistent (after pressing a button, they disappear, before the error could be solved).
  • Writing to the Error log view – a bit better, but the log could be overwhelmed, if the messages are too many, because they cannot be deleted when the problem is solved.
  • Displaying the error in the Problems view – that’s one of the standard places, where parse errors should be displayed. The problems view is generated by reading (and filtering) the error marker type (org.eclipse.core.resources.problemmarker).
  • Marking the files in the Project Navigator view with a small symbol, if they contain errors/warnings. This is also handled using the previously mentioned error marker.
  • Underlining the erroneous parts in the editor. For this reason annotations should be added to the JFace Document Model used by the JFace TextEditor component.

The basic idea is to create a marker and an annotation each time a problem is found. The problem with annotations, that creating them requires some connection with the editor object, or at least the document model, but our parser should not depend on the editor (core component should not depend on the GUI!).

Mark My Words!

The management of the markers is well described in the Mark My Words tutorial. Basically markers are attached to IResources, and provide a simple key-value interface with a freely definable key set (and the IMarker interface specifies some commonly used keys).

Following the tutorial we could create our own marker with the parent of the org.eclipse.core.resources.marker marker, after this adding the markers to the selected files managed the error display in the Problems and Project Navigator views.

So our marker definition looks as follows:

   <extension
         id="vtclparsermarker"
         name="VTCL Parsing Problems"
         point="org.eclipse.core.resources.markers">
      <super
            type="org.eclipse.core.resources.problemmarker">
      </super>
      <persistent
            value="true">
      </persistent>
   </extension>

The problem marker understands severity, error message and line number parameters, and is capable of displaying them in the Problems view.

IMarker marker = file.createMarker(markerId);
 marker.setAttribute(IMarker.SEVERITY, severity);
 marker.setAttribute(IMarker.MESSAGE, message);
 marker.setAttribute(IMarker.LINE_NUMBER, line);

Annotating the document manually

As stated before, markers could be added easily without knowing anything about who has opened the file currently, so they are really useful for error feedback, but this information should be also available in the open editors.

Our first idea may be to create some glue code, that listens to the marker changes, and updates our editor accordingly. The drawbacks of this approach are first the fact that we have to code something that trivial, and the second (as we saw in our project), that the editor update could be quite tricky (missing or not deleted annotations).

My theory is, that we have encountered some kind of race condition with our naive implementation, as the annotation creation code was always executed, but sometimes the results were lost. So, in the end, this listener is not so trivial. 🙁

Automatic annotation display

This was the part that gave us the most headache – we did not understand, what caused the inconsistent display problem. On the other hand, knowing one extra fact (“magic”) the problem is trivially solvable.

So, here comes the Eclipse magic: we don’t have to create this service manually, we should reuse the already existing one. For that, we would need that our marker also become a child marker of the org.eclipse.core.resources.textmarker, and a minimal set of position data should be added to the marker.

This position information is described by the start and end offset value – instead of the human-readable line/column position information a machine-readable single position is used: the number of characters that has to be read from the start of the string stream. Its lucky, that most parser generators provide such output that this information is trivially available from the AST level

   <extension
         id="vtclparsermarker"
         name="VTCL Parsing Problems"
         point="org.eclipse.core.resources.markers">
      <super
            type="org.eclipse.core.resources.problemmarker">
      </super>
      <persistent
            value="true">
      </persistent>
      <super
            type="org.eclipse.core.resources.textmarker">
      </super>
   </extension>

And the marker creator Java code looks as follows:

IMarker marker = file.createMarker(markerId);
marker.setAttribute(IMarker.SEVERITY, severity);
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.LINE_NUMBER, line);
if (pos.offset != 0) {
  marker.setAttribute(IMarker.CHAR_START,pos.offset);
  marker.setAttribute(IMarker.CHAR_END,pos.offset+pos.length);
}

After that, the platform uses a default implementation, that provides the well-known wriggly underline to annotate our text files with the associated markers.

Summary

Altogether, the following steps are needed to provide a simple error reporting for our existing editor:

  • Create a custom marker type
    • With a supertype of org.eclipse.core.resources.problemmarker to display the report in the problems view
    • With a supertype of org.eclipse.core.resources.textmarker to underline the errors in the textual editor
  • Create a marker instance
    • Setting the IMarker.SEVERITY, IMarker.MESSAGE and IMarker.LINE_NUMBER attributes for the Problems view.
    • Setting the IMarker.CHAR_START and IMarker.CHAR_END for the editor annotations.

Conclusion

The Eclipse text editors provide a well-defined, easy to use error reporting mechanism nearly for free. The main catch is, we have to be careful to set everything – if something is missing, we got the silent failure issue – no exception is thrown, but something is not shown.

The biggest issue in our implementation was that the IMarker.CHAR_START and IMarker.CHAR_END marker attributes are ignored, if the used marker is not a text attribute, making this problem hard to identify.

A fine thing with this error reporting mechanism is, that it is independent of the concrete text editor used: when we changed our implementation in the VIATRA framework, the resulting reports were visible in every text editor (e.g. the dedicated VIATRA text editor, or the default text editor in Eclipse) – thus helping error recovery.

Presentation theme for Eclipse

In the last year I often had to held live presentations of Eclipse development. At that point a typical problem is, that the font sizes used during development are too small for the projector.

The possible solutions are either ignoring this fact, using a special environment, where all the appropriate settings have been made, or tweaking the development environment. The tweaking will not work, as several settings should be made, and they are easy to forget, while the special presentation environment seems too much of a hassle for me. This left as the only choice to ignore the fact.

But finally I had some hacking time, so I created a Presentation theme for Eclipse, that solves tweaking by a single selection of the user interface: Themes can be selected in the General/Appearance tab on the Preferences page.

The Presentation theme can be selected=

Currently, the theme description is a bit hacky: for every platform the default font is copied by hand to the plugin.xml (using a Windows 7, a OpenSuse 11.3 Linux and a Snow Leopard machine). More research is needed to solve this in a more generic way. Luckily only four fonts have been redefined by the theme.

Some things missing: support for resizing elements in JFace viewers (such as EMF tree editors or CNF views), and the theme was not tested with graphical editors – although they can be resized using the Zoom control.

Finally, an early alpha version can be downloaded from our update site: http://eclipse.cubussapiens.hu

I’m looking for some feedback, or either alternative implementation ideas; I think, others have already met these problems.

The source is available from GitHub.

Update: before/after screenshots below.

The default theme on OSX uses small fonts
Before: The default theme
The Presentation theme uses increased font sizes
After: Presentation theme

New features in the Debug Visualisation plug-in

After a month, some bugs from the Debug Visualisation version 0.8.0 have been fixed. Most notably, the incorrect trimming of long titles, and a case, where arcs were incorrectly removed from the graph.

Two minor new features were also introduced: it is possible to turn off name trimming, and the values of variables is now displayed as a hover.

I created a screencast to show these new features (and also some other, as the last screencast was created over a year ago.

(If the embedded video does not show in your feed reader, you can watch it on YouTube.)

Ecore model analysis for the win

Today I tried to edit an Ecore/Generator model used in the VIATRA2 framework, but the system greated me with an error screen stating, there are 4 errors in the selected Genmodel.

Four validation errors at the opening of the genmodel

The error messages were a little bit cryptic (but all similar in nature): A containment reference of a type with a container feature platform:/resource/org.eclipse.viatra2.gtasm.model/model/gtasmmodel.ecore#//gtasm/metamodel/gt/GTPattern/namespace that requires instances to be contained elsewhere cannot be populated.

This was scary, as I don’t remember any new core features in EMF 2.6, that suggest such changes. My second guess was a misedited model, but after checking, that I have the same models as half year ago, this proved wrong. Even worse, these errors did not appear in either the Problems or Error log view. Checking the items mentioned in the error messages did not help, as the model elements looked “innocent enough” not to question their content.

It was only know when I saw that these errors are shown in a new, problem page in the editor (I often miss the editor pages option – except on form-based editors), and on the other page the tree is displayed, and code generation seemed also working.

At this point I looked on the internet for similar problems, and found a thread about the issue in the EMF newsgroup. The main idea was Ed Merks’s comment:

The point is supposed to be that you can’t be contained by more than one container, so you can’t have a container references that’s required as well as any other containment reference that’s not the opposite of that required container. I.e., a required container prevents other containment references from ever being populated.

Using this information I finally understood, what the error message meant, and begin looking for the cause in the Ecore model. After some searching (the error message only mentioned one model element from the three actors, and it is hard to get an overview of the inter modelelement relations in an EMF tree editor), I finally found the mentioned elements, that looked quite innocent at first – just take a look at the included graphical representation.

An Ecore diagram to illustrate the found model validation error
Illustration of the found problem

We have a machine, that contains both patterns and rules, while rules may contain addition pattern definitions (named local pattern definitions). On the other hand, patterns and rules have a backreference to the  machine (namespace). As we wanted to have the Machine reference available for local patterns, the pattern references exactly one machine.

The drawback of the solution is, that the machine reference is the inverse of the containment relation, so every pattern has to be contained in a machine. On the other hand, EMF requires that every EObject (not EClass) must have exactly one incoming containment reference for serialization, so it is not possible for a rule to be the container of a pattern – hence the error message.

This analysis is extremely useful: it shows, that our metamodel prevents having serializable models in some cases, which comes in handy (I wouldn’t like to be the one, who has to debug such an error after a runtime exception is caught…). The fix is not really straightforward, as this model is already used (interesting fact, that the issue has not been produced in runtime – this means, we don’t have 100% test coverage :)), but by having a map to the error it is easier to fix.

I’d like to thank for the EMF team for this fine analysis solution, but some minor additions: don’t add warnings to a new page, use the existing reporting options; and try to rephrase the message for it to become more understandable.

Update sites in the P2 era

Lately I have built several update sites during Eclipse development – e.g. for the last release of the Debug Visualisation plugin, or some related to VIATRA2 based articles (maybe more details later). They have all one thing in common: they were not created using Update site projects.

In my experience since P2 came as a provisining platform the Update site projects were not the best available solutions: at first (in Ganymede) they did not produce everything P2 needed, while produced legacy information, that triggered a backward compatible mode in the provisining platform (officially the old Update managers site.xml should not be used). Even worse, I experienced some serious errors, when trying to add a new version of the already added plug-ins to the already built update site – in most cases the category definitions were removed (as in Galileo by default all features without category are hidden, this problem is quite serious).

On the other hand, not too long ago classic update sites were also needed to provide update sites for both the Update manager and P2. Today the Update Manager compatibility is not as crucial, as all Eclipse versions supported by eclipse.org use P2, so it is better to use some dedicated P2-based mechanism for Update site creation.

This mechanism is present since Eclipse 3.4 (at least from the command line, as documented in the Eclipse wiki), but is a bit hard to use. Recently I found a somewhat hidden option in the GUI, that provides the P2 metadata generation functionality – just as needed.

To use this, at least one (or possibly more) features are needed – the features are the minimum installable units. When the features are ready and the related plug-ins are attached, the Export wizard has to be invoked with the Deployable Features wizard from the Plug-in Development category.

The deployable features and the destination should be selected as needed (in my experience the directory export makes possible the easiest update site deployment, while the zipped archive allows the easiest direct transport – e.g. for dropins).

The export deployable features wizard in action
Export deployable features wizard

The P2-related magic should be initiated on the Options page: if the Generate metadata repository option is selected, as in the screenshot, during the export all metadata needed by P2 is generated.

For categorization of the repository a specific xml-file should be created: by creating a Category Definition from the New… wizard a simple form-based editor can be used to define categories for the installer, that can also be selected using the Export wizard.

Some additional tips and tricks related to the deployment:

  • To update existing P2-based update sites, simply point the export destination to the already existing update site. This updates the existing update site – I only tried this using the directory-based output.
  • To avoid runtime issues, make sure that the exported plug-in projects use the needed Java version compatibility in the project settings (e.g. if the manifest requires Java 1.5, make sure the project gets compiled in Java 1.5 compatibility mode), as the plug-ins are recompiled using these settings. I managed to get a Java 1.5 compatible project compiled with Java 1.6 compliance settings – the plug-ins even got installed, but did not work in the target computer, instead a hard to debug runtime exception is thrown.
  • It is possible to add source boundles by selecting the appropriate checkbox. On the other hand I couldn’t find a way to set the display name of the generated source bundles, and they are shown with the same name as the non-source plug-in, making it hard to distinguish between them during runtime. If you know the solution, please let me know.

In general, this export mechanism works well, without any major issues, I tested in repeatedly with several update sites. Unless for some reason Update manager compatibility is needed, I don’t recommend using Update site projects anymore – simply export your features to deploy.