/*
 * Copyright (c) 2013, Tomas Mikula. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package codearea.demo;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import codearea.control.CodeArea;

public class JavaKeywords extends Application {

    private static final String[] KEYWORDS = new String[] {
            "abstract", "assert", "boolean", "break", "byte",
            "case", "catch", "char", "class", "const",
            "continue", "default", "do", "double", "else",
            "enum", "extends", "final", "finally", "float",
            "for", "goto", "if", "implements", "import",
            "instanceof", "int", "interface", "long", "native",
            "new", "package", "private", "protected", "public",
            "return", "short", "static", "strictfp", "super",
            "switch", "synchronized", "this", "throw", "throws",
            "transient", "try", "void", "volatile", "while"
    };

    private static final Pattern KEYWORD_PATTERN = Pattern.compile("\\b(" + String.join("|", KEYWORDS) + ")\\b");

    private static final String sampleCode = String.join("\n", new String[] {
        "package com.example;",
        "",
        "import java.util.*;",
        "",
        "public class Foo extends Bar implements Baz {",
        "",
        "   public static void main(String[] args) {",
        "       for(String arg: args) {",
        "           if(arg.length() != 0)",
        "               System.out.println(arg);",
        "           else",
        "               System.err.println(\"Warning: empty string as argument\");",
        "       }",
        "   }",
        "",
        "}"
    });


    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        final CodeArea codeArea = new CodeArea();
        codeArea.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable,
                    String oldText, String newText) {
                Matcher matcher = KEYWORD_PATTERN.matcher(newText);
                int lastKwEnd = 0;
                while(matcher.find()) {
                    codeArea.clearStyle(lastKwEnd, matcher.start());
                    codeArea.setStyleClass(matcher.start(), matcher.end(), "keyword");
                    lastKwEnd = matcher.end();
                }
                codeArea.clearStyle(lastKwEnd, newText.length());
            }
        });
        codeArea.replaceText(0, 0, sampleCode);

        StackPane root = new StackPane();
        root.getChildren().add(codeArea);
        Scene scene = new Scene(root, 600, 400);
        scene.getStylesheets().add(JavaKeywords.class.getResource("java-keywords.css").toExternalForm());
        primaryStage.setScene(scene);
        codeArea.requestFocus();
        primaryStage.show();
    }

}

@@ -1209,16 +1209,75 @@
 .demo;%0A%0A
+import java.util.Collection;%0Aimport java.util.Collections;%0A
 import j
@@ -1582,16 +1582,59 @@
 odeArea;
+%0Aimport codearea.control.StyleSpansBuilder;
 %0A%0Apublic
@@ -3589,16 +3589,136 @@
 nd = 0;%0A
+                StyleSpansBuilder%3CCollection%3CString%3E%3E spansBuilder%0A                        = new StyleSpansBuilder%3C%3E();%0A
         
@@ -3773,37 +3773,48 @@
     
-codeArea.clearStyle(lastKwEnd
+spansBuilder.add(Collections.emptyList()
 , ma
@@ -3826,16 +3826,28 @@
 .start()
+ - lastKwEnd
 );%0A     
@@ -3865,72 +3865,90 @@
     
-codeArea.setStyleClass(matcher.start(), matcher.end(), %22keyword%22
+spansBuilder.add(Collections.singleton(%22keyword%22), matcher.end() - matcher.start()
 );%0A 
@@ -4031,53 +4031,142 @@
     
-codeArea.clearStyle(lastKwEnd, newText.length
+spansBuilder.add(Collections.emptyList(), newText.length() - lastKwEnd);%0A                codeArea.setStyleSpans(0, spansBuilder.create
 ());

Use setStyleSpans in JavaKeywords demo.