Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions org.eclipse.lsp4e/schema/languageServer.exsd
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ If set to a number bigger than zero, the server will run until the timeout is re
</documentation>
</annotation>
</attribute>
<attribute name="configurationHandler" type="string">
<annotation>
<documentation>
An optional configuration handler that enables to send and update the configuration of the language server. The initial configuration is sent after receiving the initialized notification message from the language server.
</documentation>
<appinfo>
<meta.attribute kind="java" basedOn=":org.eclipse.lsp4e.IConfigurationHandler"/>
</appinfo>
</annotation>
</attribute>
</complexType>
</element>

Expand Down
74 changes: 74 additions & 0 deletions org.eclipse.lsp4e/src/org/eclipse/lsp4e/IConfigurationHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.eclipse.lsp4e;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.plugin.AbstractUIPlugin;

/**
* Configuration handler that enables to send and update
* the configuration of the language server.
* It also contains a default implementation that can be instantiated.
*/
public interface IConfigurationHandler {

/**
* Returns a {@link Map} containing all preference names and their values.
* Usually used during the initialization of the language server to send
* all the configuration at once.
* @return
*/
@SuppressWarnings("null")
default @NonNull Map<String, Object> getConfiguration() {
return Collections.emptyMap();
}

/**
* Returns a {@link Map} containing all preference names and their values.
* Used to send multiple configuration change to the language server at once.
* @return
*/
@SuppressWarnings("null")
default @NonNull Map<String, Object> getConfiguration(final List<String> prefList) {
return Collections.emptyMap();
}

/**
* Returns a {@link Map} containing the requested preference name and its value,
* usually used by a preference change listener.
* The Map will be converted to JSON by LSP4J before the transmission.
* @param preferenceName name of preference
* @return {@link Map} containing the requested preference name and its value
*/
@SuppressWarnings("null")
default @NonNull Map<String, Object> getConfiguration(final String prefName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some servers asks for concrete preference (for example vue language-server) in this case getConfiguration can be for example boolean

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I don't get this. What do you mean by "can be"? The return value or the parameter or what do you mean?

return Collections.emptyMap();
}

/**
* Returns the preference store containing the configuration of the language server.
* This must be overridden by the plugin developer, usually with the actual
* {@code Activator.getDefault().getPreferenceStore()}
* @see AbstractUIPlugin#getPreferenceStore()
* @return the preference store
*/
public @NonNull IPreferenceStore getPreferenceStore();

/**
* Default implementation that can be instantiated
*/
final static class DefaultConfigurationHandler implements IConfigurationHandler {
public DefaultConfigurationHandler() {
// Do nothing
}

@SuppressWarnings("null")
@Override
public @NonNull IPreferenceStore getPreferenceStore() {
return LanguageServerPlugin.getDefault().getPreferenceStore();
}
}
}
19 changes: 19 additions & 0 deletions org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.lsp4e.LanguageServersRegistry.LanguageServerDefinition;
import org.eclipse.lsp4e.internal.FileBufferListenerAdapter;
import org.eclipse.lsp4e.internal.SupportedFeatures;
Expand All @@ -74,6 +76,7 @@
import org.eclipse.lsp4j.ClientCapabilities;
import org.eclipse.lsp4j.ClientInfo;
import org.eclipse.lsp4j.CodeActionOptions;
import org.eclipse.lsp4j.DidChangeConfigurationParams;
import org.eclipse.lsp4j.DidChangeWorkspaceFoldersParams;
import org.eclipse.lsp4j.DocumentFormattingOptions;
import org.eclipse.lsp4j.DocumentRangeFormattingOptions;
Expand Down Expand Up @@ -142,6 +145,15 @@ public void dirtyStateChanged(IFileBuffer buffer, boolean isDirty) {

};

private final IPropertyChangeListener propertyChangeListener = new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
final IConfigurationHandler configHandler = serverDefinition.getConfigurationHandler();
languageServer.getWorkspaceService().didChangeConfiguration(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about configuration sharing? For example HTML LS can ask for CSS or JAVASCRIPT settings or just workspace settings (http)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think any LS can ask for any section, however the LS is not aware of what configuration sections are available in/at the client. So by default the configuration is shared, just need to ask the client properly.

new DidChangeConfigurationParams(configHandler.getConfiguration(event.getProperty())));
}
};

