When using the CSL API, you should not use org.netbeans.spi.editor.fold.FoldManager directly. It is too heavyweight, when compared to the alternative provided by the CSL API: org.netbeans.modules.csl.api.StructureScanner.
If you have a class like this, i.e., extending org.netbeans.modules.csl.spi.DefaultLanguageConfig and using the org.netbeans.modules.csl.spi.LanguageRegistration annotation, then you can pass in a StructureScanner, as shown below:
package org.simplejava; import org.netbeans.api.lexer.Language; import org.netbeans.modules.csl.api.StructureScanner; import org.netbeans.modules.csl.spi.DefaultLanguageConfig; import org.netbeans.modules.csl.spi.LanguageRegistration; import org.netbeans.modules.parsing.spi.Parser; import org.simplejava.lexer.SJTokenId; import org.simplejava.parser.SJParser; import org.simplejava.parser.SJStructureScanner; @LanguageRegistration(mimeType = "text/x-sj") public class SJLanguage extends DefaultLanguageConfig { @Override public Language<SJTokenId> getLexerLanguage() { return SJTokenId.getLanguage(); } @Override public String getDisplayName() { return "SJ"; } @Override public Parser getParser() { return new SJParser(); } @Override public StructureScanner getStructureScanner() { return new SJStructureScanner(); } @Override public boolean hasStructureScanner() { return true; } }
Then here's a dummy implementation of the above:
package org.simplejava.parser; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.netbeans.modules.csl.api.OffsetRange; import org.netbeans.modules.csl.api.StructureItem; import org.netbeans.modules.csl.api.StructureScanner; import org.netbeans.modules.csl.api.StructureScanner.Configuration; import org.netbeans.modules.csl.spi.ParserResult; public class SJStructureScanner implements StructureScanner { @Override public List<? extends StructureItem> scan(ParserResult pr) { return new ArrayList<>(); } @Override public Map<String, List<OffsetRange>> folds(ParserResult pr) { return new HashMap<>(); } @Override public Configuration getConfiguration() { return null; } }
When you look in GsfFoldManager.java, which any CSL plugin automatically includes thanks to the @LanguageRegistration annotation above, you'll see that from the DefaultLanguageConfig extension the StructureScanner is located and an internal FoldManager implementation is used to get the folds defined in StructureScanner.folds(), after which all the necessary things are done for you.
Some default folds are created automatically by the internal FoldManager implementation, such as for the initial comment, as shown below:
As the ParserResult from your parser is passed to the SS.folds() method, you should be able to get the folds since the parser result should contain a parse tree where the code block is described by some node in the tree.
Note: For the above to work, your ParserResult class must extend org.netbeans.modules.csl.spi.ParserResult and NOT org.netbeans.modules.parsing.spi.parser.Result. Just return Collections.EMPTY_LIST from getDiagnostics initially.
Useful implementations:
- http://blogtrader.net/blog/erlang_plugin_for_netbeans_in4#
- https://bitbucket.org/tcolar/fantomidemodule/src/e6f2e418e49d/src/net/colar/netbeans/fan/structure/FanStructureAnalyzer.java?at=Fan
- https://github.com/dstepanov/coffeescript-netbeans/blob/master/src/coffeescript/nb/CoffeeScriptStructureScanner.java