Skip to content

Commit

Permalink
Fix duplicate client/registerCapability for workspace/executeCommand
Browse files Browse the repository at this point in the history
Fixes #937

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Jan 5, 2021
1 parent 200a7aa commit c1f855c
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
*/
package org.eclipse.lemminx;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;

Expand All @@ -32,40 +32,33 @@
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
import org.eclipse.lsp4j.services.WorkspaceService;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* XML workspace service.
*
*/
public class XMLWorkspaceService implements WorkspaceService, IXMLCommandService {

private static final String WORKSPACE_EXECUTE_COMMAND = "workspace/executeCommand";

private final XMLLanguageServer xmlLanguageServer;

private final Map<String, IDelegateCommandHandler> commands;

private final Map<String, String> commandRegistrations;


public XMLWorkspaceService(XMLLanguageServer xmlLanguageServer) {
this.xmlLanguageServer = xmlLanguageServer;
this.commands = new HashMap<>();
this.commandRegistrations = new HashMap<>();
}

@Override
public CompletableFuture<List<? extends SymbolInformation>> symbol(WorkspaceSymbolParams params) {
return null;
}



@Override
public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
synchronized (commands) {
IDelegateCommandHandler handler = commands.get(params.getCommand());
if (handler == null) {
throw new ResponseErrorException(new ResponseError(ResponseErrorCode.InternalError, "No command handler for the command: " + params.getCommand(), null));
throw new ResponseErrorException(new ResponseError(ResponseErrorCode.InternalError,
"No command handler for the command: " + params.getCommand(), null));
}
return CompletableFutures.computeAsync(cancelChecker -> {
try {
Expand All @@ -82,7 +75,7 @@ public CompletableFuture<Object> executeCommand(ExecuteCommandParams params) {
});
}
}

@Override
public void didChangeConfiguration(DidChangeConfigurationParams params) {
xmlLanguageServer.updateSettings(params.getSettings());
Expand All @@ -91,9 +84,10 @@ public void didChangeConfiguration(DidChangeConfigurationParams params) {

@Override
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
XMLTextDocumentService xmlTextDocumentService = (XMLTextDocumentService) xmlLanguageServer.getTextDocumentService();
XMLTextDocumentService xmlTextDocumentService = (XMLTextDocumentService) xmlLanguageServer
.getTextDocumentService();
List<FileEvent> changes = params.getChanges();
for (FileEvent change: changes) {
for (FileEvent change : changes) {
if (!xmlTextDocumentService.documentIsOpen(change.getUri())) {
xmlTextDocumentService.doSave(change.getUri());
}
Expand All @@ -106,9 +100,6 @@ public void registerCommand(String commandId, IDelegateCommandHandler handler) {
if (commands.containsKey(commandId)) {
throw new IllegalArgumentException("Command with id '" + commandId + "' is already registered");
}
String registrationId = UUID.randomUUID().toString();
xmlLanguageServer.getCapabilityManager().registerCapability(registrationId, WORKSPACE_EXECUTE_COMMAND, ImmutableMap.of("commands", ImmutableList.of(commandId)));
commandRegistrations.put(commandId, registrationId);
commands.put(commandId, handler);
}
}
Expand All @@ -117,15 +108,18 @@ public void registerCommand(String commandId, IDelegateCommandHandler handler) {
public void unregisterCommand(String commandId) {
synchronized (commands) {
commands.remove(commandId);
String registrationId = commandRegistrations.remove(commandId);
if (registrationId != null) {
xmlLanguageServer.getCapabilityManager().unregisterCapability(registrationId, WORKSPACE_EXECUTE_COMMAND);
}
}
}

@Override
public CompletableFuture<Object> executeClientCommand(ExecuteCommandParams command) {
return xmlLanguageServer.getLanguageClient().executeClientCommand(command);
}

@Override
public void endCommandsRegistration() {
if (!commands.isEmpty()) {
xmlLanguageServer.getCapabilityManager().registerExecuteCommand(new ArrayList<>(commands.keySet()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ public void initializeParams(InitializeParams params) {
public void doSave(ISaveContext saveContext) {
if (initialized) {
extensions.stream().forEach(extension -> extension.doSave(saveContext));
} else if (this.initialSaveContext == null || (saveContext != null && saveContext.getType() == SaveContextType.SETTINGS)) {
} else if (this.initialSaveContext == null
|| (saveContext != null && saveContext.getType() == SaveContextType.SETTINGS)) {
// capture initial configuration iff:
// 1. the saveContext is for configuration, not document save
// 2. we haven't captured settings before
Expand Down Expand Up @@ -208,11 +209,17 @@ private synchronized void initialize() {
return;
}

if (commandService != null) {
commandService.beginCommandsRegistration();
}
ServiceLoader<IXMLExtension> extensions = ServiceLoader.load(IXMLExtension.class);
extensions.forEach(extension -> {
registerExtension(extension);
});
initialized = true;
if (commandService != null) {
commandService.endCommandsRegistration();
}
}

void registerExtension(IXMLExtension extension) {
Expand Down Expand Up @@ -389,10 +396,10 @@ public IXMLNotificationService getNotificationService() {
public void setNotificationService(IXMLNotificationService notificationService) {
this.notificationService = notificationService;
}

/**
* Returns the XML document validation service
*
*
* @return the validation service
*/
public IXMLValidationService getValidationService() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,54 +18,64 @@
import org.eclipse.lsp4j.jsonrpc.CancelChecker;

/**
* Service available to XML LS extensions to add/remove/execute commands via the XML LS
* Service available to XML LS extensions to add/remove/execute commands via the
* XML LS
*
*
* @author Alex Boyko
*
*/
public interface IXMLCommandService {

/**
* Command handler to register with the workspace service
*/
@FunctionalInterface
public interface IDelegateCommandHandler {

/**
* Executes a command
* @param params command execution parameters
*
* @param params command execution parameters
* @param cancelChecker check if cancel has been requested
* @return the result of the command
* @throws Exception the unhandled exception will be wrapped in
* <code>org.eclipse.lsp4j.jsonrpc.ResponseErrorException</code>
* and be wired back to the JSON-RPC protocol caller
*/
Object executeCommand(ExecuteCommandParams params, CancelChecker cancelChecker) throws Exception;
Object executeCommand(ExecuteCommandParams params, CancelChecker cancelChecker) throws Exception;
}

/**
* Registers a command with the language server
*
* @param commandId unique id of the command
* @param handler command handler function
* @param handler command handler function
*/
void registerCommand(String commandId, IDelegateCommandHandler handler);

/**
* Unregisters the command from the language server
*
* @param commandId unique id of the command to unregister
*/
void unregisterCommand(String commandId);

/**
* Executes a command via the client. The command can be registered by any language server
* Executes a command via the client. The command can be registered by any
* language server
*
* @param command the LSP command
* @param command the LSP command
* @return the result of the command
*/
CompletableFuture<Object> executeClientCommand(ExecuteCommandParams command);


default void beginCommandsRegistration() {

}

default void endCommandsRegistration() {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private ServerCapabilitiesConstants() {
public static final String CODE_LENS_ID = UUID.randomUUID().toString();
public static final String SIGNATURE_HELP_ID = UUID.randomUUID().toString();
public static final String RENAME_ID = UUID.randomUUID().toString();
public static final String EXECUTE_COMMAND_ID = UUID.randomUUID().toString();
public static final String WORKSPACE_EXECUTE_COMMAND_ID = UUID.randomUUID().toString();
public static final String WORKSPACE_SYMBOL_ID = UUID.randomUUID().toString();
public static final String DOCUMENT_SYMBOL_ID = UUID.randomUUID().toString();
public static final String CODE_ACTION_ID = UUID.randomUUID().toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_RENAME;
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_TYPEDEFINITION;
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.TYPEDEFINITION_ID;
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.WORKSPACE_EXECUTE_COMMAND;
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.WORKSPACE_EXECUTE_COMMAND_ID;
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.WORKSPACE_WATCHED_FILES;
import static org.eclipse.lemminx.settings.capabilities.ServerCapabilitiesConstants.WORKSPACE_WATCHED_FILES_ID;

Expand All @@ -56,6 +58,7 @@
import org.eclipse.lemminx.settings.XMLSymbolSettings;
import org.eclipse.lsp4j.ClientCapabilities;
import org.eclipse.lsp4j.DidChangeWatchedFilesRegistrationOptions;
import org.eclipse.lsp4j.ExecuteCommandOptions;
import org.eclipse.lsp4j.FileSystemWatcher;
import org.eclipse.lsp4j.Registration;
import org.eclipse.lsp4j.RegistrationParams;
Expand Down Expand Up @@ -181,6 +184,11 @@ private void registerWatchedFiles() {
registerCapability(WORKSPACE_WATCHED_FILES_ID, WORKSPACE_WATCHED_FILES, options);
}

public void registerExecuteCommand(List<String> commands) {
registerCapability(WORKSPACE_EXECUTE_COMMAND_ID, WORKSPACE_EXECUTE_COMMAND,
new ExecuteCommandOptions(commands));
}

/**
* Registers(indicates the servers ability to support the service) all
* capabilities that have the ability to be turned on/off on the client side
Expand Down

0 comments on commit c1f855c

Please sign in to comment.