Showing posts with label jEdit. Show all posts
Showing posts with label jEdit. Show all posts

Friday, August 28, 2015

Getting rid of the Java beep

This has been quite an adventure. I didn't think that something as simple-sounding as adding an option to jEdit to turn off the beeping noise that some of the components make would be a big deal. I thought it would be something along the lines of adding a utility method that checked a property to see if the beep should happen or not, then change all the beep calls to use this new utility method. Not even close to the right solution. The problem with this approach is that many of the JVM provided Swing components also beep and, of course, those components would have no idea about my utility method.
After some research on the internet and perusing the Swing source code, the right way to cause a component to beep is to use the look and feel to provide error feedback to the user. In fact, that is the exact method in the look and feel to use: provideErrorFeedback. By default, this method simply calls Toolkit.beep(). Here is the complete method as implemented in Java 1.8:

    /**
     * Invoked when the user attempts an invalid operation,
     * such as pasting into an uneditable <code>JTextField</code>
     * that has focus. The default implementation beeps. Subclasses
     * that wish different behavior should override this and provide
     * the additional feedback.
     *
     * @param component the <code>Component</code> the error occurred in,
     *                  may be <code>null</code>
     *                  indicating the error condition is not directly
     *                  associated with a <code>Component</code>
     * @since 1.4
     */
    public void provideErrorFeedback(Component component) {
        Toolkit toolkit = null;
        if (component != null) {
            toolkit = component.getToolkit();
        } else {
            toolkit = Toolkit.getDefaultToolkit();
        }
        toolkit.beep();
    } // provideErrorFeedback()

I grepped the Swing source code, and no component calls Toolkit.beep() directly. The only call to Toolkit.beep() is in the provideErrorFeedback method. So this leads me to believe that the proper way to implement a beep is via the look and feel rather than calling Toolkit.beep() directly. My next thought was to use one of the byte code manipulation libraries like BCEL or Javaassist in the LookAndFeel plugin to change the method to look like this:
 public void provideErrorFeedback(Component component) {
     if (!"true".equals(System.getProperty("allowBeep")))
         return;
     Toolkit toolkit = null;
     if (component != null) {
         toolkit = component.getToolkit();
     } else {
         toolkit = Toolkit.getDefaultToolkit();
     }
     toolkit.beep();
 } // provideErrorFeedback()

That seemed pretty straightforward, so I wrote a class loader for the LookAndFeel plugin that would insert the line or the whole method. This worked well, until I realized that this will only work for a look and feel loaded through the LookAndFeel plugin, not any of the Swing look and feels. I know many people are satisfied with Metal or Nimbus, and this approach wouldn't work for those. I did go ahead and give it a go anyway, adjusting the LookAndFeel plugin to let the user select the built-in look and feels and attempt to patch them on the fly, but the JVM security manager wouldn't allow it.
A note about the byte code manipulation libraries, I ended up using Javassist as it is easier to work with. BCEL is fine, but works at a lower level and has a fairly steep learning curve.
My last approach, and the most successful, is to use the Java instrumentation API and use that to patch javax.swing.LookAndFeel directly. This works well since every look and feel that I have the source code to does not override the provideErrorFeedback method in that class, so it's the single place where all look and feels, and thus all components, go to make a beep. The downside of this is the code must kick in at JVM start up time, which means it can't be in a regular jEdit plugin, since those don't get loaded until well after the JVM classes.
Using the instrumentation API is really simple. All that is needed is a Java agent. The one I wrote looks like this:

package javassist;

import java.io.*;
import java.lang.instrument.*;
import java.security.ProtectionDomain;

/**
 * Simple java agent to fix the <code>provideErrorFeedback</code> in javax.swing.LookAndFeel.
 * This adds a line to that method to check the System property "allowBeep" before it 
 * proceeds with beeping. If "allowBeep" is anything other than "true", the method returns
 * immediately without providing any error feedback.
 */
public final class LNFAgent implements ClassFileTransformer {

    private static final String CLASS_TO_PATCH = "javax/swing/LookAndFeel";

    public static void premain( String agentArgument, final Instrumentation instrumentation ) {
        LNFAgent agent = null;

        try {
            agent = new LNFAgent();
        } catch ( Exception e ) {
            System.out.println("LNFAgent not installed.");
            return;
        }
        instrumentation.addTransformer( agent );
        System.setProperty("LNFAgentInstalled", "true");
    }

    @Override
    public byte[] transform( final ClassLoader loader, String className, final Class classBeingRedefined, final ProtectionDomain protectionDomain, final byte[] classfileBuffer ) throws IllegalClassFormatException {
        byte[] result = null;

        if ( className.equals( CLASS_TO_PATCH ) ) {
            try {
                CtClass ctClass = ClassPool.getDefault().makeClass( new DataInputStream( new ByteArrayInputStream( classfileBuffer ) ) );
                CtMethod ctMethod = ctClass.getDeclaredMethod( "provideErrorFeedback" );
                ctMethod.insertBefore( "if (!\"true\".equals(System.getProperty(\"allowBeep\"))) return;" );
                result = ctClass.toBytecode();
            } catch ( Exception e ) {
                System.err.println("Unable to patch javax.swing.LookAndFeel to disable beeps.");
            }
        }
        return result;
    }
}
Here's a quick run through of this code:
  • First, I put this code in the javassist package. My thought is to go ahead and make a plugin out of Javassist anyway, and insert this agent into the Javassist jar file.
  • The premain method is the method required by the instrumentation API. This method gets called on JVM start up and initializes the agent. For this purpose. I'm setting a System property to indicate that the agent has been installed so that my LookAndFeel plugin can know.
  • The transform method is where the actual code gets inserted into the provideErrorFeedback method. Again, this method is specified by the instrumentation API. Notice that the Javassist code is only 3 lines. The corresponding BCEL code was about 30.
To get the JVM to load this code on start up requires two more adjustments.
First, the manifest in the jar needs a couple of settings. These 3 lines need to be added:

Premain-Class: javassist.LNFAgent
Agent-Class: javassist.LNFAgent
Boot-Class-Path: JavassistPlugin.jar
Technically, all that is required by the instrumentation API is the Premain-Class and Agent-Class settings. The Boot-Class-Path is required to get the rest of Javassist loaded.
Once this adjusted manifest is added to the jar file, all coding is complete.
The last step is to adjust the command line to start jEdit to invoke the agent on start up. I have a small script I use to start jEdit that sets a couple of environment variables. It looks like this:

#!/bin/sh
export JEDIT_HOME=/home/danson/apps/jedit/current

# Antialias fonts everywhere possible.
ANTIALIAS_ALL="-Dawt.useSystemAAFontSettings=on -Dswing.aatext=true"
export VISUAL=/home/danson/bin/jeditcommit
export EDITOR=$VISUAL

# this one for general usage
#java -Xmx620m -Xms512m ${ANTIALIAS_ALL} "-Djedit.home=$JEDIT_HOME" -jar "$JEDIT_HOME/jedit.jar" -reuseview "$@"


# this one for debugging
#java ${ANTIALIAS_ALL} -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8001,suspend=n -Xmx512m -jar /home/danson/apps/jedit/current/jedit.jar -reuseview > /dev/null 2>&1 &

# this one for no beeps
java -javaagent:/home/danson/.jedit/jars/JavassistPlugin.jar -Xmx620m -Xms512m ${ANTIALIAS_ALL} "-Djedit.home=$JEDIT_HOME" -jar "$JEDIT_HOME/jedit.jar" -reuseview "$@"

