Improve syntax highlighting internals

This commit is contained in:
Clément Fournier
2017-09-28 21:20:41 +02:00
parent 3f503e9f7d
commit 1de1633587
7 changed files with 115 additions and 80 deletions

View File

@ -288,7 +288,7 @@ public class DesignerWindowPresenter {
}
});
view.getXpathExpressionArea().setSyntaxHighlightingEnabled(XPathSyntaxHighlighter.INSTANCE);
view.getXpathExpressionArea().setSyntaxHighlightingEnabled(new XPathSyntaxHighlighter());
}

View File

@ -20,22 +20,22 @@ import net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.XmlS
* @since 6.0.0
*/
public enum AvailableSyntaxHighlighters {
JAVA("java", JavaSyntaxHighlighter.INSTANCE),
APEX("apex", ApexSyntaxHighlighter.INSTANCE),
XML("xml", XmlSyntaxHighlighter.INSTANCE),
XSL("xsl", XmlSyntaxHighlighter.INSTANCE),
WSDL("wsdl", XmlSyntaxHighlighter.INSTANCE),
POM("pom", XmlSyntaxHighlighter.INSTANCE),
XPATH("xpath", XPathSyntaxHighlighter.INSTANCE);
JAVA("java", new JavaSyntaxHighlighter()),
APEX("apex", new ApexSyntaxHighlighter()),
XML("xml", new XmlSyntaxHighlighter()),
XSL("xsl", new XmlSyntaxHighlighter()),
WSDL("wsdl", new XmlSyntaxHighlighter()),
POM("pom", new XmlSyntaxHighlighter()),
XPATH("xpath", new XPathSyntaxHighlighter());
private final String language;
private final SyntaxHighlighter computer;
private final SyntaxHighlighter engine;
AvailableSyntaxHighlighters(String languageTerseName, SyntaxHighlighter computer) {
AvailableSyntaxHighlighters(String languageTerseName, SyntaxHighlighter engine) {
this.language = languageTerseName;
this.computer = computer;
this.engine = engine;
}
@ -51,7 +51,7 @@ public enum AvailableSyntaxHighlighters {
.filter(e -> e.language.equals(language.getTerseName()))
.findFirst();
if (found.isPresent()) {
return found.get().computer;
return found.get().engine;
} else {
return null;
}

View File

@ -18,24 +18,31 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SpanBound;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlighter;
import javafx.concurrent.Task;
/**
* Language specific engine for syntax highlighting.
* Language-specific engine for syntax highlighting. The highlighter assigns classes to
*
* @author Clément Fournier
* @since 6.0.0
*/
public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
public abstract class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
private final Pattern pattern;
private final Map<String, String> namesToCssClass;
private final RegexHighlightGrammar grammar;
private final String languageName;
protected SimpleRegexSyntaxHighlighter(String languageName, Pattern pattern, Map<String, String> namesToCssClass) {
this.pattern = pattern;
this.namesToCssClass = namesToCssClass;
/**
* Creates a highlighter given a name for the language and a "regex grammar".
*
* @param languageName The language name
* @param grammar The grammar
*/
protected SimpleRegexSyntaxHighlighter(String languageName, final RegexHighlightGrammar grammar) {
this.grammar = grammar;
this.languageName = languageName;
}
@ -57,12 +64,12 @@ public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
private List<SpanBound> computeHighlighting(String text) {
List<SpanBound> updated = new ArrayList<>();
Matcher matcher = pattern.matcher(text);
Matcher matcher = grammar.getPattern().matcher(text);
int lastKwEnd = 0;
try {
while (matcher.find()) {
String styleClass = getCssClassOfLastGroup(matcher);
String styleClass = grammar.getCssClassOfLastGroup(matcher);
updated.add(new SpanBound(lastKwEnd, Collections.singleton(languageName), true));
updated.add(new SpanBound(matcher.start(), Collections.emptySet(), false));
updated.add(new SpanBound(matcher.start(), new HashSet<>(Arrays.asList(languageName, styleClass)), true));
@ -76,37 +83,32 @@ public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
}
private String getCssClassOfLastGroup(Matcher matcher) {
for (Entry<String, String> groupToClass : namesToCssClass.entrySet()) {
if (matcher.group(groupToClass.getKey()) != null) {
return groupToClass.getValue();
}
}
return "";
}
@Override
public final String getLanguageTerseName() {
return languageName;
}
public static RegexHighlighterBuilder builder(String languageName, String cssClass, String pattern) {
return new RegexHighlighterBuilder(languageName, cssClass, pattern);
/**
* Gets a builder to make a grammar to build a highlighter.
*
* @param cssClass The css class of the first pattern
* @param pattern The first pattern
*
* @return A builder
*/
protected static RegexHighlightGrammarBuilder grammarBuilder(String cssClass, String pattern) {
return new RegexHighlightGrammarBuilder(cssClass, pattern);
}
public static class RegexHighlighterBuilder {
protected static class RegexHighlightGrammarBuilder {
private final String language;
private Map<String, String> regexToClasses = new LinkedHashMap<>();
RegexHighlighterBuilder(String languageName, String cssClass, String regex) {
RegexHighlightGrammarBuilder(String cssClass, String regex) {
or(cssClass, regex);
language = languageName;
}
@ -118,7 +120,7 @@ public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
*
* @return The same builder
*/
public RegexHighlighterBuilder or(String cssClass, String regex) {
public RegexHighlightGrammarBuilder or(String cssClass, String regex) {
regexToClasses.put(regex, cssClass);
return this;
}
@ -135,7 +137,6 @@ public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
private String getRegexString() {
return String.join("|",
regexToClasses.entrySet()
.stream()
@ -144,24 +145,27 @@ public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
}
public SyntaxHighlighter create() {
return new SimpleRegexSyntaxHighlighter(language,
Pattern.compile(getRegexString()),
getGroupNamesToCssClasses());
/**
* Builds the grammar.
*
* @return A new grammar
*/
public RegexHighlightGrammar create() {
return new RegexHighlightGrammar(Pattern.compile(getRegexString()),
getGroupNamesToCssClasses());
}
/**
* Builds the syntax highlighter.
* Builds the grammar.
*
* @param flags Regex compilation flags
*
* @return A new highlighter
* @return A new grammar
*/
public SyntaxHighlighter create(int flags) {
return new SimpleRegexSyntaxHighlighter(language,
Pattern.compile(getRegexString(), flags),
getGroupNamesToCssClasses());
public RegexHighlightGrammar create(int flags) {
return new RegexHighlightGrammar(Pattern.compile(getRegexString(), flags),
getGroupNamesToCssClasses());
}
@ -176,4 +180,48 @@ public class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter {
}
}
/**
* Describes the tokens of the language that should be colored with a regular expression.
*/
protected static class RegexHighlightGrammar {
private final Pattern pattern;
private final Map<String, String> namesToCssClass;
public RegexHighlightGrammar(Pattern pattern, Map<String, String> namesToCssClass) {
this.pattern = pattern;
this.namesToCssClass = namesToCssClass;
}
/**
* Pattern describing the tokens.
*
* @return The pattern
*/
public Pattern getPattern() {
return pattern;
}
/**
* Gets the css class that should be applied to the last matched group (token), according to this grammar.
*
* @param matcher The matcher in which to look
*
* @return The name of the css class corresponding to the token
*/
public String getCssClassOfLastGroup(Matcher matcher) {
for (Entry<String, String> groupToClass : namesToCssClass.entrySet()) {
if (matcher.group(groupToClass.getKey()) != null) {
return groupToClass.getValue();
}
}
return "";
}
}
}

View File

@ -4,11 +4,9 @@
package net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting;
import java.util.Map;
import java.util.regex.Pattern;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlighter;
/**
* Syntax highlighter for Apex.
@ -46,9 +44,8 @@ public class ApexSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
};
public static final SyntaxHighlighter INSTANCE
= builder("apex",
"single-line-comment", "//[^\r\n]*")
public static final RegexHighlightGrammar GRAMMAR
= grammarBuilder("single-line-comment", "//[^\r\n]*")
.or("multi-line-comment", "/\\*.*?\\*/")
.or("keyword", "\\b(" + String.join("|", KEYWORDS) + ")\\b")
.or("paren", "[()]")
@ -59,8 +56,8 @@ public class ApexSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
.create(Pattern.DOTALL);
private ApexSyntaxHighlighter(String languageName, Pattern pattern, Map<String, String> namesToCssClass) {
super(languageName, pattern, namesToCssClass);
public ApexSyntaxHighlighter() {
super("apex", GRAMMAR);
}
}

View File

@ -4,11 +4,9 @@
package net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting;
import java.util.Map;
import java.util.regex.Pattern;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlighter;
/**
* Syntax highlighter for Java.
@ -33,9 +31,8 @@ public class JavaSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
};
public static final SyntaxHighlighter INSTANCE
= builder("java",
"single-line-comment", "//[^\n]*")
private static final RegexHighlightGrammar GRAMMAR
= grammarBuilder("single-line-comment", "//[^\n]*")
.or("multi-line-comment", "/\\*.*?\\*/")
.or("annotation", "@[\\w]+")
.or("paren", "[()]")
@ -49,8 +46,8 @@ public class JavaSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
.create(Pattern.DOTALL);
private JavaSyntaxHighlighter(String languageName, Pattern pattern, Map<String, String> namesToCssClass) {
super(languageName, pattern, namesToCssClass);
public JavaSyntaxHighlighter() {
super("java", GRAMMAR);
}
}

View File

@ -4,11 +4,7 @@
package net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting;
import java.util.Map;
import java.util.regex.Pattern;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlighter;
/**
* @author Clément Fournier
@ -21,14 +17,14 @@ public class XPathSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
"ancestor-or-self", "following", "following-sibling", "namespace", "parent",
"preceding-sibling",
};
private static final String[] KEYWORDS = new String[] {
"or", "and", "not",
};
public static final SyntaxHighlighter INSTANCE
= builder("xpath",
"attribute", "@[\\w]+")
private static final RegexHighlightGrammar GRAMMAR
= grammarBuilder("attribute", "@[\\w]+")
.or("axis", "(" + String.join("|", AXIS_NAMES) + ")(?=::)")
.or("keyword", "(" + String.join("|", KEYWORDS) + ")")
.or("function", "[\\w-]+?(?=\\()")
@ -40,8 +36,8 @@ public class XPathSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
.create();
private XPathSyntaxHighlighter(String languageName, Pattern pattern, Map<String, String> namesToCssClass) {
super(languageName, pattern, namesToCssClass);
public XPathSyntaxHighlighter() {
super("xpath", GRAMMAR);
}

View File

@ -4,11 +4,9 @@
package net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting;
import java.util.Map;
import java.util.regex.Pattern;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter;
import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlighter;
/**
* @author Clément Fournier
@ -17,9 +15,8 @@ import net.sourceforge.pmd.util.fxdesigner.util.codearea.SyntaxHighlighter;
public class XmlSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
public static final SyntaxHighlighter INSTANCE
= builder("xml",
"multi-line-comment", "<!--.*?-->")
private static final RegexHighlightGrammar GRAMMAR
= grammarBuilder("multi-line-comment", "<!--.*?-->")
.or("cdata-tag", "<!\\[CDATA\\[|]]>")
.or("cdata-content", "(?<=<!\\[CDATA\\[).*?(?=]]>)")
.or("xml-prolog", "<[?]xml.*[?]>")
@ -30,7 +27,7 @@ public class XmlSyntaxHighlighter extends SimpleRegexSyntaxHighlighter {
.create(Pattern.DOTALL);
private XmlSyntaxHighlighter(String languageName, Pattern pattern, Map<String, String> namesToCssClass) {
super(languageName, pattern, namesToCssClass);
public XmlSyntaxHighlighter() {
super("xml", GRAMMAR);
}
}