HTML Tidy in NetBeans IDE
- by Geertjan
First step in integrating HTML Tidy (via its JTidy implementation) into NetBeans IDE:
The reason why I started doing this is because I want to integrate this into the pluggable analyzer functionality of NetBeans IDE that I recently blogged about, i.e., where the FindBugs functionality is found.
So a logical first step is to get it working in an Action class, after which I can port it into the analyzer infrastructure:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.LineCookie;
import org.openide.loaders.DataObject;
import org.openide.text.Line;
import org.openide.text.Line.ShowOpenType;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.IOProvider;
import org.openide.windows.InputOutput;
import org.openide.windows.OutputEvent;
import org.openide.windows.OutputListener;
import org.openide.windows.OutputWriter;
import org.w3c.tidy.Tidy;
@ActionID(
category = "Tools",
id = "org.jtidy.TidyAction")
@ActionRegistration(
displayName = "#CTL_TidyAction")
@ActionReferences({
@ActionReference(path = "Loaders/text/html/Actions", position = 150),
@ActionReference(path = "Editors/text/html/Popup", position = 750)
})
@Messages("CTL_TidyAction=Run HTML Tidy")
public final class TidyAction implements ActionListener {
private final DataObject context;
private final OutputWriter writer;
private EditorCookie ec = null;
public TidyAction(DataObject context) {
this.context = context;
ec = context.getLookup().lookup(org.openide.cookies.EditorCookie.class);
InputOutput io = IOProvider.getDefault().getIO("HTML Tidy", false);
io.select();
writer = io.getOut();
}
@Override
public void actionPerformed(ActionEvent ev) {
Tidy tidy = new Tidy();
try {
writer.reset();
StringWriter stringWriter = new StringWriter();
PrintWriter errorWriter = new PrintWriter(stringWriter);
tidy.setErrout(errorWriter);
tidy.parse(context.getPrimaryFile().getInputStream(), System.out);
String[] split = stringWriter.toString().split("\n");
for (final String string : split) {
final int end = string.indexOf(" c");
if (string.startsWith("line")) {
writer.println(string, new OutputListener() {
@Override
public void outputLineAction(OutputEvent oe) {
LineCookie lc = context.getLookup().lookup(LineCookie.class);
int lineNumber = Integer.parseInt(string.substring(0, end).replace("line ", ""));
Line line = lc.getLineSet().getOriginal(lineNumber - 1);
line.show(ShowOpenType.OPEN, Line.ShowVisibilityType.FOCUS);
}
@Override
public void outputLineSelected(OutputEvent oe) {}
@Override
public void outputLineCleared(OutputEvent oe) {}
});
}
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
}
The string parsing above is ugly but gets the job done for now.
A problem integrating this into the pluggable analyzer functionality is the limitation of its scope. The analyzer lets you select one or more projects, or individual files, but not a folder. So it doesn't work on folders in the Favorites window, for example, which is where I'd like to apply HTML Tidy, across multiple folders via the analyzer functionality. That's a bit of a bummer that I'm hoping to get around somehow.