Extending TagSEA

TagSEA was not implemented merely as a tool to support source code tagging in Java. It was designed as an extensible framework for creating tags within your working environment. Exemplary extensions have been created for tagging Java source, web pages, resources, and tasks.

Still, TagSEA was created for software developers concerned with being able to find source code. So, new with version 0.6.6, there are some features that make it easy for you to extend TagSEA to support the reading of standard-formatted waypoints from almost any source language.

Standard Waypoint Syntax

From the early days of TagSEA, when only Java was supported, a standard syntax was defined as:

//@tag tag-names meta-data : message

Where tag-names is a white-space-separated list of tag names to be applied in the code, meta-data is a white-space-separated list of meta data to be applied in the code, and message is a display message for the waypoint in the code.

Tag names can be single words, or they can be part of a hierarchy. Hierarchies are defined by dot-separation between the tag words. For example:

//@tag hack bug.1234

Will create a waypoint that has the tags hack and bug.1234 where 1234 is considered a sub-tag of bug.

There are two types of meta-data that can be applied: names and dates. Where a name can be specified by -name="name" and a date can be specified by -date="date-code". The date-code is a locale-specific date of the format languageCOUNTRY:date. For example, we can add an author and a date to the previous waypoint:

//@tag hack bug.1234 -author="Joe Shmidt" -date="enCA:01/01/01"

This would create a waypoint with an author of Joe Shmidt, and a date of January first, 2001 in English speaking Canada.

Contributing a Standard Parsed Waypoint

This standard format for parsed waypoints makes it easy to imagine the usage of parsed waypoints in many other languages besides Java. Since programming languages are just in plain text, and the text that we are considering is standard, the same parsers can be used to discover waypoints for all different languages. The only missing part of the puzzle is how to discover the areas of text that contain valid waypoints. Since waypoints can't be a part of the proper program, the natural place to put them is in comments. So, an extension point has been defined to allow extenders to contribute their own standard parsed waypoints.

Let's consider the Perl programming language. There are really only two pieces of information that we need to know about Perl: the standard file names that are used to define a Perl program; and the way that comments are defined in Perl.

In Eclipse, there is a way to define content types associated with files. For example, the JDT defines a content type for files that represent java programs. For this example, though, we don't want to depend on any third-party Perl IDE plugins, so we will just use the file extensions for Perl programs. These file extensions are .pl and .pm.

