问题描述
我想在已经配备 Netbeans Java 编辑器工具包(类 org.netbeans.modules.editor.java.JavaKit)的 JEditorPane 中实现语法着色。我注意到当 JEditorPane 使用 RTF 编辑器工具包时,关键字是彩色的(请参阅此问题和答案 https://stackoverflow.com/a/67025502/8315843)。问题是 Netbeans 有一个有趣的组件,我想使用它,称为 diff 视图,而 diff 视图使用两个 JEditorPanes,这两个 JEditorPanes 配备了这个似乎不提供语法着色的 Javakit。
在下面的示例代码中,我展示了 2 个可能的执行路径:
- 使用 RTF 编辑器工具包,您会看到标记为蓝色的关键字 public
- 使用 Netbeans Javakit,您发现它不起作用
至于输入,我使用了一个非常简约的类“public class Hello {}”,它位于名为“text”的变量中。
boolean useNetbeansJavakit = JOptionPane.showConfirmDialog(null,"Use Netbeans Javakit ?") == JOptionPane.YES_OPTION;
JFrame f = new JFrame("JAVA Syntax Coloring");
// Create the StyleContext,the document and the pane
StyleContext sc = new StyleContext();
final DefaultStyledDocument doc = new DefaultStyledDocument(sc);
JEditorPane pane;
if (useNetbeansJavakit) {
pane = new JEditorPane();
pane.setEditorKit(CloneableEditorSupport.getEditorKit("text/x-java"));
} else {
pane = new JEditorPane("text/rtf","");
}
System.out.println(pane.getEditorKit());
pane.setDocument(doc);
// Create and add the constant width style
final Style cwStyle = sc.addStyle("ConstantWidth",null);
StyleConstants.setFontFamily(cwStyle,"monospaced");
StyleConstants.setForeground(cwStyle,Color.blue);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
// Add the text to the document
doc.insertString(0,text,null);
// Only color the word public for Now in a hardcoded style
doc.setCharacterattributes(0,6,cwStyle,false);
} catch (BadLocationException e) {
}
}
});
} catch (Exception e) {
System.out.println("Exception when constructing document: " + e);
System.exit(1);
}
f.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(pane));
f.setSize(400,300);
f.setVisible(true);
}
public static final String text = "public class Hello {}";
这是 gradle 构建文件:
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation files("${System.properties['java.home']}/../lib/tools.jar")
implementation 'org.netbeans.modules:org-netbeans-modules-java-editor:RELEASE123'
implementation 'org.netbeans.modules:org-netbeans-modules-editor-mimelookup-impl:RELEASE123'
implementation 'org.apache.commons:commons-lang3:3.10'
}
我一直在尝试使用基于词法分析器的语法高亮器,但我不知道如何使用,我只能猜测如何使用它,如下所示,但我只是不明白它是如何使用的'不是本地人。在 netbeans 库中,一切似乎都可以进行一些语法着色(请参阅类 org.netbeans.modules.editor.lib2.highlighting.SyntaxHighlighting,但我找不到有关如何使用它的任何解释)。 在下面的代码中,我将文本标记为标识符并检查关键字,然后输入关键字标记的着色信息。
JFrame f = new JFrame("JAVA Syntax Coloring");
// Create the StyleContext,the document and the pane
StyleContext sc = new StyleContext();
final DefaultStyledDocument doc = new DefaultStyledDocument(sc);
JEditorPane pane = new JEditorPane();
pane.setEditorKit(CloneableEditorSupport.getEditorKit("text/x-java"));
System.out.println(pane.getEditorKit());
pane.setDocument(doc);
LexerBasedHighlightLayer lexerBasedHighlightLayer = (LexerBasedHighlightLayer) doc.getProperty(SemanticHighlighter.class);
HashMap<Token,Coloring> colorings = new HashMap<>(lexerBasedHighlightLayer.getColorings());
Language<JavaTokenId> java = JavaTokenId.language();
TokenHierarchy<String> th = TokenHierarchy.create(text,java);
TokenSequence<JavaTokenId> ts = th.tokenSequence(java);
while (ts.moveNext()) {
Token<JavaTokenId> token = ts.token();
String tokenText = token.text().toString();
if (tokenText.matches(
"(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)")) {
ColoringAttributes colorAttr = EnumUtils.getEnum(ColoringAttributes.class,tokenText.toupperCase());
if (colorAttr != null) {
Coloring coloring = ColoringAttributes.add(ColoringAttributes.empty(),colorAttr);
colorings.put(token,coloring);
}
}
}
lexerBasedHighlightLayer.setColorings(colorings,colorings.keySet(),null);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
// Add the text to the document
doc.insertString(0,null);
} catch (BadLocationException e) {
}
}
});
} catch (Exception e) {
System.out.println("Exception when constructing document: " + e);
System.exit(1);
}
f.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(pane));
f.setSize(400,300);
f.setVisible(true);
}
public static final String text = "public class Hello {}";
颜色信息在 jar org-netbeans-modules-java-editor-RELEASE123.jar 中的 XML 文件中配置。为了配置我自己的颜色,我将 org/netbeans/modules/java/editor/resources 目录从 jar 复制到我的工作区 src/main/resources/org/netbeans/modules/java/editor/resources。
在文件 src/main/resources/org/netbeans/modules/java/editor/resources/fontsColors.xml 中,我在 mod-public 中添加了一个属性 foreColor="blue" 以尝试将关键字 public 突出显示为 blue :
<fontcolor name="mod-public" foreColor="blue" />
我还修改了同一目录下的 fontsColors-highlighting.xml 文件,现在看起来像这样:
<fontscolors>
<fontcolor name="remove-surround-code-delete" foreColor="ffB4B4B4" bgColor="ffF5F5F5"/>
<fontcolor name="remove-surround-code-remain" bgColor="ffCCFFCC"/>
<fontcolor name="mod-public" foreColor="blue" />
</fontscolors>
我在这里遗漏了什么?
解决方法
答案在这里:
文档可以通过做来定义顶级语言 doc.putProperty("mimeType",mimeType)(为 将搜索和使用给定的 mime 类型)或通过执行 putProperty(Language.class,语言)。否则返回 层次结构将处于非活动状态,而 TokenHierarchy.tokenSequence() 将 返回空。
而这个 TokenHierarchy.get(doc) 在 SyntaxHighlighting 的构造函数中被调用:
/** Creates a new instance of SyntaxHighlighting */
public SyntaxHighlighting(Document document) {
this.document = document;
String mimeType = (String) document.getProperty("mimeType"); //NOI18N
if (mimeType != null && mimeType.startsWith("test")) { //NOI18N
this.mimeTypeForOptions = mimeType;
} else {
this.mimeTypeForOptions = null;
}
// Start listening on changes in global colorings since they may affect colorings for target language
findFCSInfo("",null);
hierarchy = TokenHierarchy.get(document);
hierarchy.addTokenHierarchyListener(WeakListeners.create(TokenHierarchyListener.class,this,hierarchy));
}
然而,仅仅设置 mime 类型对我不起作用。 这对我有用:
doc.putProperty(Language.class,JavaTokenId.language());
也不需要标记,netbeans 库完成了所有工作,代码简化为以下内容:
public void doSyntaxColoring(String fileName) {
JFrame f = new JFrame("JAVA Syntax Coloring");
DefaultStyledDocument doc = new DefaultStyledDocument();
doc.putProperty(Language.class,JavaTokenId.language());
JEditorPane pane = new JEditorPane();
pane.setEditorKit(CloneableEditorSupport.getEditorKit(JavaKit.JAVA_MIME_TYPE));
pane.setDocument(doc);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try (FileReader fileReader = new FileReader(fileName)) {
String text = IOUtils.toString(fileReader);
// Add the text to the document
doc.insertString(0,text,null);
} catch (BadLocationException | IOException e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
System.out.println("Exception when constructing document: " + e);
System.exit(1);
}
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(pane));
f.setSize(400,300);
f.setVisible(true);
}
和 gradle 构建文件:
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation files("${System.properties['java.home']}/../lib/tools.jar")
implementation 'org.netbeans.modules:org-netbeans-modules-java-editor:RELEASE123'
implementation 'org.netbeans.modules:org-netbeans-modules-editor-mimelookup-impl:RELEASE123'
implementation 'org.apache.commons:commons-lang3:3.10'
implementation 'commons-io:commons-io:2.8.0'
}
也不需要在资源文件中做任何事情(除非可能是为了颜色改变)