Studio with hint decorators
This commit is contained in:
parent
55e821989c
commit
11555263d3
@ -35,7 +35,7 @@ final class EditorInlineHintLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String displayText(final LspInlineHintDTO inlineHint) {
|
static String displayText(final LspInlineHintDTO inlineHint) {
|
||||||
return "[%s]".formatted(inlineHint.label());
|
return ": %s".formatted(inlineHint.label());
|
||||||
}
|
}
|
||||||
|
|
||||||
static String categoryStyleClass(final LspInlineHintDTO inlineHint) {
|
static String categoryStyleClass(final LspInlineHintDTO inlineHint) {
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import javafx.scene.Node;
|
|||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import org.fxmisc.richtext.CodeArea;
|
import org.fxmisc.richtext.CodeArea;
|
||||||
import org.fxmisc.richtext.model.TwoDimensional;
|
|
||||||
import org.reactfx.Subscription;
|
import org.reactfx.Subscription;
|
||||||
import p.studio.lsp.dtos.LspInlineHintDTO;
|
import p.studio.lsp.dtos.LspInlineHintDTO;
|
||||||
|
|
||||||
@ -34,6 +33,7 @@ final class EditorInlineHintOverlay {
|
|||||||
codeArea.layoutBoundsProperty().addListener((ignored, previous, current) -> refresh());
|
codeArea.layoutBoundsProperty().addListener((ignored, previous, current) -> refresh());
|
||||||
codeArea.textProperty().addListener((ignored, previous, current) -> refresh());
|
codeArea.textProperty().addListener((ignored, previous, current) -> refresh());
|
||||||
overlayPane.layoutBoundsProperty().addListener((ignored, previous, current) -> refresh());
|
overlayPane.layoutBoundsProperty().addListener((ignored, previous, current) -> refresh());
|
||||||
|
overlayPane.sceneProperty().addListener((ignored, previous, current) -> scheduleRefresh());
|
||||||
viewportSubscription = codeArea.viewportDirtyEvents().subscribe(ignored -> refresh());
|
viewportSubscription = codeArea.viewportDirtyEvents().subscribe(ignored -> refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +51,10 @@ final class EditorInlineHintOverlay {
|
|||||||
setInlineHints(List.of());
|
setInlineHints(List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void refreshLater() {
|
||||||
|
scheduleRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
viewportSubscription.unsubscribe();
|
viewportSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
@ -109,10 +113,8 @@ final class EditorInlineHintOverlay {
|
|||||||
if (codeArea.getLength() == 0) {
|
if (codeArea.getLength() == 0) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
final int anchorOffsetExclusive = Math.max(inlineHint.anchor().startOffset() + 1, inlineHint.anchor().endOffset());
|
final int anchorOffset = Math.max(0, Math.min(codeArea.getLength(), inlineHint.anchor().endOffset()));
|
||||||
final int anchorCharOffset = Math.max(0, Math.min(codeArea.getLength() - 1, anchorOffsetExclusive - 1));
|
final Optional<Bounds> characterBounds = codeArea.getCharacterBoundsOnScreen(anchorOffset, anchorOffset);
|
||||||
final var position = codeArea.offsetToPosition(anchorCharOffset, TwoDimensional.Bias.Forward);
|
|
||||||
final Optional<Bounds> characterBounds = codeArea.getCharacterBoundsOnScreen(position.getMajor(), position.getMinor());
|
|
||||||
return characterBounds.map(bounds -> new EditorInlineHintLayout.AnchorBounds(
|
return characterBounds.map(bounds -> new EditorInlineHintLayout.AnchorBounds(
|
||||||
bounds.getMinX(),
|
bounds.getMinX(),
|
||||||
bounds.getMinY(),
|
bounds.getMinY(),
|
||||||
|
|||||||
@ -0,0 +1,159 @@
|
|||||||
|
package p.studio.workspaces.editor;
|
||||||
|
|
||||||
|
import org.fxmisc.richtext.model.StyleSpans;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpan;
|
||||||
|
import p.studio.lsp.dtos.LspInlineHintDTO;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
final class EditorInlineHintProjection {
|
||||||
|
private final String displayText;
|
||||||
|
private final StyleSpans<Collection<String>> displayStyles;
|
||||||
|
private final List<ProtectedRange> protectedRanges;
|
||||||
|
|
||||||
|
private EditorInlineHintProjection(
|
||||||
|
final String displayText,
|
||||||
|
final StyleSpans<Collection<String>> displayStyles,
|
||||||
|
final List<ProtectedRange> protectedRanges) {
|
||||||
|
this.displayText = Objects.requireNonNull(displayText, "displayText");
|
||||||
|
this.displayStyles = Objects.requireNonNull(displayStyles, "displayStyles");
|
||||||
|
this.protectedRanges = new ArrayList<>(Objects.requireNonNull(protectedRanges, "protectedRanges"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static EditorInlineHintProjection create(
|
||||||
|
final String sourceText,
|
||||||
|
final StyleSpans<Collection<String>> sourceStyles,
|
||||||
|
final List<LspInlineHintDTO> inlineHints) {
|
||||||
|
Objects.requireNonNull(sourceText, "sourceText");
|
||||||
|
Objects.requireNonNull(sourceStyles, "sourceStyles");
|
||||||
|
Objects.requireNonNull(inlineHints, "inlineHints");
|
||||||
|
if (inlineHints.isEmpty()) {
|
||||||
|
return new EditorInlineHintProjection(sourceText, sourceStyles, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
final var sortedHints = inlineHints.stream()
|
||||||
|
.sorted(Comparator.comparingInt(hint -> hint.anchor().endOffset()))
|
||||||
|
.toList();
|
||||||
|
final var displayText = new StringBuilder(sourceText.length() + (sortedHints.size() * 8));
|
||||||
|
final var displayStyles = new StyleSpansBuilder<Collection<String>>();
|
||||||
|
final var protectedRanges = new ArrayList<ProtectedRange>();
|
||||||
|
|
||||||
|
int sourceOffset = 0;
|
||||||
|
int displayOffset = 0;
|
||||||
|
for (final var inlineHint : sortedHints) {
|
||||||
|
final int anchorOffset = Math.max(0, Math.min(sourceText.length(), inlineHint.anchor().endOffset()));
|
||||||
|
if (anchorOffset > sourceOffset) {
|
||||||
|
displayText.append(sourceText, sourceOffset, anchorOffset);
|
||||||
|
appendSourceStyles(displayStyles, sourceStyles.subView(sourceOffset, anchorOffset));
|
||||||
|
displayOffset += anchorOffset - sourceOffset;
|
||||||
|
sourceOffset = anchorOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String hintText = " " + EditorInlineHintLayout.displayText(inlineHint);
|
||||||
|
displayText.append(hintText);
|
||||||
|
displayStyles.add(hintClasses(inlineHint), hintText.length());
|
||||||
|
protectedRanges.add(new ProtectedRange(displayOffset, displayOffset + hintText.length()));
|
||||||
|
displayOffset += hintText.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceOffset < sourceText.length()) {
|
||||||
|
displayText.append(sourceText, sourceOffset, sourceText.length());
|
||||||
|
appendSourceStyles(displayStyles, sourceStyles.subView(sourceOffset, sourceText.length()));
|
||||||
|
}
|
||||||
|
return new EditorInlineHintProjection(displayText.toString(), displayStyles.create(), protectedRanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
String displayText() {
|
||||||
|
return displayText;
|
||||||
|
}
|
||||||
|
|
||||||
|
StyleSpans<Collection<String>> displayStyles() {
|
||||||
|
return displayStyles;
|
||||||
|
}
|
||||||
|
|
||||||
|
String stripDecorations(final String currentDisplayText) {
|
||||||
|
Objects.requireNonNull(currentDisplayText, "currentDisplayText");
|
||||||
|
if (protectedRanges.isEmpty()) {
|
||||||
|
return currentDisplayText;
|
||||||
|
}
|
||||||
|
final var sourceText = new StringBuilder(currentDisplayText);
|
||||||
|
for (int index = protectedRanges.size() - 1; index >= 0; index--) {
|
||||||
|
final var range = protectedRanges.get(index);
|
||||||
|
final int start = Math.max(0, Math.min(sourceText.length(), range.start()));
|
||||||
|
final int end = Math.max(start, Math.min(sourceText.length(), range.end()));
|
||||||
|
sourceText.delete(start, end);
|
||||||
|
}
|
||||||
|
return sourceText.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyDisplayChange(final int position, final int removedLength, final int insertedLength) {
|
||||||
|
final int delta = insertedLength - removedLength;
|
||||||
|
for (int index = 0; index < protectedRanges.size(); index++) {
|
||||||
|
final var range = protectedRanges.get(index);
|
||||||
|
if (range.end() <= position) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (range.start() >= position + removedLength) {
|
||||||
|
protectedRanges.set(index, range.shift(delta));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
protectedRanges.set(index, range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean containsOffset(final int offset) {
|
||||||
|
return protectedRanges.stream().anyMatch(range -> range.contains(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean touchesRange(final int start, final int end) {
|
||||||
|
if (start == end) {
|
||||||
|
return containsOffset(start);
|
||||||
|
}
|
||||||
|
return protectedRanges.stream().anyMatch(range -> range.intersects(start, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
int clampCaret(final int offset, final boolean preferRightBoundary) {
|
||||||
|
for (final var range : protectedRanges) {
|
||||||
|
if (!range.contains(offset)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return preferRightBoundary ? range.end() : range.start();
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendSourceStyles(
|
||||||
|
final StyleSpansBuilder<Collection<String>> builder,
|
||||||
|
final StyleSpans<Collection<String>> styles) {
|
||||||
|
for (final StyleSpan<Collection<String>> span : styles) {
|
||||||
|
builder.add(span.getStyle(), span.getLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Collection<String> hintClasses(final LspInlineHintDTO inlineHint) {
|
||||||
|
final var classes = new LinkedHashSet<String>();
|
||||||
|
classes.add("editor-inline-hint");
|
||||||
|
classes.add(EditorInlineHintLayout.categoryStyleClass(inlineHint));
|
||||||
|
return List.copyOf(classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
record ProtectedRange(int start, int end) {
|
||||||
|
boolean contains(final int offset) {
|
||||||
|
return offset >= start && offset < end;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean intersects(final int rangeStart, final int rangeEnd) {
|
||||||
|
return rangeStart < end && rangeEnd > start;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectedRange shift(final int delta) {
|
||||||
|
return new ProtectedRange(start + delta, end + delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,11 +4,14 @@ import javafx.application.Platform;
|
|||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.control.SplitPane;
|
import javafx.scene.control.SplitPane;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import org.fxmisc.flowless.VirtualizedScrollPane;
|
import org.fxmisc.flowless.VirtualizedScrollPane;
|
||||||
import org.fxmisc.richtext.CodeArea;
|
import org.fxmisc.richtext.CodeArea;
|
||||||
import org.fxmisc.richtext.LineNumberFactory;
|
import org.fxmisc.richtext.LineNumberFactory;
|
||||||
|
import org.reactfx.Subscription;
|
||||||
import p.studio.lsp.LspService;
|
import p.studio.lsp.LspService;
|
||||||
import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
|
import p.studio.lsp.messages.LspAnalyzeDocumentRequest;
|
||||||
import p.studio.lsp.messages.LspAnalyzeDocumentResult;
|
import p.studio.lsp.messages.LspAnalyzeDocumentResult;
|
||||||
@ -30,7 +33,6 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
private final BorderPane root = new BorderPane();
|
private final BorderPane root = new BorderPane();
|
||||||
private final CodeArea codeArea = new CodeArea();
|
private final CodeArea codeArea = new CodeArea();
|
||||||
private final VirtualizedScrollPane<CodeArea> codeScroller = new VirtualizedScrollPane<>(codeArea);
|
private final VirtualizedScrollPane<CodeArea> codeScroller = new VirtualizedScrollPane<>(codeArea);
|
||||||
private final EditorInlineHintOverlay inlineHintOverlay = new EditorInlineHintOverlay(codeArea);
|
|
||||||
private final Button saveButton = new Button();
|
private final Button saveButton = new Button();
|
||||||
private final Button saveAllButton = new Button();
|
private final Button saveAllButton = new Button();
|
||||||
private final EditorWarningStrip warningStrip = new EditorWarningStrip();
|
private final EditorWarningStrip warningStrip = new EditorWarningStrip();
|
||||||
@ -43,10 +45,15 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
private final LspService prometeuLspService;
|
private final LspService prometeuLspService;
|
||||||
private final VfsProjectDocument vfsProjectDocument;
|
private final VfsProjectDocument vfsProjectDocument;
|
||||||
private final EditorOpenFileSession openFileSession = new EditorOpenFileSession();
|
private final EditorOpenFileSession openFileSession = new EditorOpenFileSession();
|
||||||
|
private final Subscription inlineHintChangeSubscription;
|
||||||
private final List<String> activePresentationStylesheets = new ArrayList<>();
|
private final List<String> activePresentationStylesheets = new ArrayList<>();
|
||||||
private final IntFunction<Node> lineNumberFactory = LineNumberFactory.get(codeArea);
|
private final IntFunction<Node> lineNumberFactory = LineNumberFactory.get(codeArea);
|
||||||
private EditorDocumentScopeGuideModel scopeGuideModel = EditorDocumentScopeGuideModel.empty();
|
private EditorDocumentScopeGuideModel scopeGuideModel = EditorDocumentScopeGuideModel.empty();
|
||||||
private EditorDocumentScopeGuideModel.ActiveGuides activeGuides = EditorDocumentScopeGuideModel.ActiveGuides.empty();
|
private EditorDocumentScopeGuideModel.ActiveGuides activeGuides = EditorDocumentScopeGuideModel.ActiveGuides.empty();
|
||||||
|
private EditorInlineHintProjection inlineHintProjection = EditorInlineHintProjection.create(
|
||||||
|
"",
|
||||||
|
presentationRegistry.resolve("text").highlight(""),
|
||||||
|
List.of());
|
||||||
private boolean syncingEditor;
|
private boolean syncingEditor;
|
||||||
|
|
||||||
public EditorWorkspace(
|
public EditorWorkspace(
|
||||||
@ -64,6 +71,17 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
codeArea.caretPositionProperty().addListener((ignored, previous, current) ->
|
codeArea.caretPositionProperty().addListener((ignored, previous, current) ->
|
||||||
updateActiveGuides(current == null ? 0 : current.intValue()));
|
updateActiveGuides(current == null ? 0 : current.intValue()));
|
||||||
codeArea.getStyleClass().add("editor-workspace-code-area");
|
codeArea.getStyleClass().add("editor-workspace-code-area");
|
||||||
|
codeArea.addEventFilter(KeyEvent.KEY_PRESSED, this::guardInlineHintMutation);
|
||||||
|
codeArea.addEventFilter(KeyEvent.KEY_TYPED, this::guardInlineHintMutation);
|
||||||
|
inlineHintChangeSubscription = codeArea.plainTextChanges().subscribe(change -> {
|
||||||
|
if (syncingEditor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inlineHintProjection.applyDisplayChange(
|
||||||
|
change.getPosition(),
|
||||||
|
change.getRemoved().length(),
|
||||||
|
change.getInserted().length());
|
||||||
|
});
|
||||||
EditorDocumentPresentationStyles.applyToCodeArea(codeArea, presentationRegistry.resolve("text"));
|
EditorDocumentPresentationStyles.applyToCodeArea(codeArea, presentationRegistry.resolve("text"));
|
||||||
configureCommandBar();
|
configureCommandBar();
|
||||||
configureWarning();
|
configureWarning();
|
||||||
@ -91,7 +109,7 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unLoad() {
|
public void unLoad() {
|
||||||
inlineHintOverlay.dispose();
|
inlineHintChangeSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeArea codeArea() { return codeArea; }
|
public CodeArea codeArea() { return codeArea; }
|
||||||
@ -145,9 +163,12 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
applyPresentationStylesheets(presentation);
|
applyPresentationStylesheets(presentation);
|
||||||
syncingEditor = true;
|
syncingEditor = true;
|
||||||
try {
|
try {
|
||||||
codeArea.replaceText(fileBuffer.content());
|
inlineHintProjection = EditorInlineHintProjection.create(
|
||||||
codeArea.setStyleSpans(0, highlighting.styleSpans());
|
fileBuffer.content(),
|
||||||
inlineHintOverlay.setInlineHints(highlighting.inlineHints());
|
highlighting.styleSpans(),
|
||||||
|
highlighting.inlineHints());
|
||||||
|
codeArea.replaceText(inlineHintProjection.displayText());
|
||||||
|
codeArea.setStyleSpans(0, inlineHintProjection.displayStyles());
|
||||||
codeArea.moveTo(0);
|
codeArea.moveTo(0);
|
||||||
codeArea.requestFollowCaret();
|
codeArea.requestFollowCaret();
|
||||||
} finally {
|
} finally {
|
||||||
@ -195,9 +216,9 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
applyPresentationStylesheets(presentation);
|
applyPresentationStylesheets(presentation);
|
||||||
syncingEditor = true;
|
syncingEditor = true;
|
||||||
try {
|
try {
|
||||||
|
inlineHintProjection = EditorInlineHintProjection.create("", presentation.highlight(""), List.of());
|
||||||
codeArea.replaceText("");
|
codeArea.replaceText("");
|
||||||
codeArea.setStyleSpans(0, presentation.highlight(""));
|
codeArea.setStyleSpans(0, inlineHintProjection.displayStyles());
|
||||||
inlineHintOverlay.clear();
|
|
||||||
codeArea.moveTo(0);
|
codeArea.moveTo(0);
|
||||||
codeArea.requestFollowCaret();
|
codeArea.requestFollowCaret();
|
||||||
} finally {
|
} finally {
|
||||||
@ -250,7 +271,7 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private VBox buildCenterColumn() {
|
private VBox buildCenterColumn() {
|
||||||
final var editorViewport = new StackPane(codeScroller, inlineHintOverlay.node());
|
final var editorViewport = new StackPane(codeScroller);
|
||||||
editorViewport.getStyleClass().add("editor-workspace-editor-viewport");
|
editorViewport.getStyleClass().add("editor-workspace-editor-viewport");
|
||||||
final var editorSurface = new VBox(0, warningStrip, editorViewport);
|
final var editorSurface = new VBox(0, warningStrip, editorViewport);
|
||||||
editorSurface.getStyleClass().add("editor-workspace-editor-surface");
|
editorSurface.getStyleClass().add("editor-workspace-editor-surface");
|
||||||
@ -298,7 +319,8 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
openFileSession.activeFile()
|
openFileSession.activeFile()
|
||||||
.filter(EditorOpenFileBuffer::editable)
|
.filter(EditorOpenFileBuffer::editable)
|
||||||
.ifPresent(activeFile -> {
|
.ifPresent(activeFile -> {
|
||||||
final VfsDocumentOpenResult.VfsTextDocument updatedDocument = vfsProjectDocument.updateDocument(activeFile.path(), content);
|
final String sourceContent = inlineHintProjection.stripDecorations(content);
|
||||||
|
final VfsDocumentOpenResult.VfsTextDocument updatedDocument = vfsProjectDocument.updateDocument(activeFile.path(), sourceContent);
|
||||||
openFileSession.open(bufferFrom(updatedDocument));
|
openFileSession.open(bufferFrom(updatedDocument));
|
||||||
tabStrip.showOpenFiles(
|
tabStrip.showOpenFiles(
|
||||||
openFileSession.openFiles(),
|
openFileSession.openFiles(),
|
||||||
@ -402,4 +424,34 @@ public final class EditorWorkspace extends Workspace {
|
|||||||
activeGuides = next;
|
activeGuides = next;
|
||||||
refreshParagraphGraphics();
|
refreshParagraphGraphics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void guardInlineHintMutation(final KeyEvent event) {
|
||||||
|
if (syncingEditor || !codeArea.isEditable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int selectionStart = codeArea.getSelection().getStart();
|
||||||
|
final int selectionEnd = codeArea.getSelection().getEnd();
|
||||||
|
if (selectionStart != selectionEnd && inlineHintProjection.touchesRange(selectionStart, selectionEnd)) {
|
||||||
|
event.consume();
|
||||||
|
codeArea.moveTo(inlineHintProjection.clampCaret(selectionStart, false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final int caret = codeArea.getCaretPosition();
|
||||||
|
if (event.getEventType() == KeyEvent.KEY_TYPED) {
|
||||||
|
if (inlineHintProjection.containsOffset(caret)) {
|
||||||
|
event.consume();
|
||||||
|
codeArea.moveTo(inlineHintProjection.clampCaret(caret, true));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.getCode() == KeyCode.BACK_SPACE && inlineHintProjection.containsOffset(Math.max(0, caret - 1))) {
|
||||||
|
event.consume();
|
||||||
|
codeArea.moveTo(inlineHintProjection.clampCaret(Math.max(0, caret - 1), false));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.getCode() == KeyCode.DELETE && inlineHintProjection.containsOffset(caret)) {
|
||||||
|
event.consume();
|
||||||
|
codeArea.moveTo(inlineHintProjection.clampCaret(caret, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -711,19 +711,16 @@
|
|||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-inline-hint-layer {
|
.editor-workspace-code-area .text.editor-inline-hint {
|
||||||
-fx-background-color: transparent;
|
-fx-fill: #707070;
|
||||||
}
|
|
||||||
|
|
||||||
.editor-inline-hint {
|
|
||||||
-fx-text-fill: rgba(182, 196, 209, 0.72);
|
|
||||||
-fx-font-family: "JetBrains Mono Medium", "JetBrains Mono", "Iosevka", "Cascadia Mono", "IBM Plex Mono", monospace;
|
-fx-font-family: "JetBrains Mono Medium", "JetBrains Mono", "Iosevka", "Cascadia Mono", "IBM Plex Mono", monospace;
|
||||||
-fx-font-size: 14px;
|
-fx-font-size: 13px;
|
||||||
-fx-opacity: 0.82;
|
-rtfx-background-color: rgba(70, 76, 84, 0.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-inline-hint-type {
|
.editor-workspace-code-area .text.editor-inline-hint-type {
|
||||||
-fx-text-fill: rgba(135, 198, 114, 0.82);
|
-fx-fill: #707070;
|
||||||
|
-rtfx-background-color: rgba(70, 76, 84, 0.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-workspace-code-area-type-text .text {
|
.editor-workspace-code-area-type-text .text {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ final class EditorInlineHintLayoutTest {
|
|||||||
ignored -> Optional.of(new EditorInlineHintLayout.AnchorBounds(20.0d, 8.0d, 40.0d, 16.0d)));
|
ignored -> Optional.of(new EditorInlineHintLayout.AnchorBounds(20.0d, 8.0d, 40.0d, 16.0d)));
|
||||||
|
|
||||||
assertEquals(1, placements.size());
|
assertEquals(1, placements.size());
|
||||||
assertEquals("[int]", placements.getFirst().displayText());
|
assertEquals(": int", placements.getFirst().displayText());
|
||||||
assertEquals("editor-inline-hint-type", placements.getFirst().categoryStyleClass());
|
assertEquals("editor-inline-hint-type", placements.getFirst().categoryStyleClass());
|
||||||
assertEquals(46.0d, placements.getFirst().screenX());
|
assertEquals(46.0d, placements.getFirst().screenX());
|
||||||
assertEquals(8.0d, placements.getFirst().screenY());
|
assertEquals(8.0d, placements.getFirst().screenY());
|
||||||
@ -39,6 +39,6 @@ final class EditorInlineHintLayoutTest {
|
|||||||
|
|
||||||
assertEquals(1, placements.size());
|
assertEquals(1, placements.size());
|
||||||
assertEquals(stable, placements.getFirst().inlineHint());
|
assertEquals(stable, placements.getFirst().inlineHint());
|
||||||
assertEquals("[int]", placements.getFirst().displayText());
|
assertEquals(": int", placements.getFirst().displayText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user