From 604da237192f53d3b14b3e2c51d287083ee9cbdd Mon Sep 17 00:00:00 2001 From: Ahmed Neil Hussain Date: Thu, 2 Feb 2023 10:00:21 +0000 Subject: [PATCH] New API: Port code lenses --- .../codelens/LSPCodeMiningTest.java | 21 +++++------ .../operations/codelens/CodeLensProvider.java | 37 ++++++++----------- .../operations/codelens/LSPCodeMining.java | 22 +++++------ 3 files changed, 36 insertions(+), 44 deletions(-) diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java index d96e10596..e3bf0c3e8 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/operations/codelens/LSPCodeMiningTest.java @@ -11,11 +11,10 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.operations.codelens; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.core.commands.ExecutionEvent; @@ -25,9 +24,10 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; -import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; +import org.eclipse.lsp4e.LanguageServerWrapper; import org.eclipse.lsp4e.LanguageServersRegistry; +import org.eclipse.lsp4e.LanguageServiceAccessor; import org.eclipse.lsp4e.command.LSPCommandHandler; import org.eclipse.lsp4e.operations.codelens.CodeLensProvider; import org.eclipse.lsp4e.operations.codelens.LSPCodeMining; @@ -39,7 +39,6 @@ import org.eclipse.lsp4j.ExecuteCommandParams; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; -import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.widgets.Display; @@ -71,7 +70,7 @@ public void setUp() throws CoreException { } @Test - public void testLSPCodeMiningActionClientSideHandling() throws BadLocationException, CoreException { + public void testLSPCodeMiningActionClientSideHandling() throws Exception { String commandID = "test.command"; final CodeLens lens = createCodeLens(commandID); @@ -94,10 +93,10 @@ public Object execute(ExecutionEvent event, Command command, IPath context) thro IFile file = TestUtils.createUniqueTestFile(project, "lspt", "test content"); IDocument document = TestUtils.openTextViewer(file).getDocument(); - LanguageServer languageServer = MockLanguageServer.INSTANCE; CodeLensProvider provider = new CodeLensProvider(); + LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrapperForConnection(project, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID)); - LSPCodeMining sut = new LSPCodeMining(lens, document, languageServer, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID), provider); + LSPCodeMining sut = new LSPCodeMining(lens, document, wrapper, provider); MouseEvent mouseEvent = createMouseEvent(); sut.getAction().accept(mouseEvent); @@ -107,8 +106,7 @@ public Object execute(ExecutionEvent event, Command command, IPath context) thro @Test public void testLSPCodeMiningActionServerSideHandling() - throws InterruptedException, java.util.concurrent.ExecutionException, TimeoutException, - BadLocationException, CoreException { + throws Exception { final CodeLens lens = createCodeLens(MockLanguageServer.SUPPORTED_COMMAND_ID); Command command = lens.getCommand(); JsonObject jsonObject = new JsonObject(); @@ -122,8 +120,9 @@ public void testLSPCodeMiningActionServerSideHandling() MockLanguageServer languageServer = MockLanguageServer.INSTANCE; CodeLensProvider provider = new CodeLensProvider(); - LSPCodeMining sut = new LSPCodeMining(lens, document, languageServer, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID), provider); - MouseEvent mouseEvent = createMouseEvent(); + LanguageServerWrapper wrapper = LanguageServiceAccessor.getLSWrapperForConnection(project, LanguageServersRegistry.getInstance().getDefinition(MOCK_SERVER_ID)); + + LSPCodeMining sut = new LSPCodeMining(lens, document, wrapper, provider); MouseEvent mouseEvent = createMouseEvent(); sut.getAction().accept(mouseEvent); // We expect that the language server will be called to execute the command diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java index f1f045b49..a966742bd 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/CodeLensProvider.java @@ -9,11 +9,10 @@ package org.eclipse.lsp4e.operations.codelens; import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.annotation.NonNull; @@ -24,10 +23,11 @@ import org.eclipse.jface.text.codemining.ICodeMining; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServerPlugin; -import org.eclipse.lsp4e.LanguageServiceAccessor; +import org.eclipse.lsp4e.LanguageServerWrapper; +import org.eclipse.lsp4e.LanguageServers; +import org.eclipse.lsp4e.LanguageServers.LanguageServerDocumentExecutor; import org.eclipse.lsp4j.CodeLens; import org.eclipse.lsp4j.CodeLensParams; -import org.eclipse.lsp4j.services.LanguageServer; public class CodeLensProvider extends AbstractCodeMiningProvider { @@ -35,30 +35,25 @@ private CompletableFuture> provideCodeMinings(@NonNu URI docURI = LSPEclipseUtils.toUri(document); if (docURI != null) { final var param = new CodeLensParams(LSPEclipseUtils.toTextDocumentIdentifier(docURI)); - final var codeLensResults = Collections.synchronizedList(new ArrayList()); - return LanguageServiceAccessor - .getLanguageServers(document, capabilities -> capabilities.getCodeLensProvider() != null) - .thenComposeAsync(languageServers -> CompletableFuture.allOf(languageServers.stream() - .map(languageServer -> languageServer.getTextDocumentService().codeLens(param) - .thenAcceptAsync(codeLenses -> { - // textDocument/codeLens may return null - if (codeLenses != null) { - codeLenses.stream().filter(Objects::nonNull) - .map(codeLens -> toCodeMining(document, languageServer, codeLens)) - .filter(Objects::nonNull).forEach(codeLensResults::add); - } - })) - .toArray(CompletableFuture[]::new))) - .thenApplyAsync(theVoid -> codeLensResults); + LanguageServerDocumentExecutor executor = LanguageServers.forDocument(document) + .withFilter(sc -> sc.getCodeLensProvider() != null); + return executor.collectAll((w, ls) -> ls.getTextDocumentService().codeLens(param) + .thenApply(codeLenses -> LanguageServers.streamSafely(codeLenses) + .map(codeLens -> toCodeMining(document, w, codeLens)) + .filter(Objects::nonNull))) + .thenApply(result -> result.stream().flatMap(s -> s).collect(Collectors.toList())); } else { return null; } } - private LSPCodeMining toCodeMining(IDocument document, LanguageServer languageServer, CodeLens codeLens) { + private LSPCodeMining toCodeMining(IDocument document, LanguageServerWrapper languageServerWrapper, CodeLens codeLens) { + if (codeLens == null) { + return null; + } try { - return new LSPCodeMining(codeLens, document, languageServer, LanguageServiceAccessor.resolveServerDefinition(languageServer).orElse(null), CodeLensProvider.this); + return new LSPCodeMining(codeLens, document, languageServerWrapper, CodeLensProvider.this); } catch (BadLocationException e) { LanguageServerPlugin.logError(e); return null; diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java index 5bb7f34d6..067c72af9 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/codelens/LSPCodeMining.java @@ -18,26 +18,27 @@ import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.codemining.LineHeaderCodeMining; +import org.eclipse.lsp4e.LanguageServerWrapper; import org.eclipse.lsp4e.LanguageServersRegistry.LanguageServerDefinition; -import org.eclipse.lsp4e.LanguageServiceAccessor; import org.eclipse.lsp4e.command.CommandExecutor; import org.eclipse.lsp4j.CodeLens; import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.swt.events.MouseEvent; public class LSPCodeMining extends LineHeaderCodeMining { private CodeLens codeLens; - private final LanguageServer languageServer; + + // TODO: Store a SingleServerDocumentExecutor instead when that codestream is merged + private final LanguageServerWrapper languageServerWrapper; private final LanguageServerDefinition languageServerDefinition; private final @Nullable IDocument document; - public LSPCodeMining(CodeLens codeLens, IDocument document, LanguageServer languageServer, LanguageServerDefinition languageServerDefinition, + public LSPCodeMining(CodeLens codeLens, IDocument document, LanguageServerWrapper languageServerWrapper, CodeLensProvider provider) throws BadLocationException { super(codeLens.getRange().getStart().getLine(), document, provider, null); this.codeLens = codeLens; - this.languageServer = languageServer; - this.languageServerDefinition = languageServerDefinition; + this.languageServerWrapper = languageServerWrapper; + this.languageServerDefinition = languageServerWrapper.serverDefinition; this.document = document; setLabel(getCodeLensString(codeLens)); } @@ -52,14 +53,11 @@ public LSPCodeMining(CodeLens codeLens, IDocument document, LanguageServer langu @Override protected CompletableFuture doResolve(ITextViewer viewer, IProgressMonitor monitor) { - if (!LanguageServiceAccessor.checkCapability(languageServer, - capabilities -> { - Boolean resolveProvider = capabilities.getCodeLensProvider().getResolveProvider(); - return resolveProvider != null && resolveProvider; - })) { + if (Boolean.TRUE != this.languageServerWrapper.getServerCapabilities().getCodeLensProvider().getResolveProvider()) { return CompletableFuture.completedFuture(null); } - return languageServer.getTextDocumentService().resolveCodeLens(this.codeLens) + + return this.languageServerWrapper.execute(languageServer -> languageServer.getTextDocumentService().resolveCodeLens(this.codeLens)) .thenAcceptAsync(resolvedCodeLens -> { codeLens = resolvedCodeLens; if (resolvedCodeLens != null) {