org.fxmisc.richtext.demo.TextArea4Java Maven / Gradle / Ivy
package org.fxmisc.richtext.demo;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.time.Duration;
import javafx.beans.value.ChangeListener;
import javafx.concurrent.Task;
import org.fxmisc.richtext.LineNumberFactory;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;
import com.sta.mlogger.MLogger;
/**
* Name: TextArea4Java
* Description: .
*
* Comment: ...
*
* Copyright: Copyright (c) 2018, 2019
* Company: >StA-Soft<
* @author StA
* @version 1.0
*/
public class TextArea4Java extends TextAreaBase
{
private static final String[] KEYWORDS = new String[]{
"abstract", "assert", "boolean", "break", "byte",
"case", "catch", "char", "class", "const",
"continue", "default", "do", "double", "else",
"enum", "extends", "false", "final", "finally", "float",
"for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native",
"new", "null", "package", "private", "protected", "public",
"return", "short", "static", "strictfp", "super",
"switch", "synchronized", "this", "throw", "throws",
"transient", "true", "try", "void", "volatile", "while"
};
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
private static final String PAREN_PATTERN = "\\(|\\)";
private static final String BRACE_PATTERN = "\\{|\\}";
private static final String BRACKET_PATTERN = "\\[|\\]";
private static final String SEMICOLON_PATTERN = ";";
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
private static final String CHAR_PATTERN = "\'([^\'\\\\]|\\\\.)*\'";
private static final String NUMBER_PATTERN = "\\b(\\d+|0x[0-9a-fA-F]+)\\b";
private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";
private static final String ANNOTATION_PATTERN = "\\@\\w+";
private static final Pattern PATTERN = Pattern.compile(
"(?" + KEYWORD_PATTERN + ")|" +
"(?" + PAREN_PATTERN + ")|" +
"(?" + BRACE_PATTERN + ")|" +
"(?" + BRACKET_PATTERN + ")|" +
"(?" + SEMICOLON_PATTERN + ")|" +
"(?" + STRING_PATTERN + ")|" +
"(?" + CHAR_PATTERN + ")|" +
"(?" + NUMBER_PATTERN + ")|" +
"(?" + COMMENT_PATTERN + ")|" +
"(?" + ANNOTATION_PATTERN + ")"
);
//===========================================================================
private static StyleSpans> computeHighlighting(String text)
{
Matcher matcher = PATTERN.matcher(text);
int lastKwEnd = 0;
StyleSpansBuilder> spansBuilder = new StyleSpansBuilder<>();
while (matcher.find())
{
String styleClass =
matcher.group("KEYWORD") != null ? "keyword" :
matcher.group("PAREN") != null ? "paren" :
matcher.group("BRACE") != null ? "brace" :
matcher.group("BRACKET") != null ? "bracket" :
matcher.group("SEMICOLON") != null ? "semicolon" :
matcher.group("STRING") != null ? "string" :
matcher.group("CHAR") != null ? "character" :
matcher.group("NUMBER") != null ? "number" :
matcher.group("COMMENT") != null ? "comment" :
matcher.group("ANNOTATION") != null ? "annotation" :
null; /* never happens */
assert styleClass != null;
spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
lastKwEnd = matcher.end();
}
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
return spansBuilder.create();
}
//===========================================================================
public TextArea4Java(boolean sync)
{
super();
init(sync);
}
public TextArea4Java(boolean sync, String text)
{
super(text);
init(sync);
}
public TextArea4Java(boolean sync, ChangeListener cl)
{
super(cl);
init(sync);
}
//===========================================================================
private void init(boolean sync)
{
setParagraphGraphicFactory(LineNumberFactory.get(this));
if (sync)
{
initSync();
}
else
{
initASync();
}
getStylesheets().add(getClass().getResource("java-keywords.css").toExternalForm());
}
private void initSync()
{
richChanges()
.filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
.subscribe(change ->
{
setStyleSpans(0, computeHighlighting(getText()));
});
}
private void initASync()
{
richChanges()
.filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
.successionEnds(Duration.ofMillis(500))
.supplyTask(this::computeHighlightingAsync)
.awaitLatest(richChanges())
.filterMap(t ->
{
if (t.isSuccess())
{
return Optional.of(t.get());
}
else
{
MLogger.err("", t.getFailure());
return Optional.empty();
}
})
.subscribe(this::applyHighlighting);
}
private Task>> computeHighlightingAsync()
{
String text = getText();
Task>> task = new Task>>()
{
@Override
protected StyleSpans> call() throws Exception
{
return computeHighlighting(text);
}
};
ExecutorHelper.getExecutor().execute(task);
return task;
}
private void applyHighlighting(StyleSpans> highlighting)
{
setStyleSpans(0, highlighting);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy