Wednesday, October 8, 2008

Reformat generated getters/setters with Eclipse Monkey (Aptana Scripting)

I write Java code with Eclipse every day, and I find it to be an indispensable tool. However, I still find situations where I drop back to Emacs for things that Eclipse is just not flexible enough for. For instance, although the code formatting options in Eclipse are very thorough, there is at least one situation where I prefer to override what it generates for me.

Before I go any further, I'd like to point out that it doesn't matter if you agree with the formatting preference I'm going to describe. I'm not saying that to be difficult, I'm just saying that the facilities I want to describe to you will allow you to implement your own formatting preferences, or your own custom scripting, whatever you want. My formatting preference is just an example of something you could do.

What I'm going to describe is part of the Aptana Studio plugin for Eclipse. The facility is called "Eclipse Monkey", although the Eclipse project for this appears to be obsolete, and this is now totally under the Aptana domain. It's now generically called "Aptana Scripting". You can read about this (still with the "Eclipse Monkey" name) here.

The tool is inspired by the Mozilla Greasemonkey facility. It allows you to write and execute JavaScript in Eclipse that operates on the "object model" in Eclipse. The Eclipse Monkey site has examples, and when you install the Aptana plugin, you'll see lots of examples you can view in the "Scripts" view. The bad news is that the documentation for this tool leaves a great deal to be desired. You can do some useful things just by copying code from examples, but there's no obvious place to get information on the APIs you're using in that code. The transition from "Eclipse Monkey" to "Aptana Scripting" happened recently, so hopefully Aptana will make more of this information available.

The example I'm going to show you will reformat the generated code for the "Generate Getters/Setters" operation to reflect my preference. I prefer to format getters/setters in a very compact form, with each method on a single line, although my general bracing and spacing preferences are very different from this.

After installing the Aptana plugin, create a simple Java project. Create a folder at the root of the project called "scripts". In that folder, place the following script, calling it "formatGettersSetters.js" (or whatever you want to call it):
/*
* Reformat the result of "Generate Getters/Setters" so each method is on a single
* line. For instance, if the generated code was this:
*
* public String getStuff()
* {
* return stuff;
* }
* public void setStuff(String stuff)
* {
* this.stuff = stuff;
* }
*
* The script will produce this:
*
* public String getStuff() { return stuff; }
* public void setStuff(String stuff) { this.stuff = stuff; }
*
* Menu: Java > Format Getters/Setters
* Kudos: David Karr
* Key:M3+INSERT
* License: EPL 1.0
* DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript
*/

function main()
{
var sourceEditor = editors.activeEditor;
// make sure we have an editor
if (sourceEditor === undefined)
{
valid = false;
showError("No active editor");
}
else
{
var range = sourceEditor.selectionRange;
var offset = range.startingOffset;
var deleteLength = range.endingOffset - range.startingOffset;
var source = sourceEditor.source;

var selection = source.substring(range.startingOffset, range.endingOffset);
// Find spaces between right paren and left brace
var regex = /\)[ \r\t\f\n]*{/gm;
selection = selection.replace(regex, ') {');
// Find spaces between left brace and first non-space
regex = /{[ \r\t\f\n]*/gm;
selection = selection.replace(regex, '{ ');
// Find spaces between last non-space and right-brace
regex = /[ \r\t\f\n]*}/gm;
selection = selection.replace(regex, ' }');
sourceEditor.applyEdit(offset, deleteLength, selection);
sourceEditor.selectAndReveal(offset, selection.length);
}
}
Now, create a new Java class in your project. In the class, define three (for example) instance variables. Then, execute the "Generate Getters and Setters..." option from the Eclipse menu, however you like to do it. I use the keyboard shortcut, which is "Alt-Shift-s, r". Then do "Select All" (Alt-a) and click OK.

At this point, the generated getters/setters have been inserted into the editor, and the inserted region is selected. Without changing the selection, from the menubar select "Scripts", then "Java", then "Format Getters/Setters". This will replace the generated region with a reformatted version of it, with each method on a single line.

Again, this is just an example of the kinds of things you can do with this tool. As Aptana does more work on refining the tool and producing more documentation, this tool will become even more useful. For example, one facility that is available, but which I need more information about, is the ability to have scripts execute automatically when certain events occur, without having to manually execute them. It's possible that this reformatting script could be executed automatically after completion of the "Generate Getters/Setters" operation.

No comments: