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 61968939..ee6fb0f7 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 @@ -1,10 +1,7 @@ package org.fxmisc.richtext.demo; -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; @@ -20,13 +17,9 @@ 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.Paragraph; 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 { @@ -118,12 +111,7 @@ public void start(Stage primaryStage) { // run: `cleanupWhenNoLongerNeedIt.unsubscribe();` */ // recompute syntax highlighting only for visible paragraph changes - // Note that this shows how it can be done but is not recommended for production where multi- - // line syntax requirements are needed, like comment blocks without a leading * on each line. - codeArea.getVisibleParagraphs().addModificationObserver - ( - new VisibleParagraphStyler<>( codeArea, this::computeHighlighting ) - ); + codeArea.setVisibleOnlyStyler( (pNo,p) -> p.restyle(0, computeHighlighting(pNo, p.getText())) ); // auto-indent: insert previous line's indents on enter final Pattern whiteSpace = Pattern.compile( "^\\s+" ); @@ -147,11 +135,10 @@ public void start(Stage primaryStage) { primaryStage.show(); } - private StyleSpans> computeHighlighting(String text) { + private StyleSpans> computeHighlighting(Integer paragraphNo, String text) { Matcher matcher = PATTERN.matcher(text); int lastKwEnd = 0; - StyleSpansBuilder> spansBuilder - = new StyleSpansBuilder<>(); + StyleSpansBuilder> spansBuilder = new StyleSpansBuilder<>(); while(matcher.find()) { String styleClass = matcher.group("KEYWORD") != null ? "keyword" : @@ -170,40 +157,6 @@ private StyleSpans> computeHighlighting(String text) { 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 ) Platform.runLater( () -> - { - int paragraph = Math.min( area.firstVisibleParToAllParIndex() + lm.getFrom(), area.getParagraphs().size()-1 ); - String text = area.getText( paragraph, 0, paragraph, area.getParagraphLength( paragraph ) ); - - if ( paragraph != prevParagraph || text.length() != prevTextLength ) - { - if ( paragraph < area.getParagraphs().size()-1 ) - { - int startPos = area.getAbsolutePosition( paragraph, 0 ); - area.setStyleSpans( startPos, computeStyles.apply( text ) ); - } - prevTextLength = text.length(); - prevParagraph = paragraph; - } - }); - } - } - private class DefaultContextMenu extends ContextMenu { private MenuItem fold, unfold, print; diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java b/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java index 61453458..3f028e75 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java @@ -778,9 +778,9 @@ public GenericStyledArea( // Initialize content virtualFlow = VirtualFlow.createVertical( getParagraphs(), - par -> { + (index, par) -> { Cell, ParagraphBox> cell = createCell( - par, + index, par, applyParagraphStyle, nodeFactory); nonEmptyCells.add(cell.getNode()); @@ -1548,6 +1548,24 @@ public final PS getParagraphStyleForInsertionAt(int pos) { } } + private BiFunction,Paragraph> visibleOnlyStyler; + /** + * This styler will only be applied to visible Paragraphs, just before being displayed. + *

Important Notes

+ *
    + *
  1. The result of this styling does NOT modify the document model. + *
  2. Paragraph is immutable, so don't return the same object expecting changes. + *
  3. The styler should return the result of one of Paragraph's restyle methods. + *
+ */ + public void setVisibleOnlyStyler(BiFunction,Paragraph> styler) { + visibleOnlyStyler = styler; + } + + public void refreshParagraphs(int paragraphStart, int paragraphEnd) { + virtualFlow.refreshCells(paragraphStart, paragraphEnd); + } + @Override public void replaceText(int start, int end, String text) { StyledDocument doc = ReadOnlyStyledDocument.fromString( @@ -1910,10 +1928,11 @@ ParagraphBox.CaretOffsetX getTargetCaretOffset() { * ********************************************************************** */ private Cell, ParagraphBox> createCell( - Paragraph paragraph, + Integer index, Paragraph paragraph, BiConsumer applyParagraphStyle, Function, Node> nodeFactory) { + if (visibleOnlyStyler != null) paragraph = visibleOnlyStyler.apply(index, paragraph); ParagraphBox box = new ParagraphBox<>(paragraph, applyParagraphStyle, nodeFactory); box.highlightTextFillProperty().bind(highlightTextFill);