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;
|
||||
|
||||
import com.annimon.hotarufx.ui.controller.EditorController;
|
||||
import java.io.IOException;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@ -9,12 +10,15 @@ import lombok.val;
|
||||
|
||||
public class Main extends Application {
|
||||
|
||||
private EditorController controller;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
primaryStage.setTitle("HotaruFX");
|
||||
try {
|
||||
val loader = new FXMLLoader(getClass().getResource("/fxml/Editor.fxml"));
|
||||
val scene = new Scene(loader.load());
|
||||
controller = loader.getController();
|
||||
primaryStage.setScene(scene);
|
||||
} catch (IOException e) {
|
||||
// TODO: notice me!!
|
||||
@ -22,6 +26,14 @@ public class Main extends Application {
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (controller != null) {
|
||||
controller.stop();
|
||||
}
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] 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.ParseError;
|
||||
import com.annimon.hotarufx.parser.visitors.InterpreterVisitor;
|
||||
import com.annimon.hotarufx.ui.SyntaxHighlighter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.Executors;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
@ -37,6 +38,8 @@ public class EditorController implements Initializable {
|
||||
@FXML
|
||||
private TitledPane logPane;
|
||||
|
||||
private SyntaxHighlighter syntaxHighlighter;
|
||||
|
||||
@FXML
|
||||
private void handleMenuExit(ActionEvent event) {
|
||||
// TODO: confirmation
|
||||
@ -81,9 +84,15 @@ public class EditorController implements Initializable {
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
editor.setParagraphGraphicFactory(LineNumberFactory.get(editor));
|
||||
syntaxHighlighter = new SyntaxHighlighter(editor, Executors.newSingleThreadExecutor());
|
||||
syntaxHighlighter.init();
|
||||
editor.replaceText(0, 0, readProgram("/main.hfx"));
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
syntaxHighlighter.release();
|
||||
}
|
||||
|
||||
private static String readProgram(String path) {
|
||||
val fallbackProgram = "composition(640, 480, 25)";
|
||||
try (InputStream is = Main.class.getResourceAsStream(path)) {
|
||||
|
Loading…
Reference in New Issue
Block a user