Thursday Jan 03, 2013

Code Folding via NetBeans, JJTree, and PowerJava

Once you have a ParserResult, as described yesterday, you also need to have access to some kind of AST node, i.e., not only tokens. Tokens let you distinguish between individual characters in a document, but that's not enough if you want to create code folding for your editor. Below you see code folding for PowerJava, which is an extension to Java 1.5 for role programming. It has about 8 special keywords, which in my editor are shown in orange, as can be seen for two of them below:

The first code fold, i.e., the initial code fold, is created automatically for you if you use the CSL API. However, the other code fold you see above was created via code in the related StructureScanner:

class PowerJavaStructureScanner implements StructureScanner {

    public static final String CODE_FOLDS = "codeblocks";
    public List<? extends StructureItem> scan(ParserResult pr) {
        return new ArrayList<StructureItem>();

    public Map<String, List<OffsetRange>> folds(ParserResult pr) {
        HashMap<String, List<OffsetRange>> folds = new HashMap<String, List<OffsetRange>>();
        PowerJavaParserResult pjpr = (PowerJavaParserResult) pr;
        Document document = pr.getSnapshot().getSource().getDocument(false);
        try {
            ASTCompilationUnit cu = pjpr.getASTCompilationUnit();
            Node[] children = cu.getChildren();
            for (int i = 0; i < children.length; i++) {
                Node node = children[i];
                if (node instanceof ASTTypeDeclaration) {
                    ASTTypeDeclaration asttd = (ASTTypeDeclaration) node;
                    Token jjtGetFirstToken = asttd.jjtGetFirstToken();
                    Token jjtGetLastToken = asttd.jjtGetLastToken();
                    int start = NbDocument.findLineOffset((StyledDocument) document, 
                            jjtGetFirstToken.beginLine - 1) + jjtGetFirstToken.beginColumn - 1;
                    int end = NbDocument.findLineOffset((StyledDocument) document, 
                            jjtGetLastToken.endLine - 1) + jjtGetLastToken.endColumn;
                    String type = CODE_FOLDS;
                    OffsetRange range = new OffsetRange(start, end);
                    List<OffsetRange> fold = folds.get(type);
                    if (fold == null) {
                        fold = new ArrayList<OffsetRange>();
                    folds.put(type, fold);
        } catch (org.netbeans.modules.parsing.spi.ParseException ex) {
        return folds;

    public Configuration getConfiguration() {
        return new Configuration(false, false);


The above implies that you have higher level objects, such as ASTCompilationUnit. You can get those via JJTree, but only if you have defined a related JJT file, in addition to your JJ file. And that's why I am using PowerJava as an example, as can be seen above, because the nice people who created PowerJava have all the relevant source code available. I simply had to run javacc on their Java1.5.jjt file, and then I had everything I needed. I then integrated their lexer into the NetBeans lexer infrastructure, which enabled me to create the syntax coloring you see above. Then I used the generated parser as shown above, i.e., I can now obtain meaningful information via the generated parser so that code folds can be created.


Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.


« January 2013 »