【问题标题】:How do I apply styles to do syntax coloring in a JEditorPane with Netbeans Java editor kit (Javakit)?如何使用 Netbeans Java 编辑器工具包 (Javakit) 在 JEditorPane 中应用样式进行语法着色?
【发布时间】:2021-07-05 18:14:41
【问题描述】:

我想在已经配备了 Netbeans Java 编辑器工具包(类 org.netbeans.modules.editor.java.JavaKit)的 JEditorPane 中实现语法着色。我注意到,当 JEditorPane 具有 RTF 编辑器工具包时,关键字是彩色的(请参阅此问题并回答 https://stackoverflow.com/a/67025502/8315843)。问题是 Netbeans 有一个有趣的组件,称为 diff 视图,我想使用它,并且该 diff 视图使用两个 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'
}

我一直在努力尝试使用基于词法分析器的语法荧光笔,但我不知道如何使用,我只能猜测如何使用它,如下所示,但我就是不明白它是怎么用的t 只是天生的。在 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, text, 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 突出显示为蓝色:

<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>

我在这里错过了什么?

【问题讨论】:

    标签: java swing syntax-highlighting lexer netbeans-platform


    【解决方案1】:

    答案就在这里:

    https://bits.netbeans.org/dev/javadoc/org-netbeans-modules-lexer/org/netbeans/api/lexer/TokenHierarchy.html

    文档可以通过以下方式定义顶级语言 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'
    }
    

    也不需要在资源文件中做任何事情(除非可能改变颜色)

    【讨论】:

      猜你喜欢
      • 2012-05-29
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 2011-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      相关资源
      最近更新 更多