The key piece here is that -javaagent part. This tells the JVM to look in JavassistPlugin.jar for a java agent. The manifest tells the JVM the rest of the details. Once the agent is loaded, every single class that the JVM loads is passed to the transform method in the agent, which looks only for the javax.swing.LookAndFeel class, and inserts the tiny bit of code needed to toggle the beep.
That's really all there is to it. My main problems with this approach are
  • The command line to start jEdit needs to be set by hand. There isn't a way to get the agent code to run without including the -javaagent parameter.
  • Packaging this as a jEdit plugin is not right, since jEdit loads plugins late in the start up process and loads them each in their own classloader. Since this agent code is loaded way before jEdit, it can't take advantage of any of the usual plugin facilities.
  • When used as an agent, the plugin cannot be reloaded since it is loaded in the system classloader.
  • And the biggest problem is that I shouldn't need to patch a JVM class. Really, Sun/Oracle should have included what is basically a one-liner to allow apps to turn off the error feedback. It's a simple fix that quite a few people would take advantage of, myself included.
One more note: the right way to make a beep is to make a call like this:
javax.swing.UIManager.getLookAndFeel().provideErrorFeedback(null);
Instead of null, the appropriate component can be passed. Using Toolkit.beep() directly short-circuits the ability of the look and feel to provide it's own implementation of appropriate error feedback, so don't do it! Now I need to go through the jEdit code itself and change out all 156 of those calls to Toolkit.beep()



















Monday, October 29, 2012

Xubuntu ".desktop" files

Xubuntu doesn't have a nice gui editor for the desktop menu. It isn't hard to edit by hand, though.

Each application that appears in the desktop menu has a corresponding file in /usr/share/applications. To create a new one, just copy an existing one and edit it. For example, I created one for jEdit by copying the netbeans.desktop file:

netbeans.desktop:
[Desktop Entry]
Name=NetBeans
Comment=NetBeans
Exec=/home/danson/bin/netbeans
Icon=/home/danson/apps/netbeans-7.0.1/nb/netbeans.png
Categories=Development;Java;
Terminal=false
Type=Application

Modified to jedit.desktop:
[Desktop Entry]
Name=jEdit
Comment=jEdit
Exec=/home/danson/bin/jedit
Icon=/home/danson/apps/jedit/current/doc/jedit.png
Categories=Development;Java;
Terminal=false
Type=Application

One important entry is the "Categories", this puts the applications in the appropriate place in the menu. Possible choices are:

Accessories
Audio
Development
Games
Graphics
Internet
Multimedia
Network
Office
Settings
System
Utility

There are others, but these are the common categories.




Wednesday, May 25, 2011

One of the best features of jEdit

Macros. The beanshell macro integration in jEdit is simply awesome. Here's an excellent example. Recently, a number of us at work are writing components for Day CQ5 (www.day.com), which is a high-end content management system. Most of the components are written as jsps. We are running local instance of CQ, but everything is packaged into jars, so it's not a simple matter of saving a changed jsp to the server with a regular save command. Fortunately, the server will reload a jsp that is sent to it with curl:

curl -T localfile destinationUrl

The Eclipse people run this from the command line, changing the filename and url by hand each time they move to a different file. I wrote a simple macro:


// macro to save and send a jsp file to a local Day instance
String filename = buffer.getPath();

// save the buffer and upload it to crx.
if (!buffer.isReadOnly()) {
    buffer.save(view, null);
}
//String filepath = filename.substring(filename.indexOf("WebContent") +"WebContent".length());
String filepath = filename.substring(filename.indexOf("jcr_root") + "jcr_root".length());
String destination = "http://admin:admin@localhost:4502" + filepath;
String cmd = "curl -T " + filename + " " + destination;
exec(cmd);

Then I mapped a keyboard shortcut to Alt+S. Now whenever I want to save an edited jsp to the server, it is a simple keyboard command, no typing long paths in the command line. The Eclipse guys are somewhat jealous and I am saving quite a bit of time.

Saturday, November 14, 2009

The jEdit IDE


jEdit an extremely customizable code editor. There are literally hundreds of plugins, and with the right combination, a full-fledged IDE can be setup. This is not out-of-the box, rather, it takes some work to get jEdit configured as a really good IDE.