As for defining how the parser finds comments, there are two steps. First, we must tell the plugin what characters to look for. For Perl, this is straight-forward because Perl only has single-line comments. The begin with a hash (#) symbol. But we have to be careful. There are certain cases when we don't want the hash-symbol to be considered as a comment. For example, within strings or regex's. Otherwise, a piece of code such as:

print "#1 : the first number\n";

would be considered a comment. In order to deal with these situations, TagSEA provides an "exclusion" mechanism. We will define areas within quote-like characters (' and ") as areas to be excluded. We also want to ignore regex areas. Perl complicates this by allowing the regex syntax to be changed dynamically. Since we can't anticipate all possible scenarios, we will simplify the problem by just excluding areas between the standard '/' characters. The final plugin XML code looks like this:


<extension
    point="net.sourceforge.tagsea.parsed.standardComment">
    <definition
            fileAssociations="*.pl,*.pm"
            kind="net.sourceforge.tagse.parsed.perl.waypoint"
            name="Parsed Per Waypoints">
         <singleline
               open="#">
         </singleline>
         <exclusion
               close="'"
               open="'">
         </exclusion>
         <exclusion
               close="&quot;"
               open="&quot;">
         </exclusion>
         <exclusion
               close="/"
               open="/">
         </exclusion>
    </definition>
</extension>

And that's it. That is all you have to do. The TagSEA platform will automatically create the parsers, the markers, the icons, and the refactoring support for you. Now, you are ready to start using waypoints inside your Perl code.

Tweeking the contribution

Though everything you need is now available, and you are ready to start using waypoints in your Perl code, it might be nice to tweek it a little. For example, it would be nice to have a way of making sure that Perl waypoints are distinguishable in the TagSEA ui. There is a simple interface for this called IParsedWaypointPresentation. It offers a number of methods which provide images and labels for your parsed waypoint.

For now, we are only interested in decorating an image to indicate that the waypoint is in a Perl file. The standard image for Perl is a camel . So we'll use that. TagSEA also offers some decorations for images to indicate that an image is a waypoint, and that it is parsed. We'll use those as well to decorate our image. The methods of interest in our implementation are getImage(IWaypoint) and getImage(). They look like this:

public Image getImage(IWaypoint waypoint) {
    return getImage();
}
public Image getImage() {
    ImageRegistry registry = PerlWaypointPlugin.getDefault().getImageRegistry();
    Image image = registry.get("PERL_WAYPOINT_IMAGE");
    if (image == null) {
        //construct the image from various adornments.
        Image base = registry.get("PERL_ICON");
        ImageDescriptor overlay = 
            TagSEAPlugin.
                getDefault().
                getImageRegistry().
                getDescriptor(ITagSEAImageConstants.IMG_WAYPOINT_OVERLAY);
        ImageDescriptor overlay2 = 
            ParsedWaypointPlugin.
                getDefault().
                getImageRegistry().
                getDescriptor(IParsedWaypointImageConstants.PARSE_OVERLAY);
        DecorationOverlayIcon icon = 
            new DecorationOverlayIcon(
                base, new ImageDescriptor[] {
                    overlay,  null, null, overlay2, null
                }
            );
        registry.put("PERL_WAYPOINT_IMAGE", icon);
        image = registry.get("PERL_WAYPOINT_IMAGE");
    }
    return image;
}

This assumes that our plugin object has an icon called "PERL_ICON" in its image registry. That icon is the camel image.

Finally, we have to tell the plugin that the new waypoint kind has a presentation associated with it. This is done through the "presentation" attribute in the plugin xml. The final XML looks like this:

<extension
    point="net.sourceforge.tagsea.parsed.standardComment">
    <definition
            fileAssociations="*.pl,*.pm"
            kind="net.sourceforge.tagse.parsed.perl.waypoint"
            name="Parsed Per Waypoints",
            presentation="net.sourceforge.tagsea.parsed.perl.PerlWaypointPresentation">
         <singleline
               open="#">
         </singleline>
         <exclusion
               close="'"
               open="'">
         </exclusion>
         <exclusion
               close="&quot;"
               open="&quot;">
         </exclusion>
         <exclusion
               close="/"
               open="/">
         </exclusion>
    </definition>
</extension>

More Control

It is possible to create all kinds of different waypoints that don't necessarily follow the standard syntax, though it is normally better to follow a standard way of writing waypoints. Nonetheless, another extension point-- net.sourceforge.tagsea.parsed.parsedWaypoint exists for this purpose. It allows you to define your own parsers and refactoring support. See the extension point documentation, and the example project net.sourceforge.tagsea.parsed.javabang for an example. The "javabang" plugin allows you to add tags in a much more light-weight manner: by simply placing a back-tick (`) character in front of the word that you want to be a tag. For example:

//this code is a `hack

The above will create a waypoint with the tag hack applied to it, and a message of this code is a hack. Other metadata is not supported by this kind of waypoint.

Note also that parsed waypoint kinds are not allowed to overlap in a file. If you have both Java waypoints and "Simple Java" waypoints installed, the following code will cause a conflict:

//@tag `hack : this code is a hack

Because the word `hack is recognized by both parsers.

It is possible to create waypoints for more than just source code, as well. TagSEA comes with several different types of waypoints for waypointing on arbitrary resources, Java Task Tags, breakpoints, and URLs. These all use the net.sourceforge.tagsea.waypoint extension point. Using this extension point, you can create a new Waypoint Delegate. Waypoint delegates are responsible for the full lifecycle of waypoints, from their creation to their death. They are also responsible for reacting to changes to waypoints, and allowing/dissallowing those changes. The following plugins make use of the net.sourceforge.tagsea.waypoint extension point:

net.sourceforge.tagsea.url
net.sourceforge.tagsea.parsed
net.sourceforge.tagsea.tasks
net.sourceforge.tagsea.resources
net.sourceforge.tagsea.breakpoint