genjava / articles / jedit plugins

A guide to writing a plugin for JEdit

This document details my quest in adding a plugin to the jEdit IDE one insomniacal night, in May 2001, not long after my move to the USA.

First step

Firstly I had to get jEdit. If you travel to http://www.jedit.org, and download the latest development version of jEdit, you'll have done all the hard work. My particular need was for a linux version, so I'll detail that. I clicked on the linux option on their website, and downloaded the latest jar. At a guess, this jar will run on any jdk1.2 machine. I then ran it to install it. It popped up a nice GUI asking where I wanted to put the files. I realised that my user wouldn't have permission to write to those places, and I dislike using X as root, so I ran the jar again like so: java -jar jedit32pre1install.jar text This time I got a command line interface, it took all of 5 seconds to whizz through, and voila, I was installed. Switching back to my user and typing jedit caused it to load. Congratulations the jEdit people for a lovely install system.

Finding an example plugin

Next I needed to find an example plugin. It happened that I'd already downloaded the JavaStyle plugin for jEdit as a separate zip. You need to do it this way to get the source. The jedit.org site has a list of plugins. If you just want to install the plugin into jEdit, then you can do that through the program. It's a very nice system and as easy as pie, I promise. However, I'd downloaded JavaStyle, so my first problem was, how to manually install the plugin. The website suggested unpacking and doing make install, but being lazy I carried on reading and learnt that if you copy the .jar that arrives with the plugin, then it wil work. The location to copy to in linux is the ~/.jedit/jars/ directory. For other OSes, you should check the website. I quit jedit, started it up again, and lo and behold, I had the JavaStyle plugin. My reason for choosing to use the JavaStyle plugin as an example to learn from was that I'd added the same functionality to the Java Psion Editor and felt pretty comfortable with it.

How to write a plugin

I will spare you the time I spent looking at my example, merely to say that I started with a file called 'JavaStylePlugin.java' in the default package and worked my way down its dependency tree, looking at each file that looked relevant to jEdit. So at the end of that, the classes that are needed to fulfill a minimal (good) plugin are: Plugin class. Represents the Plugin itself. Action class. Called when user clicks on your plugin. property file. Holds your plugin info and label data. documentation html. Link into your documentation. One of the things I've noticed with all the plugins is that they don't have packages, but are in the default package. I don't know if that's bad style or an essential part of the system. For the moment I'm going to emulate it.

A minimal plugin

So. I had before me the wide world of plugins, lots to do and write. Naturally the first all important plugin had to be a Hello World one. Except as a hungry programmer I had it print "Foo'd". My task was to write a program that would replace the text in the currently file with "Foo'd", but only if it was a java source file. Essential I know.

The Plugin Class

// default package
 
import java.util.Vector;
 
import org.gjt.sp.jedit.EBPlugin;
import org.gjt.sp.jedit.GUIUtilities;
import org.gjt.sp.jedit.View;
import org.gjt.sp.jedit.jEdit;
 
public class FoodPlugin extends EBPlugin {
 
    static public void doFood(View view) {
        System.err.println("DO FOOD CALLED");
    }
 
    public void start() {
        // register my Action
        jEdit.addAction( new FoodAction() );
    }
 
 
    // register my menu item in the plugin's menu.
    public void createMenuItems(Vector menuItems) {
        menuItems.addElement(GUIUtilities.loadMenuItem("Food"));
    }
 
}
Things of note in this class: We extend the EBPlugin class. We register an Action. We add a menu under the name 'Food' EBPlugin has no abstract methods, so you don't have to implement any. However the start and createMenuItems methods seem essential if you want to have a working plugin.

The Action class

import java.util.Vector;
import org.gjt.sp.jedit.*;
import org.gjt.sp.jedit.io.VFSManager;
import org.gjt.sp.jedit.gui.OptionsDialog;
import org.gjt.sp.util.Log;
 
public class FoodAction extends EditAction {
 
    public FoodAction() {
        super("Food");
    }
 
    public void invoke(View view) {
        Buffer buffer = view.getBuffer();
        String bufferFilename = buffer.getName();
 
        if (!bufferFilename.toLowerCase().endsWith(".java") &&
            !buffer.getMode().getName().equals("java"))
        {
            GUIUtilities.error(view, "food.error.noJavaBuffer", null);
            return;
        }
 
        // is the current buffer editable?
        if (view != null && !view.getTextArea().isEditable()) {
            GUIUtilities.error(view, "food.error.isNotEditable", null);
            return;
        }
 
        VFSManager.runInAWTThread( new FoodDoit(view) );
 
    }
 
}
Things to note in this class: We supply an invoke(View) method. We get a Buffer from it. We do some checks to see if it's a java source file. If not then we use some errors. We fire off a thread called FoodDoit. FoodDoit is the class that does the actual change. FoodAction could happily have implemented Runnable and contained the run method. My habits make me prefer to keep them separate.

FoodDoit class

Not strictly necessary as I've mentioned.
import org.gjt.sp.jedit.View;
import org.gjt.sp.jedit.textarea.JEditTextArea;
import org.gjt.sp.util.Log;
 
public class FoodDoit implements Runnable {
 
    private View view;
 
    public FoodDoit(View view) {
        this.view = view;
    }
 
    public void run() {
        JEditTextArea textArea = view.getTextArea();
        textArea.setText( "Foo'd" );
    }
 
}  
This class is pretty simple. The only thing of real interest is the run() method. We get the textarea from the view. Then we set text on it. Voila, important java document is gone and replaced with a request for food.

Food.props

Why it is .props and not .properties, I don't know. This property file has two chunks of data in. Data about your plugin for jEdit to use, and data to be used by your plugin. Here's my example:
plugin.FoodPlugin.name=GenerationJava Food Example
plugin.FoodPlugin.author=bayard@generationjava.com
plugin.FoodPlugin.version=0.1.1
plugin.FoodPlugin.docs=Food.html
plugin.FoodPlugin.depend.0=jedit 03.01.03.00

food.error.noJavaBuffer.title=JavaStyle
food.error.noJavaBuffer.message=\
    This is not a Java buffer.\n\
    Make sure the buffer is in Java mode,\n\
    or the filename ends with ".java".
 
food.error.isNotEditable.title=JavaStyle
food.error.isNotEditable.message=\
    Cannot reformat the current buffer, because it is not editable. 
It's easy to tell the two types apart. The ones beginning with plugin are for jEdit, the ones with food are for this particular plugin. The first 4 plugin ones, you can put what you want. The docs property is the file it will show for help. The others it just shows when discussing your plugin. The 5th property says what version of jEdit the user needs. To be honest I've just copied JavaStyle's at the moment. Then we have the plugin specific properies. You'll recognise these as the errors which were thrown out in FoodAction. For each error you send to GUIUtilities.error, you need a title and a message. Note that the backslash allows you to continue using the next line.

action.xml

Don't know yet. I have the following:
<?xml version="1.0"?>
 
<!DOCTYPE ACTIONS SYSTEM "actions.dtd">
 
<ACTIONS>
        <ACTION NAME="Food">
                <CODE>
                        FoodPlugin.doFood(view);
                </CODE>
        </ACTION>
</ACTIONS>  

Compiling

Next I compiled the .java files. jikes *.java works well enough. Make sure you have the jedit.jar in your classpath however.

Installing the new plugin

This worried me. There was no documentation I could find, and no help. So I guessed. First I jarred up all the classes I thought would help. jar -0cf Food.jar *.class actions.xml Food.html Food.props Then I copied the jar into the ~/.jedit/jars/ directory. Started up jEdit and looked at the plugins menu. It was there! Enjoy :)