The list below is what I consider to be the essential plugins for Java web application development. Together, these provide basic project management, version control, fast access to your files, customizable output from the various plugins and external tools, easily work with and execute Ant build files, view and navigate to errors, and move quickly through your code, in essence, the main features you'd want in any IDE. This is just a quick overview, read the individual help files for each plugin for details. This is a minimal set, there are many other plugins available that may be worth exploring if you work in other languages than Java.


This list is in alphabetical order rather than importance. Importance is really dependent on the user, so I leave that to you to decide.


  • Antelope Runs targets in Ant files with the click of a button, which makes it very easy to compile and build your code just as your build system does. There is an old version of this plugin available in Plugin Manager, but the newest version is at tigris.org.
  • AStyle A fast and good formatter for Java and C/C+ code, integrates with Beauty.
  • Beauty Provides a code beautifying framework. It works with the XML plugin to beautify XML-based files and with the AStyle plugin to beautify Java and C files. It provided built-in formatting of a variety of files, including html, javascript, css, jsp, etc.
  • BufferLocal This is the most unobstrusive plugin of all. It keeps track of the buffer local settings you make on a per file basis. "Buffer local" settings are those that you make using the Utilities - Buffer Options dialog. If you change those settings, this plugin will remember them for you and apply them automatically the next time you open the same file.
  • Calculator Full-featured RPN calculator, work in binary, octal, decimal, and hexidecimal. Perfect for when you need to work with computer-based numbers.
  • Character Map Lets you choose specific characters from any supported encoding for insertion into your code.
  • Code2HTML This plugin transforms the current source file or the current selection into a visually equivalent HTML file. The generated HTML files accurately represents the syntax highlighting and spacing of the file. This is great when preparing code examples for documentation or even for javadoc comments.
  • Console The Console plugin has four main functions:
    • Running external programs and commands.
    • Parsing the output of external programs for errors in a variety of formats, and reporting those errors using the ErrorList plugin.
    • The Commando feature provides graphical front-ends, specified using an XML file, to command-line tools.
    • Providing an extensible framework for other plugins that need to display streamed output.

    This is where many plugins will show their output, and can be considered one of the core plugins.
  • Context Menu The ContextMenu plugin allows you to change the text area's right-click context menu for each mode. To the menu, you can add jEdit's built-in actions, or actions from any plugin, or a macro. Selected actions can be also shown in jEdit's menu bar.
  • CtagsInterface The CtagsInterface plugin provides the "jumping around" feature that many IDE's provide. You can put the caret on a variable, and jump to the definition of the variable, or put the caret on a class name, and jump to the class itself.
  • ErrorList The ErrorList plugin displays errors and warnings generated by other plugins. It does nothing on its own, but many plugins use it to show any error messages. This is should be considered a core plugin.
  • Fast Open FastOpen is a plugin designed to quickly open any file in the current project by just typing in the first few characters of the filename you want to open. Besides quickly opening any file, it has a lot of features like switching between projects, indicating invalid filenames etc. FastOpen can open files in the projects and/or non project files too. I've got this set to open with Ctrl-Shift-F key combination.
  • Highlight This plugin is a very simple plugin that will highlight a word you selected and is very similar to the same feature found in IntelliJ. Ctrl-H will toggle highlighting of the current word.
  • ImageViewer This is a simple image viewer that makes it easy to see a preview of images files from jEdit's file system browser or from ProjectViewer. This plugin does not provide any image editing capability, rather, it is intended to help you find the right image file quickly without having to open a separate image editing application.
  • Info Viewer With the InfoViewer Plugin you can choose to use the built-in web browser or set the preferred browser that jEdit and assorted plugins use to display HTML documentation.
  • JavaSideKick The JavaSideKick plugin provides a highly customizable tool for navigating through Java source code. Integrated with SideKick, you can see a tree view for the hierarchy of classes, interfaces, and methods for the file in the current buffer. In addition, attributes, extends, implements and method exception information can be displayed. This plugin also provides browsing of Java-style property files and JavaCC files (.jj and .jjt files), and provided context-sensitive code completion for Java files.
  • JDiff This is a diff and merge utility for jEdit, and is as good or better than many other diff programs you may find on the internet. The SVN Plugin uses JDiff.
  • JIndex When editing Java source files, the JIndex plugin enables jEdit to show the JavaDoc API html documentation for the currently selected word, with a single key press. You'd be advised to use a regular browser with this plugin rather than InfoViewer.
  • Log Viewer This plugin allows you to follow several log files at a time within jEdit, much like you might do with tail.
  • LookAndFeel This one is not an essential plugin, but it can let you set the user interface to something more pleasant to use than Metal. The LookAndFeel plugin lets you choose between different non standard look and feel implementations for jEdit. Currently, the following look and feel implementations are supported:
    • JGoodies
    • Kunststoff
    • Metouia
    • NimROD
    • Oyoaha
    • Skin
    • Tonic
    • Napkin
    • Lipstik

    It's nice to be able to easily change up the look of your main application every now and then. Along with the Look and Feel plugin, the Editor Scheme plugin lets you choose between a number of color schemes for the main text area. Personally, I like Lipstik with the Zenburn theme and use the Editor Scheme plugin to set the Zenburn scheme.
  • MacroManager Not essential for code development, this plugin provides an interface within jEdit to the macros contributed to the jEdit Community website, much like Plugin Manager. It makes it easy to install new macros that others have written.
  • Navigator The Navigator Plugin provides a set of "Back" and "Forward" actions similar to a web browser. This is surprisingly handy when browsing code, especially when used in conjunction with CtagsInterface.
  • Outline Provides a SideKick-like tree which displays folds rather than language-specific structures. I don't use this much since I don't like folding and have it turned off, but it's nice for those languages for which there isn't a specific Sidekick parser.
  • PMDPlugin This is an essential plugin for working with Java. PMD is a Java source code analyzer - it finds unused variables, questionable design decisions, empty catch blocks, and so forth. I've got it set to check files on save. It can be really verbose and hard to configure, but the version included here has some UI fixes that I added to make it easier to set the rules. PMD in jEdit is a joy to use, unlike PMD in Eclipse, which is kind of a pain. It also comes with a rule designer so you can make your own rules for code checking, and a copy/paste detector to help locate duplicate code.
  • Project Viewer The ProjectViewer plugin allows defining groups of files as projects. Unlike Eclipse projects and workspaces, ProjectViewer is extremely flexible, and jEdit will easily let you work on files outside of your workspace and include files from anywhere in the file system. Consider this one a core plugin, it makes it really easy to organize your files. Several other plugins provide close integration with ProjectViewer, including SVN, CtagsInterface, TaskList, ImageViewer, and Fast Open.
  • SideKick The SideKick plugin provides a dockable window in which other plugins can display buffer structure. It really doesn't do anything by itself, it provides the framework for other plugins, such as JavaSideKick and XML to display a code browsing tree. The "Outline" view in Eclipse is modeled after Sidekick.
  • SVN This is a plugin for providing Subversion support from within jEdit. It is tightly integrated with Project Viewer, and requires no external SVN client libraries.
  • TaskList This is a handy plugin for showing to do's, notes, and so on. Just add a tag in your code and it'll show up in the Task List. Tasks can be displayed per file, for all open files, for a project, or for a selection of files from the file system browser.
  • TextAutocomplete Collects "words" in the current buffer and those that you type and offers you automatically a list of possible completions. It's pretty similar to the jEdit's function "Complete Word" but it's automatic, you don't need to press any key to invoke the list of completions. There are several plugins similar to this one, you might want to try them all to see which one best fits your needs. Note that code completion for Java files is better done with the JavaSideKick plugin, and the XML plugin provided code completion for XML and HTML.
  • TextTools The TextTools plugin provides a set of plugin actions for manipulating text in a buffer:
    • Sort
    • Reverse Sort
    • Advanced Sort (field sort)
    • Delete duplicates
    • Shuffle
    • Transpose Characters
    • Transpose Lines
    • Transpose Words
    • Column Insert
    • Block Fill Insert
    • Move Rectangular Selection
    • Toggle Line Comment
    • Toggle Range Comment

  • WhiteSpace The main feature of the WhiteSpace plugin is to highlight whitespace, but the feature I find most useful is to do clean up on buffers when saved, which can be a big help in keeping files in conformance with style guidelines.
  • XML The XML plugin combines the HtmlSideKick plugin by yours truly, the JavaScriptSideKick by Martin Raspe, the CSS SideKick by Jakub Roztocil, an improved CSS SideKick by me, EcmaScript parser, again by me, and the XmlIndenter plugin by Robert McKinnon, providing six distinct Sidekick parsers and four different completion services, as well as integrating with the Beauty plugin for beautifying XML and XML-like files.




You'll notice there is no debugger listed here. I've been working with Java code for about 12 years now, and have only rarely found a need for a debugger since leaving C behind. However, if you do need one, there are a couple of options. First, there is the GdbPlugin. This plugin works as a front-end to the GNU gdb debugger. Second is a separate application altogether, JSwat. There used to be a JSwat plugin for jEdit, but I don't believe it's being maintained anymore and doesn't work with the latest versions of jEdit. JSwat is available at http://jswat.sourceforge.net.

Thursday, June 11, 2009

Setting up DocBook to create jEdit documentation

Ubuntu 9.04:

Open Synaptic, search for "docbook" and install these:

  1. docbook-xml
  2. docbook-dsssl
  3. docbook-xsl-doc-html
  4. docbook-xsl
That should be all that is necessary.

Wednesday, May 20, 2009

Using jEdit as an external editor for Eclipse

Here is a tip on how to use jEdit as an external editor from Eclipse. What this means is that when you open a file for editing in Eclipse, Eclipse will open jEdit and the editing happens in jEdit rather than in Eclipse. This is great since jEdit is a better editor than Eclipse is, and in some ways, Eclipse is a better IDE than jEdit is.

First, I created a small shell script and put it in my path:


#!/bin/bash

java -jar /home/danson/apps/jedit/jedit.jar -reuseview $1


