diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/LSPIDEServices.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/LSPIDEServices.java index c8f76e48c..1a35bbba6 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/LSPIDEServices.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/LSPIDEServices.java @@ -37,6 +37,8 @@ import org.apache.logging.log4j.Logger; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.MessageType; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.ShowDocumentParams; import org.eclipse.lsp4j.WorkspaceFolder; @@ -77,6 +79,39 @@ public LSPIDEServices(IBaseLanguageClient client, IBaseTextDocumentService docSe this.monitor = monitor; } + @Override + public void showMessage(IConstructor message) { + languageClient.showMessage(toMessageParams(message)); + } + + public static MessageParams toMessageParams(IConstructor message) { + var params = new MessageParams(); + switch (message.getName()) { + case "error": { + params.setType(MessageType.Error); + break; + } + case "warning": { + params.setType(MessageType.Warning); + break; + } + case "info": { + params.setType(MessageType.Info); + break; + } + default: params.setType(MessageType.Log); + } + + var msgText = ((IString) message.get("msg")).getValue(); + if (message.has("at")) { + var at = ((ISourceLocation) message.get("at")).getURI(); + params.setMessage(String.format("%s (at %s)", msgText, at)); + } else { + params.setMessage(msgText); + } + return params; + } + @Override public PrintWriter stderr() { assert false: "this should not be used here"; diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java index 616d157e1..d3836dbd9 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/parametric/ParametricTextDocumentService.java @@ -117,6 +117,7 @@ import org.rascalmpl.vscode.lsp.BaseWorkspaceService; import org.rascalmpl.vscode.lsp.IBaseLanguageClient; import org.rascalmpl.vscode.lsp.IBaseTextDocumentService; +import org.rascalmpl.vscode.lsp.LSPIDEServices; import org.rascalmpl.vscode.lsp.TextDocumentState; import org.rascalmpl.vscode.lsp.parametric.model.ParametricFileFacts; import org.rascalmpl.vscode.lsp.parametric.model.ParametricSummary; @@ -436,35 +437,10 @@ private void showMessages(ISet messages) { } for (var msg : messages) { - client.showMessage(setMessageParams((IConstructor) msg)); + client.showMessage(LSPIDEServices.toMessageParams((IConstructor) msg)); } } - private MessageParams setMessageParams(IConstructor message) { - var params = new MessageParams(); - switch (message.getName()) { - case "warning": { - params.setType(MessageType.Warning); - break; - } - case "info": { - params.setType(MessageType.Info); - break; - } - default: params.setType(MessageType.Log); - } - - var msgText = ((IString) message.get("msg")).getValue(); - if (message.has("at")) { - var at = ((ISourceLocation) message.get("at")).getURI(); - params.setMessage(String.format("%s (at %s)", msgText, at)); - } else { - params.setMessage(msgText); - } - - return params; - } - @Override public void didRenameFiles(RenameFilesParams params, List workspaceFolders) { Map> byContrib = bundleRenamesByContribution(params.getFiles()); diff --git a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java index cd6afe898..c0421184b 100644 --- a/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java +++ b/rascal-lsp/src/main/java/org/rascalmpl/vscode/lsp/rascal/RascalTextDocumentService.java @@ -110,6 +110,7 @@ import org.rascalmpl.vscode.lsp.BaseWorkspaceService; import org.rascalmpl.vscode.lsp.IBaseLanguageClient; import org.rascalmpl.vscode.lsp.IBaseTextDocumentService; +import org.rascalmpl.vscode.lsp.LSPIDEServices; import org.rascalmpl.vscode.lsp.TextDocumentState; import org.rascalmpl.vscode.lsp.rascal.RascalLanguageServices.CodeLensSuggestion; import org.rascalmpl.vscode.lsp.rascal.model.FileFacts; @@ -133,7 +134,6 @@ import io.usethesource.vallang.IList; import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISourceLocation; -import io.usethesource.vallang.IString; import io.usethesource.vallang.IValue; public class RascalTextDocumentService implements IBaseTextDocumentService, LanguageClientAware { @@ -391,38 +391,10 @@ public CompletableFuture rename(RenameParams params) { private void showMessages(ISet messages) { for (var msg : messages) { - client.showMessage(setMessageParams((IConstructor) msg)); + client.showMessage(LSPIDEServices.toMessageParams((IConstructor) msg)); } } - private MessageParams setMessageParams(IConstructor message) { - var params = new MessageParams(); - switch (message.getName()) { - case "error": { - params.setType(MessageType.Error); - break; - } - case "warning": { - params.setType(MessageType.Warning); - break; - } - case "info": { - params.setType(MessageType.Info); - break; - } - default: params.setType(MessageType.Log); - } - - var msgText = ((IString) message.get("msg")).getValue(); - if (message.has("at")) { - var at = ((ISourceLocation) message.get("at")).getURI(); - params.setMessage(String.format("%s (at %s)", msgText, at)); - } else { - params.setMessage(msgText); - } - return params; - } - @Override public CompletableFuture hover(HoverParams params) { logger.debug("textDocument/hover: {} at {}", params.getTextDocument(), params.getPosition()); diff --git a/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc b/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc index a5a11ee31..505c98ba3 100644 --- a/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc +++ b/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc @@ -159,11 +159,15 @@ default list[CodeAction] picoCodeActionService(Focus _focus) = []; data Command = renameAtoB(start[Program] program) | removeDecl(start[Program] program, IdType toBeRemoved) + | showInfoMessage(start[Program] program) ; @synopsis{Adds an example lense to the entire program.} lrel[loc,Command] picoCodeLenseService(start[Program] input) - = []; + = [ + , + + ]; @synopsis{Generates inlay hints that explain the type of each variable usage.} list[InlayHint] picoInlayHintService(start[Program] input) { @@ -192,6 +196,12 @@ value picoExecutionService(removeDecl(start[Program] program, IdType toBeRemoved return ("result": true); } +@synopsis{Command handler to show an info message} +value picoExecutionService(showInfoMessage(start[Program] program)) { + showMessage(info("Info message", program.src)); + return ("result": true); +} + @synopsis{Prepares the rename service by checking if the id can be renamed} loc picoRenamePreparingService(Focus _:[Id id, *_]) { if ("" == "fixed") { diff --git a/rascal-vscode-extension/src/test/vscode-suite/dsl.test.ts b/rascal-vscode-extension/src/test/vscode-suite/dsl.test.ts index 5c3a80671..65a7da8c0 100644 --- a/rascal-vscode-extension/src/test/vscode-suite/dsl.test.ts +++ b/rascal-vscode-extension/src/test/vscode-suite/dsl.test.ts @@ -25,7 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -import { VSBrowser, WebDriver, Workbench } from 'vscode-extension-tester'; +import { NotificationType, VSBrowser, WebDriver, Workbench } from 'vscode-extension-tester'; import { Delays, IDEOperations, RascalREPL, TestWorkspace, ignoreFails, printRascalOutputOnFailure, sleep } from './utils'; import * as fs from 'fs/promises'; @@ -195,6 +195,25 @@ parameterizedDescribe(function (errorRecovery: boolean) { await ide.assertLineBecomes(editor, 9, "b := 2;", "a variable should be changed to b"); }); + it("show message works", async function() { + if (errorRecovery) { this.skip(); } + const editor = await ide.openModule(TestWorkspace.picoFile); + const lens = await driver.wait(() => editor.getCodeLens("Show info message."), Delays.verySlow, "'Show info message' lens should be available"); + await lens!.click(); + await driver.wait(async () => { + const notificationCenter = await new Workbench().openNotificationsCenter(); + const notifications = await notificationCenter.getNotifications(NotificationType.Info); + for (const notification of notifications) { + const message = await notification.getMessage(); + if (message.startsWith("Info message")) { + await notificationCenter.clearAllNotifications(); + return true; + } + } + return false; + }, Delays.verySlow, "The info message should be shown after clicking the lens"); + }); + it("quick fix works", async function() { if (errorRecovery) { this.skip(); } const editor = await ide.openModule(TestWorkspace.picoFile);