package example;
//-*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
//@homepage@
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

public final class MainPanel extends JPanel {
    private MainPanel() {
        super(new BorderLayout());
        JTextPane textPane = new JTextPane(new SimpleSyntaxDocument());
        textPane.setText("red green, blue. red-green;bleu.");
        add(new JScrollPane(textPane));
        setPreferredSize(new Dimension(320, 240));
    }
    public static void main(String... args) {
        EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException
               | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        }
        JFrame frame = new JFrame("@title@");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.getContentPane().add(new MainPanel());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

//This code is taken from: SyntaxDocument.java, MultiSyntaxDocument.java
// Fast styled JTextPane editor | Oracle Community
// @author camickr
// @author David Underhill
// https://community.oracle.com/thread/2105230
class SimpleSyntaxDocument extends DefaultStyledDocument {
    //HashMap<String, AttributeSet> keywords = new HashMap<>();
    private final Style normal; //MutableAttributeSet normal = new SimpleAttributeSet();
    private static final String OPERANDS = ".,";
    public SimpleSyntaxDocument() {
        super();
        Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
        normal = addStyle("normal", def);
        StyleConstants.setForeground(normal, Color.BLACK);
        StyleConstants.setForeground(addStyle("red",   normal), Color.RED);
        StyleConstants.setForeground(addStyle("green", normal), Color.GREEN);
        StyleConstants.setForeground(addStyle("blue",  normal), Color.BLUE);
    }
    @Override public void insertString(int offset, String str, AttributeSet a) throws BadLocationException {
        super.insertString(offset, str, a);
        processChangedLines(offset, str.length());
    }
    @Override public void remove(int offset, int length) throws BadLocationException {
        super.remove(offset, length);
        processChangedLines(offset, 0);
    }
    private void processChangedLines(int offset, int length) throws BadLocationException {
        Element root = getDefaultRootElement();
        String content = getText(0, getLength());
        int startLine = root.getElementIndex(offset);
        int endLine = root.getElementIndex(offset + length);
        for (int i = startLine; i <= endLine; i++) {
            applyHighlighting(content, i);
        }
    }
    private void applyHighlighting(String content, int line) throws BadLocationException {
        Element root = getDefaultRootElement();
        int startOffset   = root.getElement(line).getStartOffset();
        int endOffset     = root.getElement(line).getEndOffset() - 1;
        int lineLength    = endOffset - startOffset;
        int contentLength = content.length();
        if (endOffset >= contentLength) {
            endOffset = contentLength - 1;
        }
        setCharacterAttributes(startOffset, lineLength, normal, true);
        checkForTokens(content, startOffset, endOffset);
    }
    private void checkForTokens(String content, int startOffset, int endOffset) {
        int index = startOffset;
        while (index <= endOffset) {
            while (isDelimiter(content.substring(index, index + 1))) {
                if (index < endOffset) {
                    index++;
                } else {
                    return;
                }
            }
            index = getOtherToken(content, index, endOffset);
        }
    }
    private int getOtherToken(String content, int startOffset, int endOffset) {
        int endOfToken = startOffset + 1;
        while (endOfToken <= endOffset) {
            if (isDelimiter(content.substring(endOfToken, endOfToken + 1))) {
                break;
            }
            endOfToken++;
        }
        String token = content.substring(startOffset, endOfToken);
        Style s = getStyle(token);
        //if (keywords.containsKey(token)) {
        //    setCharacterAttributes(startOffset, endOfToken - startOffset, keywords.get(token), false);
        if (s != null) {
            setCharacterAttributes(startOffset, endOfToken - startOffset, s, false);
        }
        return endOfToken + 1;
    }
    protected boolean isDelimiter(String character) {
        return Character.isWhitespace(character.charAt(0)) || OPERANDS.indexOf(character) != -1;
    }
}

@@ -1522,16 +1522,57 @@
 2105230%0A
+// modified by aterai aterai@outlook.com%0A
 class Si
@@ -2835,58 +2835,8 @@
 ();%0A
-        String content = getText(0, getLength());%0A
     
@@ -2963,17 +2963,20 @@
 or (int 
-i
+line
  = start
@@ -2981,17 +2981,20 @@
 rtLine; 
-i
+line
  %3C= endL
@@ -2998,17 +2998,20 @@
 ndLine; 
-i
+line
 ++) %7B%0A  
@@ -3038,26 +3038,20 @@
 ighting(
-content, i
+line
 );%0A     
@@ -3096,32 +3096,16 @@
 ighting(
-String content, 
 int line
@@ -3407,17 +3407,12 @@
 h = 
-content.l
+getL
 engt
@@ -3605,25 +3605,16 @@
 rTokens(
-content, 
 startOff
@@ -3668,32 +3668,16 @@
 rTokens(
-String content, 
 int star
@@ -3691,32 +3691,60 @@
 , int endOffset)
+ throws BadLocationException
  %7B%0A        int i
@@ -3835,40 +3835,22 @@
 ter(
-content.substring(index, index +
+getText(index,
  1))
@@ -4042,25 +4042,16 @@
 erToken(
-content, 
 index, e
@@ -4111,24 +4111,8 @@
 ken(
-String content, 
 int 
@@ -4130,32 +4130,60 @@
 , int endOffset)
+ throws BadLocationException
  %7B%0A        int e
@@ -4285,50 +4285,27 @@
 ter(
-content.substring(endOfToken, endOfToken +
+getText(endOfToken,
  1))
@@ -4408,25 +4408,15 @@
 n = 
-content.substring
+getText
 (sta
@@ -4431,24 +4431,38 @@
 , endOfToken
+ - startOffset
 );%0A        S

use AbstractDocument#getText(int,int) instead of AbstractDocument#getText(0,getLength()).substring(int,int)