You'll want to adjust the path as appropriate for your system. Windows users should be able to create a batch file to do exactly the same thing. I have a "bin" directory in my home folder that is in my path, so I put the shell script there. The "-reuseview" parameter is important so you only get one jEdit window. Without this parameter, you'll get a new jEdit window per file.

Next, tell Eclipse to use jEdit:

  1. Go to Window, Preferences, then General - Editors - File Associations.
  2. Select the file type you want to be able to edit in jEdit.
  3. Click the "Add" button beside the "Associated editors" box.
  4. Select "External programs", then "Browse", then pick your shell script from the file browser and click "OK".
  5. See that jEdit shows up in the associated editors box. You can choose it and set it as default.

It would be nice if Eclipse allowed picking multiple file types at once so it would be easier to associate say, java, jsp, js, and html files all at once to jEdit.

Now when you open a file of that type, Eclipse will open jEdit as the editor. You can still open the file in Eclipse if you'd like, just right click on the file in the perspective, choose "Open with", and pick what you want.

Wednesday, April 8, 2009

Releasing jEdit plugins

I am a member of the jEdit development group, and as part of that group, I sometimes help release plugins. These are my instructions. I copied this from email and put it here so it is easy to find.

Hudson home page: https://hudson.dev.java.net

Download the latest from here: http://hudson.gotdns.com/latest/hudson.war

Start it with: java -jar hudson.war

It has its own built-in servlet container, so it runs as a webapp.

Point your browser to: http://localhost:8080

Hudson will create ~/.hudson. All the work files (svn checkout, build artifacts, etc) end up there. I didn't bother to change the default directory.

