diff --git a/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/META-INF/MANIFEST.MF b/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/META-INF/MANIFEST.MF index 3ed752af..167c6cca 100644 --- a/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/META-INF/MANIFEST.MF +++ b/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/META-INF/MANIFEST.MF @@ -6,6 +6,7 @@ Bundle-SymbolicName: org.eclipse.lsp4jakarta.lsp4e.core;singleton:=true Bundle-Version: 0.2.0.qualifier Bundle-Activator: org.eclipse.lsp4jakarta.lsp4e.Activator Require-Bundle: + com.google.gson, org.eclipse.lsp4e, org.eclipse.core.runtime, org.eclipse.ui.workbench, diff --git a/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLSConnection.java b/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLSConnection.java index 27b7618c..3acb0328 100644 --- a/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLSConnection.java +++ b/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLSConnection.java @@ -99,9 +99,14 @@ public Object getInitializationOptions(URI rootUri) { trace.put("server", "verbose"); tools.put("trace", trace); jakarta.put("tools", tools); - settings.put("jakararta", jakarta); + settings.put("jakarta", jakarta); root.put("settings", settings); + // Set extended capabilities. + Map extendedClientCapabilities = new HashMap<>(); + extendedClientCapabilities.put("shouldLanguageServerExitOnShutdown", Boolean.TRUE); + root.put("extendedClientCapabilities", extendedClientCapabilities); + return root; } } diff --git a/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLanguageClient.java b/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLanguageClient.java index da9bd5fd..bd939929 100755 --- a/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLanguageClient.java +++ b/jakarta.eclipse/org.eclipse.lsp4jakarta.lsp4e.core/src/main/java/org/eclipse/lsp4jakarta/lsp4e/JakartaLanguageClient.java @@ -35,6 +35,8 @@ import org.eclipse.lsp4jakarta.commons.JakartaJavaProjectLabelsParams; import org.eclipse.lsp4jakarta.commons.JavaCursorContextResult; import org.eclipse.lsp4jakarta.commons.ProjectLabelInfoEntry; +import org.eclipse.lsp4jakarta.commons.codeaction.CodeActionResolveData; +import org.eclipse.lsp4jakarta.commons.utils.JSONUtility; import org.eclipse.lsp4jakarta.jdt.core.ProjectLabelManager; import org.eclipse.lsp4jakarta.jdt.core.PropertiesManagerForJava; import org.eclipse.lsp4jakarta.jdt.internal.core.ls.JDTUtilsLSImpl; @@ -56,6 +58,9 @@ public boolean isCanceled() { return monitor; } + /** + * {@inheritDoc} + */ @Override public CompletableFuture getJavaCompletion(JakartaJavaCompletionParams javaParams) { return CompletableFutures.computeAsync(cancelChecker -> { @@ -74,6 +79,9 @@ public CompletableFuture getJavaCompletion(JakartaJ }); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture> getAllJavaProjectLabels() { return CompletableFutures.computeAsync((cancelChecker) -> { @@ -82,6 +90,9 @@ public CompletableFuture> getAllJavaProjectLabels() }); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture getJavaProjectLabels(JakartaJavaProjectLabelsParams javaParams) { return CompletableFutures.computeAsync((cancelChecker) -> { @@ -91,6 +102,9 @@ public CompletableFuture getJavaProjectLabels(JakartaJava }); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture getJavaFileInfo(JakartaJavaFileInfoParams javaParams) { return CompletableFutures.computeAsync(cancelChecker -> { @@ -99,6 +113,9 @@ public CompletableFuture getJavaFileInfo(JakartaJavaFileInf }); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture> getJavaDiagnostics( JakartaJavaDiagnosticsParams javaParams) { @@ -113,6 +130,9 @@ public CompletableFuture> getJavaDiagnostics( }); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture> getJavaCodeAction(JakartaJavaCodeActionParams javaParams) { return CompletableFutures.computeAsync((cancelChecker) -> { @@ -126,11 +146,16 @@ public CompletableFuture> getJavaCodeAction(JakartaJavaCodeActi }); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture resolveCodeAction(CodeAction unresolved) { return CompletableFutures.computeAsync((cancelChecker) -> { IProgressMonitor monitor = getProgressMonitor(cancelChecker); try { + CodeActionResolveData resolveData = JSONUtility.toModel(unresolved.getData(), CodeActionResolveData.class); + unresolved.setData(resolveData); return (CodeAction) PropertiesManagerForJava.getInstance().resolveCodeAction(unresolved, JDTUtilsLSImpl.getInstance(), monitor); } catch (JavaModelException e) { diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/META-INF/MANIFEST.MF b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/META-INF/MANIFEST.MF index c86ec67b..bc06bfa8 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/META-INF/MANIFEST.MF +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/META-INF/MANIFEST.MF @@ -28,6 +28,7 @@ Bundle-ActivationPolicy: lazy Bundle-ClassPath: . Export-Package: org.eclipse.lsp4jakarta.commons, + org.eclipse.lsp4jakarta.commons.codeaction, org.eclipse.lsp4jakarta.jdt.core, org.eclipse.lsp4jakarta.jdt.core.utils, org.eclipse.lsp4jakarta.jdt.internal.core.ls diff --git a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/pom.xml b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/pom.xml index 292352be..7be389ee 100644 --- a/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/pom.xml +++ b/jakarta.jdt/org.eclipse.lsp4jakarta.jdt.core/pom.xml @@ -24,13 +24,6 @@ Eclipse Public License 2.0 - - - com.google.code.gson - gson - 2.9.0 - - diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaLanguageServer.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaLanguageServer.java index d3d00ce0..1daafc85 100644 --- a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaLanguageServer.java +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaLanguageServer.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2020 IBM Corporation and others. +* Copyright (c) 2020, 2023 IBM Corporation and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,13 +15,15 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.logging.Logger; -import org.eclipse.lsp4j.CompletionOptions; import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.InitializedParams; import org.eclipse.lsp4j.ServerCapabilities; -import org.eclipse.lsp4j.TextDocumentSyncKind; import org.eclipse.lsp4j.jsonrpc.CompletableFutures; import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageServer; @@ -35,8 +37,20 @@ import org.eclipse.lsp4jakarta.ls.api.JakartaJavaProjectLabelsProvider; import org.eclipse.lsp4jakarta.ls.api.JakartaLanguageClientAPI; import org.eclipse.lsp4jakarta.ls.commons.ParentProcessWatcher.ProcessLanguageServer; +import org.eclipse.lsp4jakarta.ls.commons.client.ExtendedClientCapabilities; +import org.eclipse.lsp4jakarta.ls.commons.client.InitializationOptionsExtendedClientCapabilities; import org.eclipse.lsp4jakarta.ls.java.JakartaTextDocuments; - +import org.eclipse.lsp4jakarta.settings.AllJakartaSettings; +import org.eclipse.lsp4jakarta.settings.InitializationOptionsSettings; +import org.eclipse.lsp4jakarta.settings.JakartaGeneralClientSettings; +import org.eclipse.lsp4jakarta.settings.JakartaTraceSettings; +import org.eclipse.lsp4jakarta.settings.SharedSettings; +import org.eclipse.lsp4jakarta.settings.capabilities.JakartaCapabilityManager; +import org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesInitializer; + +/** + * Jakarta Language server. + */ public class JakartaLanguageServer implements LanguageServer, ProcessLanguageServer, JakartaJavaProjectLabelsProvider, JakartaJavaFileInfoProvider { private Integer parentProcessId; @@ -44,64 +58,124 @@ public class JakartaLanguageServer implements LanguageServer, ProcessLanguageSer private static final Logger LOGGER = Logger.getLogger(JakartaLanguageServer.class.getName()); private final WorkspaceService workspaceService; - private final TextDocumentService textDocumentService; + private final JakartaTextDocumentService textDocumentService; private final JakartaTextDocuments javaDocuments; + private final SharedSettings sharedSettings; private JakartaLanguageClientAPI languageClient; + private JakartaCapabilityManager capabilityManager; + /** + * Constructor + */ public JakartaLanguageServer() { - // Workspace service handles workspace settings changes and calls update - // settings. - javaDocuments = new JakartaTextDocuments(this, this); workspaceService = new JakartaWorkspaceService(this); - textDocumentService = new JakartaTextDocumentService(this, javaDocuments); + javaDocuments = new JakartaTextDocuments(this, this); + sharedSettings = new SharedSettings(); + textDocumentService = new JakartaTextDocumentService(this, sharedSettings, javaDocuments); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture initialize(InitializeParams params) { - LOGGER.info("Initializing Jakarta EE server"); + LOGGER.info("Initializing Jakarta EE server using: " + System.getProperty("java.home")); this.parentProcessId = params.getProcessId(); - ServerCapabilities serverCapabilities = new ServerCapabilities(); - serverCapabilities.setTextDocumentSync(TextDocumentSyncKind.Incremental); + // Consume the capabilities supported by the client. + ExtendedClientCapabilities extendedClientCapabilities = InitializationOptionsExtendedClientCapabilities.getExtendedClientCapabilities(params); + capabilityManager.setClientCapabilities(params.getCapabilities(), extendedClientCapabilities); + updateSettings(InitializationOptionsSettings.getSettings(params)); + textDocumentService.updateClientCapabilities(params.getCapabilities(), extendedClientCapabilities); + + // Send the capabilities supported by the sever to the client. + ServerCapabilities serverCapabilities = ServerCapabilitiesInitializer.getNonDynamicServerCapabilities(capabilityManager.getClientCapabilities()); InitializeResult initializeResult = new InitializeResult(serverCapabilities); - // Provide Completion Capability to the LS - initializeResult.getCapabilities().setCompletionProvider(new CompletionOptions(false, null)); - initializeResult.getCapabilities().setHoverProvider(true); - initializeResult.getCapabilities().setCodeActionProvider(true); + return CompletableFuture.completedFuture(initializeResult); } + /** + * Registers all capabilities that do not support client side preferences to + * turn on/off + * + * (non-Javadoc) + * + * @see org.eclipse.lsp4j.services.LanguageServer#initialized(org.eclipse.lsp4j. + * InitializedParams) + */ + @Override + public void initialized(InitializedParams params) { + capabilityManager.initializeCapabilities(); + } + + /** + * Update Jakarta settings configured by the client defined by the client flowing requests between + * the LS and JDT extensions. + * + * @param initializationOptionsSettings the Jakarta settings + */ public synchronized void updateSettings(Object initializationOptionsSettings) { if (initializationOptionsSettings == null) { return; } - // TODO: else update settings + + initializationOptionsSettings = AllJakartaSettings.getJakartaToolsSettings(initializationOptionsSettings); + JakartaGeneralClientSettings clientSettings = JakartaGeneralClientSettings.getGeneralJakartaSettings(initializationOptionsSettings); + if (clientSettings != null) { + JakartaTraceSettings newTrace = clientSettings.getTrace(); + if (newTrace != null) { + textDocumentService.updateTraceSettings(newTrace); + } + } } + /** + * {@inheritDoc} + */ @Override public CompletableFuture shutdown() { - // when shutting down LS, TextDocumentService.didClose() may not be called - // properly, need to clear existing diagnostics + // Perform some clean up. During shutdown, TextDocumentService.didClose() may not be called properly. ((JakartaTextDocumentService) textDocumentService).cleanDiagnostics(); + + // If requested by the client, on shutdown (i.e. last file closed), shutdown the language server. + if (capabilityManager.getClientCapabilities().shouldLanguageServerExitOnShutdown()) { + LOGGER.info("Jakarta EE server is shutding down"); + ScheduledExecutorService delayer = Executors.newScheduledThreadPool(1); + delayer.schedule(() -> exit(0), 1, TimeUnit.SECONDS); + } + return CompletableFutures.computeAsync(cc -> new Object()); } + /** + * {@inheritDoc} + */ @Override public void exit() { exit(0); } + /** + * {@inheritDoc} + */ @Override public void exit(int exitCode) { System.exit(exitCode); } + /** + * {@inheritDoc} + */ @Override public TextDocumentService getTextDocumentService() { return this.textDocumentService; } + /** + * {@inheritDoc} + */ @Override public WorkspaceService getWorkspaceService() { return this.workspaceService; @@ -113,27 +187,48 @@ public JakartaLanguageClientAPI getLanguageClient() { public void setLanguageClient(LanguageClient languageClient) { this.languageClient = (JakartaLanguageClientAPI) languageClient; + this.capabilityManager = new JakartaCapabilityManager(languageClient); } + /** + * {@inheritDoc} + */ @Override public long getParentProcessId() { return parentProcessId != null ? parentProcessId : 0; } + /** + * {@inheritDoc} + */ @Override public CompletableFuture getJavaProjectLabels( JakartaJavaProjectLabelsParams javaParams) { return getLanguageClient().getJavaProjectLabels(javaParams); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture> getAllJavaProjectLabels() { return getLanguageClient().getAllJavaProjectLabels(); } + /** + * {@inheritDoc} + */ @Override public CompletableFuture getJavaFileInfo(JakartaJavaFileInfoParams javaParams) { return getLanguageClient().getJavaFileInfo(javaParams); } + /** + * Returns the object that manages dynamic capabilities. + * + * @return The object that manages dynamic capabilities. + */ + public JakartaCapabilityManager getCapabilityManager() { + return capabilityManager; + } } diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaTextDocumentService.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaTextDocumentService.java index 6900c03f..675cabad 100644 --- a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaTextDocumentService.java +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/JakartaTextDocumentService.java @@ -22,6 +22,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; +import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.CodeActionParams; import org.eclipse.lsp4j.Command; @@ -35,7 +36,9 @@ import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.HoverParams; +import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.TextDocumentClientCapabilities; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4jakarta.commons.DocumentFormat; @@ -48,9 +51,12 @@ import org.eclipse.lsp4jakarta.ls.commons.BadLocationException; import org.eclipse.lsp4jakarta.ls.commons.TextDocument; import org.eclipse.lsp4jakarta.ls.commons.ValidatorDelayer; +import org.eclipse.lsp4jakarta.ls.commons.client.ExtendedClientCapabilities; import org.eclipse.lsp4jakarta.ls.java.JakartaTextDocuments; import org.eclipse.lsp4jakarta.ls.java.JakartaTextDocuments.JakartaTextDocument; import org.eclipse.lsp4jakarta.ls.java.JavaTextDocumentSnippetRegistry; +import org.eclipse.lsp4jakarta.settings.JakartaTraceSettings; +import org.eclipse.lsp4jakarta.settings.SharedSettings; import org.eclipse.lsp4jakarta.snippets.JavaSnippetCompletionContext; import org.eclipse.lsp4jakarta.snippets.SnippetContextForJava; @@ -59,14 +65,16 @@ public class JakartaTextDocumentService implements TextDocumentService { private static final Logger LOGGER = Logger.getLogger(JakartaTextDocumentService.class.getName()); private final JakartaLanguageServer jakartaLanguageServer; + private final SharedSettings sharedSettings; // Text document manager that maintains the contexts of the text documents private final JakartaTextDocuments documents; private ValidatorDelayer validatorDelayer; - public JakartaTextDocumentService(JakartaLanguageServer jls, JakartaTextDocuments jakartaTextDocuments) { + public JakartaTextDocumentService(JakartaLanguageServer jls, SharedSettings sharedSettings, JakartaTextDocuments jakartaTextDocuments) { this.jakartaLanguageServer = jls; + this.sharedSettings = sharedSettings; this.documents = jakartaTextDocuments; this.validatorDelayer = new ValidatorDelayer<>((javaTextDocument) -> { triggerValidationFor(javaTextDocument); @@ -103,7 +111,7 @@ public CompletableFuture, CompletionList>> completio final Integer finalizedCompletionOffset = completionOffset; boolean canSupportMarkdown = true; - boolean snippetsSupported = true; + boolean snippetsSupported = sharedSettings.getCompletionCapabilities().isCompletionSnippetsSupported(); cancelChecker.checkCanceled(); @@ -149,20 +157,16 @@ public CompletableFuture, CompletionList>> completio @Override public CompletableFuture>> codeAction(CodeActionParams params) { // Prepare the JakartaJavaCodeActionParams - JakartaJavaCodeActionParams jakartaCodeActionParams = new JakartaJavaCodeActionParams(); - jakartaCodeActionParams.setTextDocument(params.getTextDocument()); - jakartaCodeActionParams.setRange(params.getRange()); - jakartaCodeActionParams.setContext(params.getContext()); - - // TODO: Retrieve client capabilities, and pass it along in the parameter object: - // Investigate: - // jakartaCodeActionParams.setResourceOperationSupported(), - // jakartaCodeActionParams.setCommandConfigurationUpdateSupported(), - // jakartaCodeActionParams.etResolveSupported(). + JakartaJavaCodeActionParams codeActionParams = new JakartaJavaCodeActionParams(); + codeActionParams.setTextDocument(params.getTextDocument()); + codeActionParams.setRange(params.getRange()); + codeActionParams.setContext(params.getContext()); + codeActionParams.setResourceOperationSupported(jakartaLanguageServer.getCapabilityManager().getClientCapabilities().isResourceOperationSupported()); + codeActionParams.setResolveSupported(jakartaLanguageServer.getCapabilityManager().getClientCapabilities().isCodeActionResolveSupported()); // Pass the JakartaJavaCodeActionParams to IDE client, to be forwarded to the // JDT LS extension. - return jakartaLanguageServer.getLanguageClient().getJavaCodeAction(jakartaCodeActionParams) // + return jakartaLanguageServer.getLanguageClient().getJavaCodeAction(codeActionParams) // .thenApply(codeActions -> { // Return the corresponding list of CodeActions, put in an Either and wrap as a // CompletableFuture @@ -244,10 +248,10 @@ private void triggerValidationFor(List uris) { JakartaJavaDiagnosticsParams javaParams = new JakartaJavaDiagnosticsParams(uris, new JakartaJavaDiagnosticsSettings(null)); - // TODO: Use settings to see if markdown format is supported, or remove it if not needed. - // Leave it hard coded for now. - // sharedSettings.getHoverSettings().isContentFormatSupported(MarkupKind.MARKDOWN); - javaParams.setDocumentFormat(DocumentFormat.Markdown); + boolean markdownSupported = sharedSettings.getHoverSettings().isContentFormatSupported(MarkupKind.MARKDOWN); + if (markdownSupported) { + javaParams.setDocumentFormat(DocumentFormat.Markdown); + } jakartaLanguageServer.getLanguageClient().getJavaDiagnostics(javaParams).thenApply(diagnostics -> { if (diagnostics == null) { @@ -266,4 +270,29 @@ protected void cleanDiagnostics() { jakartaLanguageServer.getLanguageClient().publishDiagnostics(new PublishDiagnosticsParams(doc.getUri(), new ArrayList())); }); } + + /** + * Update shared settings from the client capabilities. + * + * @param capabilities the client capabilities + * @param extendedClientCapabilities the extended client capabilities + */ + public void updateClientCapabilities(ClientCapabilities capabilities, + ExtendedClientCapabilities extendedClientCapabilities) { + TextDocumentClientCapabilities textDocumentClientCapabilities = capabilities.getTextDocument(); + if (textDocumentClientCapabilities != null) { + sharedSettings.getCompletionCapabilities().setCapabilities(textDocumentClientCapabilities.getCompletion()); + sharedSettings.getHoverSettings().setCapabilities(textDocumentClientCapabilities.getHover()); + } + } + + /** + * Updates the trace settings defined by the client flowing requests between the LS and JDT extensions. + * + * @param newTrace The new trace setting. + */ + public void updateTraceSettings(JakartaTraceSettings newTrace) { + JakartaTraceSettings trace = sharedSettings.getTraceSettings(); + trace.update(newTrace); + } } diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/commons/client/ExtendedClientCapabilities.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/commons/client/ExtendedClientCapabilities.java new file mode 100644 index 00000000..f6efcf67 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/commons/client/ExtendedClientCapabilities.java @@ -0,0 +1,46 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.ls.commons.client; + +/** + * Extended client capabilities not defined by the LSP. + * + * Based on: https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/commons/client/ExtendedClientCapabilities.java + * + * @author Angelo ZERR + */ +public class ExtendedClientCapabilities { + + private boolean shouldLanguageServerExitOnShutdown; + + /** + * Sets the boolean permitting language server to exit on client + * shutdown() request, without waiting for client to call exit() + * + * @param shouldLanguageServerExitOnShutdown + */ + public void setShouldLanguageServerExitOnShutdown(boolean shouldLanguageServerExitOnShutdown) { + this.shouldLanguageServerExitOnShutdown = shouldLanguageServerExitOnShutdown; + } + + /** + * Returns true if the client should exit on shutdown() request and + * avoid waiting for an exit() request + * + * @return true if the language server should exit on shutdown() request + */ + public boolean shouldLanguageServerExitOnShutdown() { + return shouldLanguageServerExitOnShutdown; + } +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/commons/client/InitializationOptionsExtendedClientCapabilities.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/commons/client/InitializationOptionsExtendedClientCapabilities.java new file mode 100644 index 00000000..b71db403 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/ls/commons/client/InitializationOptionsExtendedClientCapabilities.java @@ -0,0 +1,64 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.ls.commons.client; + +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4jakarta.commons.utils.JSONUtility; + +/** + * Represents all extended client capabilities sent from the server + * + *
+ * "extendedClientCapabilities": {
+ *      ...
+ *      }
+ *  }
+ * 
+ */ +public class InitializationOptionsExtendedClientCapabilities { + + private ExtendedClientCapabilities extendedClientCapabilities; + + public ExtendedClientCapabilities getExtendedClientCapabilities() { + return extendedClientCapabilities; + } + + public void setExtendedClientCapabilities(ExtendedClientCapabilities extendedClientCapabilities) { + this.extendedClientCapabilities = extendedClientCapabilities; + } + + /** + * Returns the "settings" section of + * {@link InitializeParams#getInitializationOptions()}. + * + * Here a sample of initializationOptions + * + *
+     * "extendedClientCapabilities": {
+     *      ...
+     *      }
+     *  }
+     * 
+ * + * @param initializeParams + * @return the "extendedClientCapabilities" section of + * {@link InitializeParams#getInitializationOptions()}. + */ + public static ExtendedClientCapabilities getExtendedClientCapabilities(InitializeParams initializeParams) { + InitializationOptionsExtendedClientCapabilities root = JSONUtility.toModel( + initializeParams.getInitializationOptions(), + InitializationOptionsExtendedClientCapabilities.class); + return root != null ? root.getExtendedClientCapabilities() : null; + } +} diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/AllJakartaSettings.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/AllJakartaSettings.java new file mode 100644 index 00000000..60c3c007 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/AllJakartaSettings.java @@ -0,0 +1,74 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings; + +import org.eclipse.lsp4j.jsonrpc.json.adapters.JsonElementTypeAdapter; +import org.eclipse.lsp4jakarta.commons.utils.JSONUtility; + +import com.google.gson.annotations.JsonAdapter; + +/** + * Represents all settings under the 'jakarta' key + * + * { 'jakarta': {...} } + */ +public class AllJakartaSettings { + + private static class ToolsSettings { + + @JsonAdapter(JsonElementTypeAdapter.Factory.class) + private Object tools; + + public Object getTools() { + return tools; + } + + } + + @JsonAdapter(JsonElementTypeAdapter.Factory.class) + private Object jakarta; + + /** + * @return the jakarta capabilities + */ + public Object getJakarta() { + return jakarta; + } + + /** + * Sets the client specified Jakarta capabilities. + * + * @param jakarta The client specified Jakarta capabilities + */ + public void setJakarta(Object jakarta) { + this.jakarta = jakarta; + } + + /** + * Returns the client specific tool settings under root->settings->jakarta->tools + * + * @param initializationOptionsSettings The client specific settings. + * + * @return The client specific tool settings under root->settings->jakarta->tools + */ + public static Object getJakartaToolsSettings(Object initializationOptionsSettings) { + AllJakartaSettings rootSettings = JSONUtility.toModel(initializationOptionsSettings, + AllJakartaSettings.class); + if (rootSettings == null) { + return null; + } + ToolsSettings jakartaSettings = JSONUtility.toModel(rootSettings.getJakarta(), ToolsSettings.class); + return jakartaSettings != null ? jakartaSettings.getTools() : null; + } +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/InitializationOptionsSettings.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/InitializationOptionsSettings.java new file mode 100644 index 00000000..3d72d47b --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/InitializationOptionsSettings.java @@ -0,0 +1,70 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings; + +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.jsonrpc.json.adapters.JsonElementTypeAdapter; +import org.eclipse.lsp4jakarta.commons.utils.JSONUtility; + +import com.google.gson.annotations.JsonAdapter; + +/** + * Represents all settings sent from the client + * + * { 'settings': { 'jakarta': {...}, 'http': {...} } } + */ +public class InitializationOptionsSettings { + + @JsonAdapter(JsonElementTypeAdapter.Factory.class) + private Object settings; + + public Object getSettings() { + return settings; + } + + public void setSettings(Object settings) { + this.settings = settings; + } + + /** + * Returns the "settings" section of + * {@link InitializeParams#getInitializationOptions()}. + * + * Here a sample of initializationOptions + * + *
+     * "initializationOptions": {
+    		"settings": {
+    			"jakarta": {
+    				"tools": {
+    					"trace": {
+    					    "server: "verbose"
+    					}
+    				},
+    				...
+    			}
+    		}
+    	}
+     * 
+ * + * @param initializeParams + * @return the "settings" section of + * {@link InitializeParams#getInitializationOptions()}. + */ + public static Object getSettings(InitializeParams initializeParams) { + InitializationOptionsSettings root = JSONUtility.toModel(initializeParams.getInitializationOptions(), + InitializationOptionsSettings.class); + return root != null ? root.getSettings() : null; + } +} diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaGeneralClientSettings.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaGeneralClientSettings.java new file mode 100644 index 00000000..b9126065 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaGeneralClientSettings.java @@ -0,0 +1,65 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings; + +import org.eclipse.lsp4jakarta.commons.utils.JSONUtility; + +/** + * Class to hold all settings from the client side. + * + * + * This class is created through the deserialization of a JSON object. Each + * internal setting must be represented by a class and have: + * + * 1) A constructor with no parameters + * + * 2) The JSON key/parent for the settings must have the same name as a + * variable. + * + * eg: {"trace" : {...}} + * + * Based on: https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/MicroProfileGeneralClientSettings.java + */ +public class JakartaGeneralClientSettings { + + private JakartaTraceSettings trace; + + /** + * Returns the trace settings. + * + * @return the trace settings. + */ + public JakartaTraceSettings getTrace() { + return trace; + } + + /** + * Set the validation settings. + * + * @param trace the trace settings. + */ + public void setTrace(JakartaTraceSettings trace) { + this.trace = trace; + } + + /** + * Returns the general settings from the given initialization options + * + * @param initializationOptionsSettings the initialization options + * @return the general settings from the given initialization options + */ + public static JakartaGeneralClientSettings getGeneralJakartaSettings(Object initializationOptionsSettings) { + return JSONUtility.toModel(initializationOptionsSettings, JakartaGeneralClientSettings.class); + } +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaHoverSettings.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaHoverSettings.java new file mode 100644 index 00000000..af3886ab --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaHoverSettings.java @@ -0,0 +1,45 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings; + +import org.eclipse.lsp4j.HoverCapabilities; + +/** + * A wrapper around LSP {@link HoverCapabilities}. + * + */ +public class JakartaHoverSettings { + + private HoverCapabilities capabilities; + + public void setCapabilities(HoverCapabilities capabilities) { + this.capabilities = capabilities; + } + + public HoverCapabilities getCapabilities() { + return capabilities; + } + + /** + * Returns true if the client support the given documentation + * format and false otherwise. + * + * @return true if the client support the given documentation + * format and false otherwise. + */ + public boolean isContentFormatSupported(String documentationFormat) { + return capabilities.getContentFormat() != null && capabilities.getContentFormat().contains(documentationFormat); + } + +} diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaTraceSettings.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaTraceSettings.java new file mode 100644 index 00000000..540eea99 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/JakartaTraceSettings.java @@ -0,0 +1,65 @@ +/******************************************************************************* +* Copyright (c) 2023 IBM Corporation and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* IBM Corporation - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings; + +/** + * Jakarta trace settings. + */ +public class JakartaTraceSettings { + + /** trace setting options. */ + private static enum Setting { + info, verbose; + } + + /** Holds the server trace setting. */ + private String server; + + /** + * Constructor. + */ + public JakartaTraceSettings() { + setServer(Setting.info.name()); + } + + /** + * Returns the trace setting for the server. + * + * @return The trace setting for the server. + */ + public String getServer() { + return server; + } + + /** + * Sets the trace setting for the server. + * + * @param setting The trace setting for the server. + */ + public void setServer(String setting) { + if (Setting.info.name().equals(setting) || + Setting.verbose.name().equals(setting)) { + this.server = setting; + } + } + + /** + * Update the trace settings with the given new trace settings. + * + * @param newTrace the new trace settings. + */ + public void update(JakartaTraceSettings newTrace) { + this.setServer(newTrace.getServer()); + } +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/SharedSettings.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/SharedSettings.java new file mode 100644 index 00000000..f705919a --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/SharedSettings.java @@ -0,0 +1,61 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings; + +/** + * Shared settings. + * + * Based on: https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/SharedSettings.java + * + * @author Angelo ZERR + */ +public class SharedSettings { + + private final JakartaCompletionCapabilities completionCapabilities; + private final JakartaHoverSettings hoverSettings; + private final JakartaTraceSettings traceSettings; + + public SharedSettings() { + this.completionCapabilities = new JakartaCompletionCapabilities(); + this.hoverSettings = new JakartaHoverSettings(); + this.traceSettings = new JakartaTraceSettings(); + } + + /** + * Returns the completion capabilities. + * + * @return the completion capabilities. + */ + public JakartaCompletionCapabilities getCompletionCapabilities() { + return completionCapabilities; + } + + /** + * Returns the hover settings. + * + * @return the hover settings. + */ + public JakartaHoverSettings getHoverSettings() { + return hoverSettings; + } + + /** + * Returns the trace settings. + * + * @return the trace settings. + */ + public JakartaTraceSettings getTraceSettings() { + return traceSettings; + } +} diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ClientCapabilitiesWrapper.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ClientCapabilitiesWrapper.java new file mode 100644 index 00000000..25e167f7 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ClientCapabilitiesWrapper.java @@ -0,0 +1,119 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings.capabilities; + +import org.eclipse.lsp4j.ClientCapabilities; +import org.eclipse.lsp4j.DynamicRegistrationCapabilities; +import org.eclipse.lsp4j.ResourceOperationKind; +import org.eclipse.lsp4j.TextDocumentClientCapabilities; +import org.eclipse.lsp4j.WorkspaceClientCapabilities; +import org.eclipse.lsp4jakarta.ls.commons.client.ExtendedClientCapabilities; + +/** + * Determines if a client supports a specific capability dynamically. + * + * Based on: + * https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ClientCapabilitiesWrapper.java + */ +public class ClientCapabilitiesWrapper { + + private boolean v3Supported; + + private ClientCapabilities capabilities; + + private final ExtendedClientCapabilities extendedCapabilities; + + public ClientCapabilitiesWrapper() { + this(new ClientCapabilities(), null); + } + + public ClientCapabilitiesWrapper(ClientCapabilities capabilities, ExtendedClientCapabilities extendedCapabilities) { + this.capabilities = capabilities; + this.v3Supported = capabilities != null ? capabilities.getTextDocument() != null : false; + this.extendedCapabilities = extendedCapabilities; + } + + /** + * IMPORTANT + * + * This should be up to date with all Server supported capabilities + * + */ + + public boolean isCodeActionDynamicRegistered() { + return v3Supported && isDynamicRegistrationSupported(getTextDocument().getCodeAction()); + } + + public boolean isCompletionDynamicRegistrationSupported() { + return v3Supported && isDynamicRegistrationSupported(getTextDocument().getCompletion()); + } + + private boolean isDynamicRegistrationSupported(DynamicRegistrationCapabilities capability) { + return capability != null && capability.getDynamicRegistration() != null + && capability.getDynamicRegistration().booleanValue(); + } + + public TextDocumentClientCapabilities getTextDocument() { + return this.capabilities.getTextDocument(); + } + + public WorkspaceClientCapabilities getWorkspace() { + return this.capabilities.getWorkspace(); + } + + /** + * Returns true if the client should exit on shutdown() request and avoid + * waiting for an exit() request + * + * @return true if the language server should exit on shutdown() request + */ + public boolean shouldLanguageServerExitOnShutdown() { + if (extendedCapabilities == null) { + return false; + } + return extendedCapabilities.shouldLanguageServerExitOnShutdown(); + } + + public boolean isResourceOperationSupported() { + return capabilities.getWorkspace() != null && capabilities.getWorkspace().getWorkspaceEdit() != null + && capabilities.getWorkspace().getWorkspaceEdit().getResourceOperations() != null + && capabilities.getWorkspace().getWorkspaceEdit().getResourceOperations().contains(ResourceOperationKind.Create) + && capabilities.getWorkspace().getWorkspaceEdit().getResourceOperations().contains(ResourceOperationKind.Rename) + && capabilities.getWorkspace().getWorkspaceEdit().getResourceOperations().contains(ResourceOperationKind.Delete); + } + + public boolean isInlayHintDynamicRegistered() { + return v3Supported && isDynamicRegistrationSupported(getTextDocument().getInlayHint()); + } + + /** + * Returns true if the client supports both code action data and resolving + * workspace edits for code actions, and false otherwise. + * + * Both of these feature must be present in order to implement code action + * resolve effectively. + * + * @return true if the client supports both code action data and resolving + * workspace edits for code actions, and false otherwise + */ + public boolean isCodeActionResolveSupported() { + return capabilities.getTextDocument() != null && capabilities.getTextDocument().getCodeAction() != null + && capabilities.getTextDocument().getCodeAction().getDataSupport() != null + && capabilities.getTextDocument().getCodeAction().getDataSupport().booleanValue() + && capabilities.getTextDocument().getCodeAction().getResolveSupport() != null + && capabilities.getTextDocument().getCodeAction().getResolveSupport().getProperties() != null + && capabilities.getTextDocument().getCodeAction().getResolveSupport().getProperties().contains("edit"); + } + +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/JakartaCapabilityManager.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/JakartaCapabilityManager.java new file mode 100644 index 00000000..d89bfb56 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/JakartaCapabilityManager.java @@ -0,0 +1,85 @@ +/******************************************************************************* +* Copyright (c) 2019-2020 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings.capabilities; + +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.CODE_ACTION_ID; +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.COMPLETION_ID; +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_CODEACTION_OPTIONS; +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_COMPLETION_OPTIONS; +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_CODE_ACTION; +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.TEXT_DOCUMENT_COMPLETION; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.lsp4j.ClientCapabilities; +import org.eclipse.lsp4j.Registration; +import org.eclipse.lsp4j.RegistrationParams; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4jakarta.ls.commons.client.ExtendedClientCapabilities; + +/** + * Manages dynamic capabilities + * + * Based on: + * https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/MicroProfileCapabilityManager.java + */ +public class JakartaCapabilityManager { + + private final Set registeredCapabilities = new HashSet<>(3); + private final LanguageClient languageClient; + + private ClientCapabilitiesWrapper clientWrapper; + + public JakartaCapabilityManager(LanguageClient languageClient) { + this.languageClient = languageClient; + } + + /** + * Registers all dynamic capabilities. + */ + public void initializeCapabilities() { + if (this.getClientCapabilities().isCodeActionDynamicRegistered()) { + registerCapability(CODE_ACTION_ID, TEXT_DOCUMENT_CODE_ACTION, DEFAULT_CODEACTION_OPTIONS); + } + if (this.getClientCapabilities().isCompletionDynamicRegistrationSupported()) { + registerCapability(COMPLETION_ID, TEXT_DOCUMENT_COMPLETION, DEFAULT_COMPLETION_OPTIONS); + } + } + + public void setClientCapabilities(ClientCapabilities clientCapabilities, + ExtendedClientCapabilities extendedClientCapabilities) { + this.clientWrapper = new ClientCapabilitiesWrapper(clientCapabilities, extendedClientCapabilities); + } + + public ClientCapabilitiesWrapper getClientCapabilities() { + if (this.clientWrapper == null) { + this.clientWrapper = new ClientCapabilitiesWrapper(); + } + return this.clientWrapper; + } + + public Set getRegisteredCapabilities() { + return registeredCapabilities; + } + + private void registerCapability(String id, String method, Object options) { + if (registeredCapabilities.add(id)) { + Registration registration = new Registration(id, method, options); + RegistrationParams registrationParams = new RegistrationParams(Collections.singletonList(registration)); + languageClient.registerCapability(registrationParams); + } + } +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ServerCapabilitiesConstants.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ServerCapabilitiesConstants.java new file mode 100644 index 00000000..0428be02 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ServerCapabilitiesConstants.java @@ -0,0 +1,51 @@ +/******************************************************************************* +* Copyright (c) 2018 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings.capabilities; + +import java.util.Arrays; +import java.util.UUID; + +import org.eclipse.lsp4j.CodeActionOptions; +import org.eclipse.lsp4j.CompletionOptions; + +/** + * Server Capabilities Constants + * + * Based on: + * https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesConstants.java + */ +public class ServerCapabilitiesConstants { + + private ServerCapabilitiesConstants() {} + + public static final String TEXT_DOCUMENT_COMPLETION = "textDocument/completion"; + public static final String TEXT_DOCUMENT_CODE_ACTION = "textDocument/codeAction"; + + public static final String COMPLETION_ID = UUID.randomUUID().toString(); + public static final String CODE_ACTION_ID = UUID.randomUUID().toString(); + + public static final CompletionOptions DEFAULT_COMPLETION_OPTIONS = new CompletionOptions(true, Arrays.asList("@" /* triggered characters for java snippet annotations */, + "\"" /* + * trigger characters for annotation property value completion + */)); + + public static final CodeActionOptions DEFAULT_CODEACTION_OPTIONS = createDefaultCodeActionOptions(); + + private static CodeActionOptions createDefaultCodeActionOptions() { + CodeActionOptions options = new CodeActionOptions(); + options.setResolveProvider(Boolean.TRUE); + return options; + } + +} \ No newline at end of file diff --git a/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ServerCapabilitiesInitializer.java b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ServerCapabilitiesInitializer.java new file mode 100644 index 00000000..fe4eebf2 --- /dev/null +++ b/jakarta.ls/src/main/java/org/eclipse/lsp4jakarta/settings/capabilities/ServerCapabilitiesInitializer.java @@ -0,0 +1,52 @@ +/******************************************************************************* +* Copyright (c) 2018 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4jakarta.settings.capabilities; + +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_CODEACTION_OPTIONS; +import static org.eclipse.lsp4jakarta.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_COMPLETION_OPTIONS; + +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.TextDocumentSyncKind; + +/** + * All default capabilities of this server + * + * Based on: + * https://github.com/eclipse/lsp4mp/blob/0.9.0/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/settings/capabilities/ServerCapabilitiesInitializer.java + */ +public class ServerCapabilitiesInitializer { + + private ServerCapabilitiesInitializer() {} + + /** + * Returns all server capabilities (with default values) that aren't dynamic. + * + * A service's dynamic capability is indicated by the client. + * + * @param clientCapabilities + * @return ServerCapabilities object + */ + public static ServerCapabilities getNonDynamicServerCapabilities(ClientCapabilitiesWrapper clientCapabilities) { + ServerCapabilities serverCapabilities = new ServerCapabilities(); + serverCapabilities.setTextDocumentSync(TextDocumentSyncKind.Incremental); + if (!clientCapabilities.isCompletionDynamicRegistrationSupported()) { + serverCapabilities.setCompletionProvider(DEFAULT_COMPLETION_OPTIONS); + } + if (!clientCapabilities.isCodeActionDynamicRegistered()) { + serverCapabilities.setCodeActionProvider(DEFAULT_CODEACTION_OPTIONS); + } + + return serverCapabilities; + } +} \ No newline at end of file