diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java index 2fbded965..df933a9ed 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/inlayhint/LSPLineContentCodeMiningTest.java @@ -33,6 +33,9 @@ import org.eclipse.lsp4j.InlayHint; import org.eclipse.lsp4j.InlayHintLabelPart; import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.widgets.Display; @@ -75,6 +78,25 @@ public void singleLabelPartCommand() throws Exception { assertEquals(MockLanguageServer.SUPPORTED_COMMAND_ID, executedCommand.getCommand()); assertEquals(command.getArguments(), executedCommand.getArguments()); } + + @Test + void inlayHintWithTextEdit() throws Exception { + IFile file = TestUtils.createUniqueTestFile(project, "lspt", "x = [1, 2]"); + ITextViewer textViewer = TestUtils.openTextViewer(file); + IDocument document = textViewer.getDocument(); + + final var provider = new InlayHintProvider(); + + InlayHint inlayHint = new InlayHint(new Position(0,0), Either.forLeft(": list[int]")); + inlayHint.setTextEdits(List.of(new TextEdit(new Range(new Position(0, 1),new Position(0,1)), ": list[int]"))); + + LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrapper(project, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID)); + final var sut = new LSPLineContentCodeMining(inlayHint, document, wrapper, provider); + MouseEvent mouseEvent = createMouseEvent(); + sut.getAction().accept(mouseEvent); + + assertEquals(document.get(), "x: list[int] = [1, 2]"); + } private static InlayHintLabelPart createInlayLabelPart(String text, String commandID) { final var labelPart = new InlayHintLabelPart(text); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java index f67fee6d5..5c83c7648 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/inlayhint/LSPLineContentCodeMining.java @@ -111,7 +111,7 @@ private static boolean canResolveInlayHint(@Nullable ServerCapabilities capabili Either inlayProvider = capabilities.getInlayHintProvider(); if (inlayProvider != null && inlayProvider.isRight()) { InlayHintRegistrationOptions options = inlayProvider.getRight(); - return options.getResolveProvider() != null && options.getResolveProvider().booleanValue(); + return Boolean.TRUE.equals(options.getResolveProvider()); } return false; } @@ -134,7 +134,28 @@ private static org.eclipse.jface.text.Position toPosition(Position position, IDo @Override public final @Nullable Consumer getAction() { - return inlayHint.getLabel().map(l -> null, this::labelPartAction); + // Check if there is a specific command to execute for the clicked on label part + var consumer = inlayHint.getLabel().map(l -> null, this::labelPartAction); + if (consumer != null) { + return consumer; + } + + // Check if there are text edits to apply when clicking on the inlay hint + if (inlayHint.getTextEdits() != null && !inlayHint.getTextEdits().isEmpty()) { + return evt -> { + try { + LSPEclipseUtils.applyEdits(document, inlayHint.getTextEdits()); + // The text of the inlay hint is integrated into the document. + // To avoid a brief moment where both the inserted text and the inlay hint are + // rendered, we set an empty label for the hint. + setLabel(""); //$NON-NLS-1$ + } catch (BadLocationException e) { + // Location to modify document was no longer valid -> Ignore + } + }; + } + + return null; } private @Nullable Consumer labelPartAction(List labelParts) {