Configure Hudson:
- Click the "Manage Hudson" link. Add in your JDK installations and Ant installations. This lets you easily pick the right JDK and Ant version to build a specific plugin.
- Click the "Manage Plugins" link. Add the "batch-task" plugin.


To build a plugin: (Note, depending on the plugin, you'll need to do this step for each plugin that the plugin depends on.)

On the Hudson front page, click "New Job".
- Fill in the "Job Name". Hudson will make a directory with this name so don't put spaces in the name if you don't like them in your directory names.
- Click "Build a free-style software project". After the first one, you can do "Copy existing job" to save some time.
- Click OK, you'll be taken to the Configure page
- Pick the JDK to use to build the plugin
- Choose Subversion and fill in the the url to the release tag for the plugin
- Fill in the module name if you want.
- Check "Use update" if you want.
- Pick the version of Ant to use to build the plugin.
- You can probably leave the targets field blank, but that might depend on the specific plugin.
- Click the "Advanced" button and add these properties, adjusting for your local paths and the appropriate jEdit installation. I've got my various jEdit installations in ~/apps/jedit/$version/. You might also need to include your xdoclet properties:

build.support=/home/danson/src/plugins/build-support
jedit.install.dir=/home/danson/apps/jedit/4.3pre7
install.dir=/home/danson/apps/jedit/4.3pre7/jars

- Click the "Save" button, you'll be taken to the project home page.
- Click the "Build Now" link.
- Click the date link when the build starts.
- Click "Console output" to see the build output.
- Adjust and repeat as necessary to get the plugin to build.


To package a plugin: (The first 4 steps could be done with the configure steps above.)
- From the project home page, click the "Configure" link.
- Check the "Batch tasks" check box.
- Fill in the task name, I called it "package".
- Fill in the "Script" text area with this, adjusting the values for the plugin:
ant -f /home/danson/src/plugins/build-support/package.xml -Dplugin.name=CommonControls -Dplugin.version=1.0.2 -Djar.filename=CommonControls.jar -Djar.location=/home/danson/apps/jedit/4.3pre11/build/jars -Dsrc.dir=/home/danson/.hudson/jobs/CommonControls/workspace/CommonControls -Dout.dir=/home/danson/tmp/CommonControls
- Go back to the project front page
- Click "task", then "package" (or whatever you named the task) from the box on the right.
- Click the "Build Now" link to tar/zip the files.

I've attached the "package.xml" file referenced in the "Script" section above, I'll probably add it to the build-support project in jEdit subversion. This is what creates the .tgz and .zip files to upload to the file release system.

To release the plugin:
- upload the .tgz and .zip files:
cd to the directory containing the files to upload
> sftp username@frs.sourceforge.net
> cd uploads
> mput *
> bye
- log into https://sourceforge.net/projects/jedit-plugins/
- Click the "Download" tab, then "Browse All Packages", then "Manage Packages/Releases".
- Find your plugin, then click "[Add Release]"
- Enter the version number of the plugin for the release name
- Click the button to create the release
- Paste in the release notes from the plugin release request, click "Submit"
- Check the boxes by the 4 files you uploaded to frs.sourceforge.net, click the "Add files" button.
- Set the processor type and file type for each uploaded file. You have to do these one at a time.
- Send the email release notice if applicable.
- Check that the files with the right version number are available at https://sourceforge.net/project/showfiles.php?group_id=64089
- Log into http://plugins.jedit.org/wiz
- Click the "View packages" link.
- Find your plugin in the list and follow the link.
- Click "View releases"
- Click "Create new release"
- Fill in the form, version number, file sizes, and changes are required. Use the announcement line from the plugin release request or the text for the plugin from http://plugins.jedit.org/list.php. The "changes" text will end up on the http://plugins.jedit.org/list.php page.
- Enter the dependencies, then click the "Update dependencies" button.
- Click the "Create release" button. Ensure your new version is on the next page, you might have to refresh the page to see it.
- Go back to http://plugins.jedit.org/wiz
- Click the "Generate a new plugin list" link.
- Wait a while (next day, maybe) and check that the plugin shows up in Project Manager in jEdit.
- close the release request.




This is package.xml:

   1:<project name="package" default="package" basedir=".">
2:
3: <!-- name of the plugin, e.g. TextObjects -->
4: <property name="plugin.name" value="TextObjects"/>
5:
6: <!-- version of the plugin, e.g. 1.0.1 -->
7: <property name="plugin.version" value="1.0.1"/>
8:
9: <!-- name of the plugin jar file, e.g. TextObjects.jar -->
10: <property name="jar.filename" value="TextObjects.jar"/>
11:
12: <!-- full path location of the plugin jar -->
13: <property name="jar.location" location="/home/danson/.hudson/jobs/jEdit 4.3pre15/workspace/jEdit_4.3pre15/build/jars"/>
14:
15: <!-- comma or whitespace separated list of additional jars to bundle -->
16: <property name="additional.jars" value=""/>
17:
18: <!-- directory containing additional jars to bundle -->
19: <property name="additional.jars.dir" location="${jar.location}"/>
20:
21: <!-- full path location of the source directory for the plugin -->
22: <property name="src.dir" location="/home/danson/.hudson/jobs/TextObjects/workspace/TextObjects_1.0.1"/>
23:
24: <!-- where to put the tgz and zip files -->
25: <property name="out.dir" location="/home/danson/tmp"/>
26:
27: <!-- package the plugin for release to plugin central -->
28: <target name="package">
29: <mkdir dir="${out.dir}"/>
30:
31: <!-- tar/gzip, includes plugin jar, additional jars, and source code -->
32: <property name="tar.filename" value="${out.dir}/${plugin.name}-${plugin.version}"/>
33: <tar destfile="${tar.filename}.tar">
34: <tarfileset dir="${src.dir}">
35: <include name="**/*"/>
36: </tarfileset>
37: <tarfileset dir="${jar.location}">
38: <include name="${jar.filename}"/>
39: </tarfileset>
40: <filelist dir="${additional.jars.dir}" files="${additional.jars}"/>
41: </tar>
42: <gzip zipfile="${tar.filename}.tgz" src="${tar.filename}.tar"/>
43: <delete file="${tar.filename}.tar"/>
44:
45: <!-- tar/gzip bin, only includes plugin jar and additional jars -->
46: <property name="tar.bin.filename" value="${out.dir}/${plugin.name}-${plugin.version}-bin"/>
47: <tar destfile="${tar.bin.filename}.tar">
48: <tarfileset dir="${jar.location}">
49: <include name="${jar.filename}"/>
50: </tarfileset>
51: <filelist dir="${additional.jars.dir}" files="${additional.jars}"/>
52: </tar>
53: <gzip zipfile="${tar.bin.filename}.tgz" src="${tar.bin.filename}.tar"/>
54: <delete file="${tar.bin.filename}.tar"/>
55:
56: <!-- zip bin, only includes plugin jar and additional jars -->
57: <property name="zip.bin.filename" value="${out.dir}/${plugin.name}-${plugin.version}-bin.zip"/>
58: <zip destfile="${zip.bin.filename}">
59: <zipfileset dir="${jar.location}">
60: <include name="${jar.filename}"/>
61: </zipfileset>
62: <filelist dir="${additional.jars.dir}" files="${additional.jars}"/>
63: </zip>
64:
65: <!-- zip, includes plugin jar, additional jars, and source code -->
66: <property name="zip.filename" value="${out.dir}/${plugin.name}-${plugin.version}.zip"/>
67: <zip destfile="${zip.filename}">
68: <zipfileset dir="${src.dir}">
69: <include name="**/*"/>
70: </zipfileset>
71: <zipfileset dir="${jar.location}">
72: <include name="${jar.filename}"/>
73: </zipfileset>
74: <filelist dir="${additional.jars.dir}" files="${additional.jars}"/>
75: </zip>
76: </target>
77:</project>