Skip to content

Commit

Permalink
feat: support showMessageRequest with notification
Browse files Browse the repository at this point in the history
Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr authored and fbricon committed May 14, 2024
1 parent 0ad1ea8 commit 2de1906
Show file tree
Hide file tree
Showing 17 changed files with 228 additions and 98 deletions.
16 changes: 12 additions & 4 deletions docs/LSPSupport.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Current state of [Window Features]( https://microsoft.github.io/language-server-

*[window/showMessage](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessage). (see [implementation details](#show-message))
*[window/showMessageRequest](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessageRequest) (see [implementation details](#show-message-request))
* [window/logMessage](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_logMessage).
* [window/logMessage](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_logMessage) (see [implementation details](./UserGuide.md#lsp-console))
*[window/showDocument](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showDocument).
*[telemetry/event](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#telemetry_event).

Expand Down Expand Up @@ -341,10 +341,14 @@ Here is an example with [Rust Analyzer](https://rust-analyzer.github.io/) report
"message": "Failed to discover workspace.\nConsider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\nFailed to load workspaces."
}
```
is rendered as:
is rendered as a `Balloon` notification:

![window/showMessage](./images/lsp-support/window_showMessage.png)

You can change the notification behavior of `LSP/window/showMessage` by using the standard UI `Notifications` preferences :

![window/showMessage Notification](./images/lsp-support/window_showMessage_Notification.png)

## Show Message Request

[window/showMessageRequest](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessageRequest) is supported.
Expand All @@ -368,6 +372,10 @@ Here is an example with [Scala Language Server (MetaLS)](./user-defined-ls/metal
"message": "No .scalafmt.conf file detected. How would you like to proceed:"
}
```
is rendered as:
is rendered as a `Sticky balloon` notification:

![window/showMessageRequest](./images/lsp-support/window_showMessageRequest.png)

You can change the notification behavior of `LSP/window/showMessageRequest` by using the standard UI `Notifications` preferences :

![window/showMessageRequest](./images/lsp-support/window_showMessageRequest.png)
![window/showMessageRequest Notification](./images/lsp-support/window_showMessageRequest_Notification.png)
6 changes: 5 additions & 1 deletion docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ The state of the servers is visible, stop and restart is available with a right-
The communication details between the IDE and the language servers are seen in the "LSP consoles" pane.
In verbose mode, the messages can be expanded for more details:

![LSP console messages](./images/LSPConsole.png)
![LSP console Traces](./images/LSPConsole.png)

If the language server logs messages via [window/logMessage](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_logMessage), you can see them in the `Logs` tab:

![LSP console Logs](./images/LSPConsole_Logs.png)

When a language server is started, several actions are available, like stopping the language server or copying the command starting the language server :

Expand Down
Binary file modified docs/images/LSPConsole.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/LSPConsole_Logs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/lsp-support/window_showMessageRequest.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public static boolean isWillRenameFilesSupported(@Nullable ServerCapabilities se
* @param command the LSP command.
* @return true if the given LSP command is supported by the language server and false otherwise.
*/
public boolean canSupportsCommand(@Nullable Command command) {
public boolean supportsCommand(@Nullable Command command) {
if (command == null) {
return false;
}
Expand Down
97 changes: 75 additions & 22 deletions src/main/java/com/redhat/devtools/lsp4ij/ServerMessageHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupListener;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.redhat.devtools.lsp4ij.console.LSPConsoleToolWindowPanel;
import com.redhat.devtools.lsp4ij.internal.StringUtils;
import org.eclipse.lsp4j.*;
import org.jetbrains.annotations.NotNull;
Expand All @@ -33,19 +38,24 @@

public class ServerMessageHandler {

private static final ShowDocumentResult SHOW_DOCUMENT_RESULT_WITH_SUCCESS = new ShowDocumentResult(true);
public static final String LSP_WINDOW_SHOW_MESSAGE_GROUP_ID = "LSP/window/showMessage";
public static final String LSP_WINDOW_SHOW_MESSAGE_REQUEST_GROUP_ID = "LSP/window/showMessageRequest";

public static final ShowDocumentResult SHOW_DOCUMENT_RESULT_WITH_FAILURE = new ShowDocumentResult(false);
private static final ShowDocumentResult SHOW_DOCUMENT_RESULT_WITH_SUCCESS = new ShowDocumentResult(true);
private static final ShowDocumentResult SHOW_DOCUMENT_RESULT_WITH_FAILURE = new ShowDocumentResult(false);

private ServerMessageHandler() {
// this class shouldn't be instantiated
}

private static final String NAME_PATTERN = "%s (%s)"; //$NON-NLS-1$


public static void logMessage(LanguageServerWrapper wrapper, MessageParams params) {
//TODO: implements message to console
/**
* Implements the LSP <a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_logMessage">window/logMessage</a> specification.
*
* @param serverWrapper the language server wrapper
* @param params the message request parameters
*/
public static void logMessage(LanguageServerWrapper serverWrapper, MessageParams params) {
LSPConsoleToolWindowPanel.showLog(serverWrapper.getServerDefinition(), params, serverWrapper.getProject() );
}

private static Icon messageTypeToIcon(MessageType type) {
Expand All @@ -68,35 +78,78 @@ private static NotificationType messageTypeToNotificationType(MessageType type)
/**
* Implements the LSP <a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessage">window/showMessage</a> specification.
*
* @param title the notification title
* @param params the message parameters
* @param title the notification title.
* @param params the message parameters.
* @param project the project.
*/
public static void showMessage(String title, MessageParams params) {
Notification notification = new Notification(LanguageServerBundle.message("language.server.protocol.groupId"), title, toHTML(params.getMessage()), messageTypeToNotificationType(params.getType()));
public static void showMessage(@NotNull String title,
@NotNull MessageParams params,
@NotNull Project project) {
Notification notification = new Notification(LSP_WINDOW_SHOW_MESSAGE_GROUP_ID,
title,
toHTML(params.getMessage()),
messageTypeToNotificationType(params.getType()));
notification.setListener(NotificationListener.URL_OPENING_LISTENER);
notification.setIcon(messageTypeToIcon(params.getType()));
Notifications.Bus.notify(notification);
Notifications.Bus.notify(notification, project);
}

/**
* Implements the LSP <a href="https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessageRequest">window/showMessageRequest</a> specification.
*
* @param wrapper the language server wrapper
* @param serverWrapper the language server wrapper
* @param params the message request parameters
*/
public static CompletableFuture<MessageActionItem> showMessageRequest(LanguageServerWrapper wrapper, ShowMessageRequestParams params) {
String[] options = params.getActions().stream().map(MessageActionItem::getTitle).toArray(String[]::new);
public static CompletableFuture<MessageActionItem> showMessageRequest(@NotNull LanguageServerWrapper serverWrapper,
@NotNull ShowMessageRequestParams params) {
CompletableFuture<MessageActionItem> future = new CompletableFuture<>();

ApplicationManager.getApplication()
.invokeLater(() -> {
MessageActionItem result = new MessageActionItem();
int dialogResult = Messages.showIdeaMessageDialog(null, params.getMessage(), wrapper.getServerDefinition().getDisplayName(), options, 0, Messages.getInformationIcon(), null);
if (dialogResult != -1) {
result.setTitle(options[dialogResult]);
String languageServerName = serverWrapper.getServerDefinition().getDisplayName();
String title = params.getMessage();
String content = toHTML(params.getMessage());
final Notification notification = new Notification(
LSP_WINDOW_SHOW_MESSAGE_REQUEST_GROUP_ID,
languageServerName,
content,
messageTypeToNotificationType(params.getType()));
notification.setIcon(messageTypeToIcon(params.getType()));
for (var action : params.getActions()) {
notification.addAction(new AnAction(action.getTitle()) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
MessageActionItem result = new MessageActionItem();
result.setTitle(action.getTitle());
future.complete(result);
notification.expire();
}

@Override
public @NotNull ActionUpdateThread getActionUpdateThread() {
return ActionUpdateThread.BGT;
}
});
}
notification.whenExpired(()-> {
if (!future.isDone()) {
future.cancel(true);
}
});

Notifications.Bus.notify(notification, serverWrapper.getProject());
var balloon= notification.getBalloon();
if (balloon != null) {
balloon.addListener(new JBPopupListener() {
@Override
public void onClosed(@NotNull LightweightWindowEvent event) {
if (!future.isDone()) {
future.cancel(true);
}
}
});
}
future.complete(result);
});

return future;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public final CompletableFuture<MessageActionItem> showMessageRequest(ShowMessage

@Override
public final void showMessage(MessageParams messageParams) {
ServerMessageHandler.showMessage(wrapper.getServerDefinition().getDisplayName(), messageParams);
ServerMessageHandler.showMessage(wrapper.getServerDefinition().getDisplayName(), messageParams, getProject());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,10 @@ private static boolean executeCommandServerSide(@NotNull Command command,
.exceptionally(error -> {
// Language server throws an error when executing a command
// Display it with an IntelliJ notification.
var languageServerWrapper = languageServer.getServerWrapper();
MessageParams messageParams = new MessageParams(MessageType.Error, error.getMessage());
var languageServerDefinition = languageServer.getServerWrapper().getServerDefinition();
ServerMessageHandler.showMessage(languageServerDefinition.getDisplayName(), messageParams);
var languageServerDefinition = languageServerWrapper.getServerDefinition();
ServerMessageHandler.showMessage(languageServerDefinition.getDisplayName(), messageParams, languageServerWrapper.getProject());
return error;
});
});
Expand All @@ -135,7 +136,7 @@ private static boolean executeCommandServerSide(@NotNull Command command,
private static CompletableFuture<LanguageServer> getLanguageServerForCommand(@NotNull Command command,
@NotNull LanguageServerItem languageServer) {

if (languageServer.canSupportsCommand(command)) {
if (languageServer.supportsCommand(command)) {
return languageServer
.getServerWrapper()
.getInitializedServer();
Expand Down
Loading

0 comments on commit 2de1906

Please sign in to comment.