mirror of
https://github.com/aNNiMON/HotaruFX.git
synced 2024-09-19 14:14:21 +03:00
Add syntax highlighter
This commit is contained in:
parent
2fb70d1b80
commit
5acaa5ee88
@ -1,5 +1,6 @@
|
|||||||
package com.annimon.hotarufx;
|
package com.annimon.hotarufx;
|
||||||
|
|
||||||
|
import com.annimon.hotarufx.ui.controller.EditorController;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
@ -9,12 +10,15 @@ import lombok.val;
|
|||||||
|
|
||||||
public class Main extends Application {
|
public class Main extends Application {
|
||||||
|
|
||||||
|
private EditorController controller;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) {
|
public void start(Stage primaryStage) {
|
||||||
primaryStage.setTitle("HotaruFX");
|
primaryStage.setTitle("HotaruFX");
|
||||||
try {
|
try {
|
||||||
val loader = new FXMLLoader(getClass().getResource("/fxml/Editor.fxml"));
|
val loader = new FXMLLoader(getClass().getResource("/fxml/Editor.fxml"));
|
||||||
val scene = new Scene(loader.load());
|
val scene = new Scene(loader.load());
|
||||||
|
controller = loader.getController();
|
||||||
primaryStage.setScene(scene);
|
primaryStage.setScene(scene);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO: notice me!!
|
// TODO: notice me!!
|
||||||
@ -22,6 +26,14 @@ public class Main extends Application {
|
|||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws Exception {
|
||||||
|
if (controller != null) {
|
||||||
|
controller.stop();
|
||||||
|
}
|
||||||
|
super.stop();
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.annimon.hotarufx.ui;
|
||||||
|
|
||||||
|
import com.annimon.hotarufx.lexer.HotaruLexer;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.val;
|
||||||
|
import org.fxmisc.richtext.CodeArea;
|
||||||
|
import org.fxmisc.richtext.StyleSpans;
|
||||||
|
import org.fxmisc.richtext.StyleSpansBuilder;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SyntaxHighlighter {
|
||||||
|
|
||||||
|
private final CodeArea editor;
|
||||||
|
private final ExecutorService executor;
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
editor.richChanges()
|
||||||
|
.filter(ch -> !ch.getInserted().equals(ch.getRemoved()))
|
||||||
|
.successionEnds(Duration.ofMillis(500))
|
||||||
|
.supplyTask(this::computeHighlightingAsync)
|
||||||
|
.awaitLatest(editor.richChanges())
|
||||||
|
.filterMap(t -> Optional.ofNullable(t.isSuccess() ? t.get() : null))
|
||||||
|
.subscribe(spans -> editor.setStyleSpans(0, spans));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<StyleSpans<Collection<String>>> computeHighlightingAsync() {
|
||||||
|
val text = editor.getText();
|
||||||
|
val task = new Task<StyleSpans<Collection<String>>>() {
|
||||||
|
@Override
|
||||||
|
protected StyleSpans<Collection<String>> call() throws Exception {
|
||||||
|
val spans = new StyleSpansBuilder<Collection<String>>();
|
||||||
|
for (val t : new HotaruLexer(text).tokenize()) {
|
||||||
|
val category = t.getType().getPrimaryCategory();
|
||||||
|
switch (category) {
|
||||||
|
case "string":
|
||||||
|
case "keyword":
|
||||||
|
case "comment":
|
||||||
|
case "number":
|
||||||
|
spans.add(Collections.singleton(category), t.getLength());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
spans.add(Collections.emptyList(), t.getLength());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spans.create();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
executor.execute(task);
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,14 @@ import com.annimon.hotarufx.lib.Context;
|
|||||||
import com.annimon.hotarufx.parser.HotaruParser;
|
import com.annimon.hotarufx.parser.HotaruParser;
|
||||||
import com.annimon.hotarufx.parser.ParseError;
|
import com.annimon.hotarufx.parser.ParseError;
|
||||||
import com.annimon.hotarufx.parser.visitors.InterpreterVisitor;
|
import com.annimon.hotarufx.parser.visitors.InterpreterVisitor;
|
||||||
|
import com.annimon.hotarufx.ui.SyntaxHighlighter;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
@ -37,6 +38,8 @@ public class EditorController implements Initializable {
|
|||||||
@FXML
|
@FXML
|
||||||
private TitledPane logPane;
|
private TitledPane logPane;
|
||||||
|
|
||||||
|
private SyntaxHighlighter syntaxHighlighter;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private void handleMenuExit(ActionEvent event) {
|
private void handleMenuExit(ActionEvent event) {
|
||||||
// TODO: confirmation
|
// TODO: confirmation
|
||||||
@ -81,9 +84,15 @@ public class EditorController implements Initializable {
|
|||||||
@Override
|
@Override
|
||||||
public void initialize(URL location, ResourceBundle resources) {
|
public void initialize(URL location, ResourceBundle resources) {
|
||||||
editor.setParagraphGraphicFactory(LineNumberFactory.get(editor));
|
editor.setParagraphGraphicFactory(LineNumberFactory.get(editor));
|
||||||
|
syntaxHighlighter = new SyntaxHighlighter(editor, Executors.newSingleThreadExecutor());
|
||||||
|
syntaxHighlighter.init();
|
||||||
editor.replaceText(0, 0, readProgram("/main.hfx"));
|
editor.replaceText(0, 0, readProgram("/main.hfx"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
syntaxHighlighter.release();
|
||||||
|
}
|
||||||
|
|
||||||
private static String readProgram(String path) {
|
private static String readProgram(String path) {
|
||||||
val fallbackProgram = "composition(640, 480, 25)";
|
val fallbackProgram = "composition(640, 480, 25)";
|
||||||
try (InputStream is = Main.class.getResourceAsStream(path)) {
|
try (InputStream is = Main.class.getResourceAsStream(path)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user