Add syntax highlighting framework
This commit is contained in:
parent
f94612cf87
commit
1860d4c57f
@ -1,17 +1,20 @@
|
||||
package app.controllers;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.LineNumberFactory;
|
||||
import org.fxmisc.richtext.model.StyleSpans;
|
||||
import org.fxmisc.richtext.model.TwoDimensional.Bias;
|
||||
import org.fxmisc.richtext.model.TwoDimensional.Position;
|
||||
|
||||
import app.events.EditorChangedEvent;
|
||||
import app.model.Model;
|
||||
import app.service.LanguageOperations;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
@ -43,6 +46,10 @@ public class EditorController implements Initializable, Controller {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public void setHighlighting(StyleSpans<Collection<String>> highlighting) {
|
||||
this.editor.setStyleSpans(0, highlighting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles events from the editor, and reflects them in the model
|
||||
* @param event The object containing metadata of the event
|
||||
@ -57,6 +64,10 @@ public class EditorController implements Initializable, Controller {
|
||||
pos.getMajor() + 1,
|
||||
pos.getMinor()
|
||||
));
|
||||
this.setHighlighting(
|
||||
LanguageOperations.syntaxHighlight(
|
||||
this.editor.getText(),
|
||||
Model.getLanguage()));
|
||||
}
|
||||
|
||||
}
|
||||
|
71
src/main/java/app/languages/Java.java
Normal file
71
src/main/java/app/languages/Java.java
Normal file
@ -0,0 +1,71 @@
|
||||
package app.languages;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import app.model.ProgrammingLanguage;
|
||||
|
||||
public class Java implements ProgrammingLanguage {
|
||||
|
||||
private String name = "Java";
|
||||
private URL iconPath = this.getClass().getResource("");
|
||||
|
||||
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", "throw", "throws",
|
||||
"transient", "try", "void", "volatile", "while"
|
||||
};
|
||||
|
||||
private static Entry<Pattern, String> e(String k, String v) {
|
||||
return new AbstractMap.SimpleEntry<>(Pattern.compile(k), v);
|
||||
}
|
||||
|
||||
private static final Map<Pattern, String> pattern =
|
||||
Map.ofEntries(
|
||||
e("\\b(" + String.join("|", keywords) + ")\\b", "keyword"), // <public>, <static>, ....
|
||||
e("this", "this"), // <this>
|
||||
e("true", "true"), // <true>
|
||||
e("false", "false"), // <false>
|
||||
e("\\(|\\)", "paranthesis"), // <(*)>
|
||||
e("\\{|\\}", "curlyBrackets"), // <{*}>
|
||||
e("\\[|\\]", "squareBrackets"), // <[*]>
|
||||
e(";", "semiColon"), // <;>
|
||||
e("[A-Z]\\w+", "identifier"), // <ClassName> or <InterfaceName>
|
||||
e("\\.\\w+", "property"), // <.property>
|
||||
e("(?<=this\\.)?\\w+(?=\\(*\\))", "method") // <this.function(*)>
|
||||
);
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public URL getIcon() {
|
||||
return this.iconPath;
|
||||
}
|
||||
|
||||
public Map<Pattern, String> getPatternMap() {
|
||||
return Java.pattern;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/16517689/java-regex-capturing-groups-indexes/16582083
|
||||
|
||||
public Pattern getPattern() {
|
||||
return Pattern.compile(
|
||||
Java.pattern
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> String.format("(?<%s>%s)", e.getValue(), e.getKey()))
|
||||
.collect(Collectors.joining("|")));
|
||||
}
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package app.model;
|
||||
|
||||
import app.languages.Java;
|
||||
|
||||
/**
|
||||
* Data model of the application
|
||||
*/
|
||||
|
51
src/main/java/app/service/LanguageOperations.java
Normal file
51
src/main/java/app/service/LanguageOperations.java
Normal file
@ -0,0 +1,51 @@
|
||||
package app.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.fxmisc.richtext.model.StyleSpans;
|
||||
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
||||
|
||||
import app.model.ProgrammingLanguage;
|
||||
|
||||
public class LanguageOperations {
|
||||
|
||||
private static String getMatch(Matcher m, Collection<String> kws) {
|
||||
return kws
|
||||
.stream()
|
||||
.filter(keyword -> m.group(keyword) != null)
|
||||
.findFirst()
|
||||
.orElse(""); // This is not possible, but is needed to convert Optional<String> to String
|
||||
}
|
||||
|
||||
public static StyleSpans<Collection<String>>
|
||||
syntaxHighlight(String text, ProgrammingLanguage language) {
|
||||
Matcher matcher = language.getPattern().matcher(text);
|
||||
StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>();
|
||||
|
||||
int lastKwEnd = 0;
|
||||
while(matcher.find()) {
|
||||
String styleClass = getMatch(matcher, language.getPatternMap().values());
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user