Fork me on GitHub

Plugins

Note

This guide is a work in progress. If in the process of writing a new plugin you find anything here that is unclear or missing, please don’t hesitate to post to the eclim-dev mailing list with questions, suggestions, etc.

To allow eclim to support different languages, eclim is broken up into eclipse plugins, each of which depend on a corresponding eclipse feature which provides support for that language. When you install or build eclim, it will examine your eclipse install to determine which features are available and will add the corresponding eclim plugins to expose those features. This page documents the core aspects of what goes into the creation of a new eclim plugin.

Bootstrapping the plugin artifacts

Eclim includes a set of templates to help you bootstrap a new plugin. To utilize them you can run the following ant target:

$ ant plugin.create

You will be prompted to enter a name for this plugin along with some guidelines on choosing an appropriate name.

Once you’ve chosen a name, the plugin’s directory structure will be created and populated with bare bones version of the required artifacts. Eclim’s build.xml file will also be updated to include a target to the new plugin’s unit test target.

Updating the initial artifacts

After you’ve bootstrapped your plugin, you can now start updating the generated artifacts:

build_<plugin_name>.gant

The first file you’ll need to modify is a gant file for your plugin. The main eclim build.gant script will load this file during the build process to determine what the plugin’s eclipse dependency is, so it knows whether it can be built against the target eclipse install. So the first thing we need to do is to fill in that information by updating the feature_<plugin_name> variable with the name of the eclipse feature that this plugin depends on. For example, the eclim jdt plugin has this set to 'org.eclipse.jdt'. The build script will look in the features directory of your eclipse install (including the dropins and your user local eclipse dir if set), to find this feature, so the value you set, must be found in one of those locations (the version suffixes will be removed from the features in order to match it against the value you’ve set).

You’ll also notice that there is a unit test target in the gant file. You can ignore that for now.

META-INF/MANIFEST.MF

The next file to note is the plugin’s META-INF/MANIFEST.MF. This is the file that eclipse will use to determine how to load the bundle and what to include in its classpath. The only part of this file that you should edit is the Require-Bundle: section. This is a comma separated list of bundles (or plugins) which this bundle depends on. When this bundle is loaded only those bundles listed here will be available in the classpath. So when you start running commands you’ve written later, if you receive a ClassNotFoundException, that is likely due to the bundle containing that class not being listed in your plugin’s Require-Bundle: list. At this point you probably don’t know yet what bundles you need to add to this list. When you start writing commands for your plugin, you’ll have to find out which bundles contain the classes imported from the eclipse plugin you are integrating with, and you’ll need to add those bundles accordingly.

It’s also worth noting that eclim provides a custom classpath container which scans the manifest of each eclim plugin and loads the required bundles of each into the classpath. So when adding new bundles, if you want validation, search, code completion, etc to work with classes from those new bundles, you’ll have to restart the eclim daemon. While restarting can be annoying, this is generally better than having to add/remove entries from the .classpath file or worrying about one user having different bundle version numbers from another.

PluginResources.java

At this point you’ll typically need to start customizing your plugin’s org.eclim.<name>/java/org/eclim/plugin/<name>/PluginResources.java file. Here is where you will map a short alias to the project nature, or natures, of the plugin you are integrating with, register a project manager for initializing project’s for this plugin, register any plugin settings that users can configure, etc. You’ll be doing all this inside of the initialize method which has been generated for you.

Project Nature

You’ll first need to find out where the plugin’s nature id is defined. Here are some examples that should give you an idea of where to look:

  • jdt: org.eclipse.jdt.core.JavaCore.NATURE_ID

One way to find it is to open up the .project file in a project containing the nature, locate the fully qualified name in the <natures> section, then grep the plugin’s code for that name.

Once you have the reference to the nature id, you can then create a public static variable called NATURE:

public static final String NATURE = SomeClass.NATURE_ID;

You’ll be using this constant as the key to register features for project containing this nature, but first we’ll register a short alias for this nature since the actual nature id tends to be long and unstandardized, and we don’t want users to have to type it out when creating projects from eclim:

ProjectNatureFactory.addNature("shortname", NATURE);

Project Manager

The next thing you’ll probably need to do is to create a project manager for your project (org.eclim.<name>/java/org/eclim/plugin/<name>/project/SomeProjectManager.java). The project manager is responsible for performing any post create, update, delete, or refresh logic required for projects of this nature. This logic can include things such as creating an initial classpath/buildpath, validate the classpath/buildpath on update, forcing a full update of the search index on refresh, or any number of other things.

Overriding the create method will almost certainly be necessary, but the logic you’ll need here varies widely. Finding what you’ll need is a matter of digging through the parent plugin’s source code, typically looking for the project creation wizard class, to see what it does to create a project of this nature and later comparing the created artifacts from your code against those of a project created from the eclipse gui. This can be a difficult hurdle to get past for someone doing this the first time, so please don’t be shy about asking for help on the eclim-dev mailing list.

Eclim does provide a couple ant tasks to at least help you to quickly extract any docs and source code found in your eclipse install:

  • eclipse.doc: This target will extract any doc jars from your eclipse install to a ‘doc’ directory in your eclipse home (or user local eclipse home).

  • eclipse.src: This target will extract any src jars from your eclipse install to a ‘src’ directory in your eclipse home (or user local eclipse home). If you download the sdk version of eclipse then the jdt and all the core eclipse source will be available. Some other plugins provide sdk versions which include the source code and this target can extract those as well, but some plugins don’t seem to have this option when installing via eclipse’s update manager (and may not include the source when installed from a system package manager). For those you can often download a zip version of their update site which should include source bundles. Once you’ve extracted that file, you can tell this target to extract source bundles from a specified directory. Here is an example of extracting the source from an unpacked dltk update site:

    $ ant -Dsrc.dir=/home/ervandew/downloads/dltk-core-5.0.0/plugins eclipse.src
    

Once you’ve created your project manager, you then map it to your plugin’s nature inside of your PluginResources.initialize method like so:

ProjectManagement.addProjectManager(NATURE, new SomeProjectManager());

Project Settings

At this point you should have the minimum of what is needed for a new plugin. Hopefully you can now create new projects with your plugin’s defined nature. The next step would be to start adding commands to provide validation, code completion, etc. The remaining items in this list are not required to continue. They provide you with the ability to setup your own preferences or to expose the parent plugin’s defined preferences inside of vim. When you’ve come to the point that you need to work with preferences, then feel free to come back here and continue reading.

To Be Continued…