Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It's possible to fill paragraph's background? #254

Closed
RodrigoSantiago opened this issue Feb 16, 2016 · 12 comments
Closed

It's possible to fill paragraph's background? #254

RodrigoSantiago opened this issue Feb 16, 2016 · 12 comments

Comments

@RodrigoSantiago
Copy link

Some text editors fill all line where the caret is, or IDEs in 'wrong syntax' with red.

@TomasMikula
Copy link
Member

It is possible to fill background of a paragraph.

area.setParagraphStyle(parIndex, style);

What style is depends on what your representation of paragraph style is, i.e. what the PS type parameter is in the definition of StyledTextArea. If, for example, you have an InlineCssTextArea, then PS is a CSS string, so it could be "-fx-background-color: #f2f9fc;". If you have a StyleClassedTextArea, then PS is a collection of strings (style classes), so style could be Collections.singletonList("has-caret"), and then in your stylesheet you would have

text-flow.has-caret {
    -fx-background-color: #f2f9fc;
}

You still need to handle changes of the current line (area.currentParagraphProperty()) yourself and de-highlight/highlight appropriately.


Since this could be a common use case, I can imagine StyledTextArea would automatically set a pseudo-class, such as :has-caret, to the paragraph with the caret. Then all you need to do would be just

text-flow:has-caret {
    -fx-background-color: #f2f9fc;
}

in your stylesheet.

@RodrigoSantiago
Copy link
Author

Thank you. For some reason, in the version I use, the method setParagraphStyle (parIndex, style) did not exist.

@TomasMikula
Copy link
Member

If you try the snapshot release, you can now use the :has-caret pseudo class on .paragraph-box. I added this behavior to the JavaKeywords demo.

If you are now working with the 0.6.10 version, be prepared that there will be some backwards incompatible changes in 0.7, so be prepared that you might have to modify your source code.

@iazarny
Copy link

iazarny commented Dec 7, 2016

It works using css, but does not works if need to highlight paragraph programmatically in 0.7 M2

 CodeArea codeArea = new CodeArea();
//... skipped
codeArea.setParagraphStyle(12, Collections.singleton("-fx-background-color: red;"));

@JordanMartinez
Copy link
Contributor

@iazarny Are you sure? Your example isn't using the right CSS as explained in the CSS Ref Guide. Did you try -rtfx-background-color: red;?

@iazarny
Copy link

iazarny commented Dec 7, 2016

@JordanMartinez Yes, I try , but result still the same - particular paragraph not highlighted.

@JordanMartinez
Copy link
Contributor

Ok. Thanks for the update. This issue might be fixed by #398.

@JFormDesigner
Copy link
Contributor

@iazarny class CodeArea expects CSS classes as styles

@iazarny
Copy link

iazarny commented Dec 13, 2016

@JFormDesigner result is very funny , works very unstable .

codeArea.setParagraphStyle(12, Collections.singleton("testCssClass"));
.testCssClass { -fx-background-color: red; -rtfx-background-color: red; }

Together with syntax highlighting may lead to stack overflow

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774) at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657) at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49) at javafx.event.Event.fireEvent(Event.java:198) at javafx.scene.control.MenuItem.fire(MenuItem.java:462) at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1405) at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(ContextMenuContent.java:1358) at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218) at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238) at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191) at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56) at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114) at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74) at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54) at javafx.event.Event.fireEvent(Event.java:198) at javafx.scene.Scene$MouseHandler.process(Scene.java:3757) at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380) at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416) at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415) at com.sun.glass.ui.View.handleMouseEvent(View.java:555) at com.sun.glass.ui.View.notifyMouse(View.java:937) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71) at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275) at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1769) ... 43 more Caused by: java.lang.StackOverflowError at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717) at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568) at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777) at java.util.regex.Pattern$Branch.match(Pattern.java:4604) at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658) at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4847) at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717) at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568) at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777) at java.util.regex.Pattern$Branch.match(Pattern.java:4604) at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658) at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4847)

@JordanMartinez
Copy link
Contributor

@iazarny Can you post a small demo that reproduces the issue?

@iazarny
Copy link

iazarny commented Dec 14, 2016

My first assumptions was wrong, it related not to paragraph highlighting, but to syntax highlighting. Long comments. Modified JavaKeywords provided
`
import java.util.Collection;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;

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 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 COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/";

private static final Pattern PATTERN = Pattern.compile(
        "(?<KEYWORD>" + KEYWORD_PATTERN + ")"
                + "|(?<PAREN>" + PAREN_PATTERN + ")"
                + "|(?<BRACE>" + BRACE_PATTERN + ")"
                + "|(?<BRACKET>" + BRACKET_PATTERN + ")"
                + "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
                + "|(?<STRING>" + STRING_PATTERN + ")"
                + "|(?<COMMENT>" + COMMENT_PATTERN + ")"
);



private static final String sampleCode = String.join("\n", new String[] {
                "node {\n" +
                "    /*stage('Build') {\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "        string string string string string string string string string string string string string string string string string string string string string string string string string string \"\n" +
                "    }*/\n" +
                "}"
});


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

@Override
public void start(Stage primaryStage) {
    CodeArea codeArea = new CodeArea();
    codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));

    codeArea.richChanges()
            .filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX
            .subscribe(change -> {
                codeArea.setStyleSpans(0, computeHighlighting(codeArea.getText()));
            });
    codeArea.replaceText(0, 0, sampleCode);

    Scene scene = new Scene(new StackPane(new VirtualizedScrollPane<>(codeArea)), 600, 400);
    scene.getStylesheets().add(JavaKeywords.class.getResource("/styles/java-keywords.css").toExternalForm());
    primaryStage.setScene(scene);
    primaryStage.setTitle("Java Keywords Demo");
    primaryStage.show();
}

private static StyleSpans<Collection<String>> computeHighlighting(String text) {
    Matcher matcher = PATTERN.matcher(text);
    int lastKwEnd = 0;
    StyleSpansBuilder<Collection<String>> 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("COMMENT") != null ? "comment" :
                                                                        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();
}

}

`

@JordanMartinez
Copy link
Contributor

@iazarny The code works if only 5 lines of your "string string string" text are left uncommented out. As soon as I uncomment the 6th line, I get this error

Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
	at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.StackOverflowError
	at java.lang.Character.codePointAt(Character.java:4866)
	at java.util.regex.Pattern$CharProperty.match(Pattern.java:3775)
	at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
	at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
	at java.util.regex.Pattern$LazyLoop.match(Pattern.java:4847)
	at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
	at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
	at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
	at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
	at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants