use of qupath.lib.gui.scripting.ScriptEditorControl in project qupath by qupath.
the class RichScriptEditor method getNewEditor.
@Override
protected ScriptEditorControl getNewEditor() {
try {
CodeArea codeArea = new CustomCodeArea();
CodeAreaControl control = new CodeAreaControl(codeArea);
/*
* Using LineNumberFactory.get(codeArea) gives errors related to the new paragraph folding introduced in RichTextFX 0.10.6.
* java.lang.IllegalArgumentException: Visible paragraphs' last index is [-1] but visibleParIndex was [0]
*
* To replicate
* - Run using codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));
* - Add some code (including line breaks) to the code area
* - Select all text (Ctrl/Cmd + A)
* - Delete text (backspace)
* - Add more text
*
* The change below avoids code folding being used.
*/
codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea, digits -> "%1$" + digits + "s", null, null));
// codeArea.setParagraphGraphicFactory(LineNumberFactory.get(codeArea));
codeArea.setStyle("-fx-background-color: -fx-control-inner-background;");
// Catch key typed events for special character handling (which should be platform-agnostic)
codeArea.addEventFilter(KeyEvent.KEY_TYPED, e -> {
if (e.isConsumed())
return;
var scriptSyntax = currentLanguage.get().getSyntax();
if ("(".equals(e.getCharacter())) {
scriptSyntax.handleLeftParenthesis(control, smartEditing.get());
e.consume();
} else if (")".equals(e.getCharacter())) {
scriptSyntax.handleRightParenthesis(control, smartEditing.get());
e.consume();
} else if ("\"".equals(e.getCharacter())) {
scriptSyntax.handleQuotes(control, true, smartEditing.get());
e.consume();
} else if ("\'".equals(e.getCharacter())) {
scriptSyntax.handleQuotes(control, false, smartEditing.get());
e.consume();
}
});
// TODO: Check if DefaultScriptEditor does any of these? It should be able to at least do syntaxing/auto-completion
codeArea.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
if (e.isConsumed())
return;
var scriptSyntax = currentLanguage.get().getSyntax();
if (scriptSyntax != null) {
if (e.getCode() == KeyCode.TAB) {
scriptSyntax.handleTabPress(control, e.isShiftDown());
e.consume();
} else if (e.isShortcutDown() && e.getCode() == KeyCode.SLASH) {
scriptSyntax.handleLineComment(control);
e.consume();
} else if (e.getCode() == KeyCode.ENTER && codeArea.getSelectedText().length() == 0) {
scriptSyntax.handleNewLine(control, smartEditing.get());
e.consume();
} else if (e.getCode() == KeyCode.BACK_SPACE) {
if (scriptSyntax.handleBackspace(control, smartEditing.get()) && !e.isShortcutDown() && !e.isShiftDown())
e.consume();
} else if (beautifyerCodeCombination.match(e)) {
getCurrentTextComponent().setText(scriptSyntax.beautify(getCurrentText()));
e.isConsumed();
}
}
var scriptAutoCompletor = currentLanguage.get().getAutoCompletor();
if (scriptAutoCompletor != null) {
if (completionCodeCombination.match(e)) {
scriptAutoCompletor.applyNextCompletion(control);
e.isConsumed();
} else if (!e.isControlDown())
scriptAutoCompletor.resetCompletion();
}
});
codeArea.setOnContextMenuRequested(e -> menu.show(codeArea.getScene().getWindow(), e.getScreenX(), e.getScreenY()));
@SuppressWarnings("unused") var cleanup = codeArea.multiPlainChanges().successionEnds(Duration.ofMillis(delayMillis)).supplyTask(() -> {
Task<StyleSpans<Collection<String>>> task = new Task<>() {
@Override
protected StyleSpans<Collection<String>> call() {
return scriptHighlighter.get().computeEditorHighlighting(codeArea.getText());
}
};
executor.execute(task);
return task;
}).awaitLatest(codeArea.multiPlainChanges()).filterMap(t -> {
if (t.isSuccess())
return Optional.of(t.get());
var exception = t.getFailure();
String message = exception.getLocalizedMessage() == null ? exception.getClass().getSimpleName() : exception.getLocalizedMessage();
logger.error("Error applying syntax highlighting: {}", message);
logger.debug("{}", t);
return Optional.empty();
}).subscribe(change -> codeArea.setStyleSpans(0, change));
codeArea.getStylesheets().add(getClass().getClassLoader().getResource("scripting_styles.css").toExternalForm());
scriptHighlighter.bind(Bindings.createObjectBinding(() -> ScriptHighlighterProvider.getHighlighterFromLanguage(getCurrentLanguage()), currentLanguage));
// Triggered whenever the script styling changes (e.g. change of language)
scriptHighlighter.addListener((v, o, n) -> {
if (n == null || (o != null && o.getClass().equals(n.getClass())))
return;
StyleSpans<Collection<String>> changes = scriptHighlighter.get().computeEditorHighlighting(codeArea.getText());
codeArea.setStyleSpans(0, changes);
});
return control;
} catch (Exception e) {
// Default to superclass implementation
logger.error("Unable to create code area", e);
return super.getNewEditor();
}
}
Aggregations