@NonNull
public final LanguageServerDefinition serverDefinition;
@Nullable
Expand Down Expand Up @@ -307,6 +319,11 @@ public synchronized void start() throws IOException {
this.initiallySupportsWorkspaceFolders = supportsWorkspaceFolders(serverCapabilities);
}).thenRun(() -> {
this.languageServer.initialized(new InitializedParams());
}).thenRun(() -> {
final IConfigurationHandler configHandler = serverDefinition.getConfigurationHandler();
this.languageServer.getWorkspaceService().didChangeConfiguration(
new DidChangeConfigurationParams(configHandler.getConfiguration()));
configHandler.getPreferenceStore().addPropertyChangeListener(propertyChangeListener);
}).thenRun(() -> {
final Map<URI, IDocument> toReconnect = filesToReconnect;
initializeFuture.thenRunAsync(() -> {
Expand Down Expand Up @@ -495,6 +512,8 @@ public synchronized void stop() {
this.languageServer = null;

FileBuffers.getTextFileBufferManager().removeFileBufferListener(fileBufferListener);
this.serverDefinition.getConfigurationHandler()
.getPreferenceStore().removePropertyChangeListener(propertyChangeListener);
}

public @Nullable CompletableFuture<@NonNull LanguageServerWrapper> connect(IDocument document, @NonNull IFile file)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public class LanguageServersRegistry {
private static final String LABEL_ATTRIBUTE = "label"; //$NON-NLS-1$
private static final String ENABLED_WHEN_ATTRIBUTE = "enabledWhen"; //$NON-NLS-1$
private static final String ENABLED_WHEN_DESC = "description"; //$NON-NLS-1$
private static final String CONFIGURATION_HANDLER_ATTRIBUTE = "configurationHandler"; //$NON-NLS-1$

public abstract static class LanguageServerDefinition {
public final @NonNull String id;
Expand Down Expand Up @@ -123,6 +124,10 @@ public <S extends LanguageServer> Launcher.Builder<S> createLauncherBuilder() {
return new Launcher.Builder<>();
}

public IConfigurationHandler getConfigurationHandler() {
return new IConfigurationHandler.DefaultConfigurationHandler();
}

}

static class ExtensionLanguageServerDefinition extends LanguageServerDefinition {
Expand Down Expand Up @@ -224,6 +229,19 @@ public <S extends LanguageServer> Launcher.Builder<S> createLauncherBuilder() {
return super.createLauncherBuilder();
}

@Override
public IConfigurationHandler getConfigurationHandler() {
final String configHandler = extension.getAttribute(CONFIGURATION_HANDLER_ATTRIBUTE);
if (configHandler != null && !configHandler.isEmpty()) {
try {
return (IConfigurationHandler) extension.createExecutableExtension(CONFIGURATION_HANDLER_ATTRIBUTE);
} catch (CoreException e) {
LanguageServerPlugin.logError(e);
}
}
return super.getConfigurationHandler();
}

}

static class LaunchConfigurationLanguageServerDefinition extends LanguageServerDefinition {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.lsp4j.CompletionItemResolveSupportCapabilities;
import org.eclipse.lsp4j.CompletionListCapabilities;
import org.eclipse.lsp4j.DefinitionCapabilities;
import org.eclipse.lsp4j.DidChangeConfigurationCapabilities;
import org.eclipse.lsp4j.DocumentHighlightCapabilities;
import org.eclipse.lsp4j.DocumentLinkCapabilities;
import org.eclipse.lsp4j.DocumentSymbolCapabilities;
Expand Down Expand Up @@ -142,6 +143,7 @@ public class SupportedFeatures {
workspaceClientCapabilities.setWorkspaceEdit(editCapabilities);
CodeLensWorkspaceCapabilities codeLensWorkspaceCapabilities = new CodeLensWorkspaceCapabilities(true);
workspaceClientCapabilities.setCodeLens(codeLensWorkspaceCapabilities);
workspaceClientCapabilities.setDidChangeConfiguration(new DidChangeConfigurationCapabilities(Boolean.FALSE));
return workspaceClientCapabilities;
}

Expand Down