diff --git a/richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/JavaKeywordsDemo.java b/richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/JavaKeywordsDemo.java index 9b2af293b..e6a2bcbef 100644 --- a/richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/JavaKeywordsDemo.java +++ b/richtextfx-demos/src/main/java/org/fxmisc/richtext/demo/JavaKeywordsDemo.java @@ -3,6 +3,8 @@ import java.time.Duration; import java.util.Collection; import java.util.Collections; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -16,9 +18,11 @@ import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.richtext.CodeArea; +import org.fxmisc.richtext.GenericStyledArea; import org.fxmisc.richtext.LineNumberFactory; import org.fxmisc.richtext.model.StyleSpans; import org.fxmisc.richtext.model.StyleSpansBuilder; +import org.reactfx.collection.ListModification; import org.reactfx.Subscription; public class JavaKeywordsDemo extends Application { @@ -88,8 +92,8 @@ public void start(Stage primaryStage) { // add line numbers to the left of area codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea)); - - // recompute the syntax highlighting 500 ms after user stops editing area +/* + // recompute the syntax highlighting for all text, 500 ms after user stops editing area Subscription cleanupWhenNoLongerNeedIt = codeArea // plain changes = ignore style changes that are emitted when syntax highlighting is reapplied @@ -105,7 +109,12 @@ public void start(Stage primaryStage) { // when no longer need syntax highlighting and wish to clean up memory leaks // run: `cleanupWhenNoLongerNeedIt.unsubscribe();` - +*/ + // recompute syntax highlighting only for visible paragraph changes + codeArea.getVisibleParagraphs().addModificationObserver + ( + new VisibleParagraphStyler<>( codeArea, this::computeHighlighting ) + ); // auto-indent: insert previous line's indents on enter final Pattern whiteSpace = Pattern.compile( "^\\s+" ); @@ -129,7 +138,7 @@ public void start(Stage primaryStage) { primaryStage.show(); } - private static StyleSpans> computeHighlighting(String text) { + private StyleSpans> computeHighlighting(String text) { Matcher matcher = PATTERN.matcher(text); int lastKwEnd = 0; StyleSpansBuilder> spansBuilder @@ -151,4 +160,36 @@ private static StyleSpans> computeHighlighting(String text) { spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd); return spansBuilder.create(); } + + private class VisibleParagraphStyler implements Consumer + { + private final GenericStyledArea area; + private final Function> computeStyles; + private int prevParagraph, prevTextLength; + + public VisibleParagraphStyler( GenericStyledArea area, Function> computeStyles ) + { + this.computeStyles = computeStyles; + this.area = area; + } + + @Override + public void accept( ListModification lm ) + { + if ( lm.getAddedSize() > 0 ) + { + int paragraph = area.visibleParToAllParIndex( lm.getFrom() ); + String text = area.getText( paragraph, 0, paragraph, area.getParagraphLength( paragraph ) ); + + if ( paragraph != prevParagraph || text.length() != prevTextLength ) + { + int startPos = area.getAbsolutePosition( paragraph, 0 ); + Platform.runLater( () -> area.setStyleSpans( startPos, computeStyles.apply( text ) ) ); + prevTextLength = text.length(); + prevParagraph = paragraph; + } + } + } + } + }