diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/composable/CompositeLanguageServerComponents.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/composable/CompositeLanguageServerComponents.java index 862f0cd94..841c7ae73 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/composable/CompositeLanguageServerComponents.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/composable/CompositeLanguageServerComponents.java @@ -17,6 +17,7 @@ import java.util.Set; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.HoverParams; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; @@ -81,14 +82,14 @@ public class CompositeLanguageServerComponents implements LanguageServerComponen //Create composite hover handler this.hoverHandler = new HoverHandler() { @Override - public Hover handle(HoverParams params) { + public Hover handle(CancelChecker cancelToken, HoverParams params) { TextDocument doc = server.getTextDocumentService().getLatestSnapshot(params.getTextDocument().getUri()); LanguageId language = doc.getLanguageId(); LanguageServerComponents subComponents = componentsByLanguageId.get(language); - if (subComponents!=null) { + if (subComponents != null) { HoverHandler subEngine = subComponents.getHoverProvider(); if (subEngine != null) { - return subEngine.handle(params); + return subEngine.handle(cancelToken, params); } } //No applicable subEngine... diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/hover/VscodeHoverEngineAdapter.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/hover/VscodeHoverEngineAdapter.java index b9558460e..c992fd267 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/hover/VscodeHoverEngineAdapter.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/hover/VscodeHoverEngineAdapter.java @@ -10,9 +10,12 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.languageserver.hover; +import java.util.concurrent.CancellationException; + import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.HoverParams; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,13 +60,15 @@ public class VscodeHoverEngineAdapter implements HoverHandler { } @Override - public Hover handle(HoverParams params) { + public Hover handle(CancelChecker cancelToken, HoverParams params) { try { SimpleTextDocumentService documents = server.getTextDocumentService(); TextDocument doc = documents.getLatestSnapshot(params.getTextDocument().getUri()); if (doc != null) { int offset = doc.toOffset(params.getPosition()); + + cancelToken.checkCanceled(); Tuple2 hoverTuple = hoverInfoProvider.getHoverInfo(doc, offset); if (hoverTuple != null) { @@ -84,6 +89,8 @@ public class VscodeHoverEngineAdapter implements HoverHandler { } else { log.debug("No hover because doc is null"); } + } catch (CancellationException e) { + throw e; } catch (Exception e) { log.error("error computing hover", e); } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/HoverHandler.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/HoverHandler.java index a3d480971..915fc3a5d 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/HoverHandler.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/HoverHandler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2020 Pivotal, Inc. + * Copyright (c) 2016, 2021 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -12,8 +12,9 @@ package org.springframework.ide.vscode.commons.languageserver.util; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.HoverParams; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; @FunctionalInterface public interface HoverHandler { - Hover handle(HoverParams params); + Hover handle(CancelChecker cancelToken, HoverParams params); } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java index 3c95438b8..51f37a107 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/SimpleTextDocumentService.java @@ -57,6 +57,7 @@ import org.eclipse.lsp4j.TextDocumentPositionParams; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4j.jsonrpc.CompletableFutures; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageClient; @@ -284,7 +285,7 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE log.debug("hover requested for {}", hoverParams.getPosition()); return CompletableFutures.computeAsync(cancelToken -> { - return computeHover(hoverParams); + return computeHover(cancelToken, hoverParams); }); @@ -296,12 +297,13 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE // })); } - private Hover computeHover(HoverParams hoverParams) { + private Hover computeHover(CancelChecker cancelToken, HoverParams hoverParams) { try { log.debug("hover handler starting"); HoverHandler h = hoverHandler; if (h != null) { - return hoverHandler.handle(hoverParams); + cancelToken.checkCanceled(); + return hoverHandler.handle(cancelToken, hoverParams); } log.debug("no hover because there is no handler"); return null; diff --git a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerInitializer.java b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerInitializer.java index 0d8dc3cae..70cee70d1 100644 --- a/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerInitializer.java +++ b/headless-services/concourse-language-server/src/main/java/org/springframework/ide/vscode/concourse/ConcourseLanguageServerInitializer.java @@ -17,17 +17,14 @@ import javax.annotation.PostConstruct; import org.eclipse.lsp4j.CompletionList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter; import org.springframework.ide.vscode.commons.languageserver.hover.HoverInfoProvider; import org.springframework.ide.vscode.commons.languageserver.hover.VscodeHoverEngineAdapter; import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine; -import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; -import org.springframework.ide.vscode.commons.util.CollectionUtil; import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.ide.vscode.commons.yaml.ast.YamlASTProvider; @@ -37,9 +34,8 @@ import org.springframework.ide.vscode.commons.yaml.completion.YamlCompletionEngi import org.springframework.ide.vscode.commons.yaml.hover.YamlHoverInfoProvider; import org.springframework.ide.vscode.commons.yaml.quickfix.YamlQuickfixes; import org.springframework.ide.vscode.commons.yaml.reconcile.ASTTypeCache; -import org.springframework.ide.vscode.commons.yaml.reconcile.TypeBasedYamlSymbolHandler; -import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine; import org.springframework.ide.vscode.commons.yaml.reconcile.TypeBasedYamlHierarchicalSymbolHandler.HierarchicalDefType; +import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaBasedReconcileEngine; import org.springframework.ide.vscode.commons.yaml.schema.YType; import org.springframework.ide.vscode.commons.yaml.schema.YamlSchema; import org.springframework.ide.vscode.commons.yaml.snippet.SchemaBasedSnippetGenerator; @@ -156,16 +152,16 @@ public class ConcourseLanguageServerInitializer { server.completionResolver.resolveNow(item); return item; }); - documents.onHover(params -> { + documents.onHover((cancelToken, params) -> { log.debug("Concourse hover handler starting"); try { TextDocument doc = documents.getLatestSnapshot(params); if (doc != null) { LanguageId languageId = doc.getLanguageId(); if (LanguageId.CONCOURSE_PIPELINE.equals(doc.getLanguageId())) { - return forPipelines.hoverEngine.handle(params); + return forPipelines.hoverEngine.handle(cancelToken, params); } else if (LanguageId.CONCOURSE_TASK.equals(doc.getLanguageId())) { - return forTasks.hoverEngine.handle(params); + return forTasks.hoverEngine.handle(cancelToken, params); } else { log.debug("No hovers because language-id = {}", languageId); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java index 3da23626b..dc5a9c001 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java @@ -31,6 +31,7 @@ import org.eclipse.lsp4j.CodeLens; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.HoverParams; import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,7 +72,7 @@ public class BootJavaHoverProvider implements HoverHandler { } @Override - public Hover handle(HoverParams params) { + public Hover handle(CancelChecker cancelToken, HoverParams params) { SimpleTextDocumentService documents = server.getTextDocumentService(); TextDocument doc = documents.getLatestSnapshot(params); @@ -80,7 +81,7 @@ public class BootJavaHoverProvider implements HoverHandler { if (server.getInterestingLanguages().contains(doc.getLanguageId())) { try { int offset = doc.toOffset(params.getPosition()); - Hover hoverResult = provideHover(doc, offset); + Hover hoverResult = provideHover(cancelToken, doc, offset); if (hoverResult != null) { return hoverResult; } @@ -205,15 +206,20 @@ public class BootJavaHoverProvider implements HoverHandler { } } - private Hover provideHover(TextDocument document, int offset) throws Exception { + private Hover provideHover(CancelChecker cancelToken, TextDocument document, int offset) throws Exception { final SpringProcessLiveData[] processLiveData = this.liveDataProvider.getLatestLiveData(); + cancelToken.checkCanceled(); + IJavaProject project = getProject(document).orElse(null); if (project != null) { return server.getCompilationUnitCache().withCompilationUnit(project, URI.create(document.getUri()), cu -> { + + cancelToken.checkCanceled(); + ASTNode node = NodeFinder.perform(cu, offset, 0); if (node != null) { - return provideHover(node, offset, document, project, processLiveData); + return provideHover(cancelToken, node, offset, document, project, processLiveData); } return null; }); @@ -221,7 +227,7 @@ public class BootJavaHoverProvider implements HoverHandler { return null; } - private Hover provideHover(ASTNode node, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) { + private Hover provideHover(CancelChecker cancelToken, ASTNode node, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) { // look for spring annotations first ASTNode annotationNode = node; @@ -229,27 +235,30 @@ public class BootJavaHoverProvider implements HoverHandler { annotationNode = annotationNode.getParent(); } if (annotationNode != null) { - return provideHoverForAnnotation(node, (Annotation) annotationNode, offset, doc, project, processLiveData); + return provideHoverForAnnotation(cancelToken, node, (Annotation) annotationNode, offset, doc, project, processLiveData); } // then do additional AST node coverage if (node instanceof SimpleName) { ASTNode parent = node.getParent(); if (parent instanceof TypeDeclaration) { - return provideHoverForTypeDeclaration(node, (TypeDeclaration) parent, offset, doc, project, processLiveData); + return provideHoverForTypeDeclaration(cancelToken, node, (TypeDeclaration) parent, offset, doc, project, processLiveData); } else if (parent instanceof MethodDeclaration) { - return provideHoverForMethodDeclaration((MethodDeclaration) parent, offset, doc, project, processLiveData); + return provideHoverForMethodDeclaration(cancelToken, (MethodDeclaration) parent, offset, doc, project, processLiveData); } else if (parent instanceof SingleVariableDeclaration && parent.getParent() instanceof MethodDeclaration) { - return provideHoverForMethodParameter((SingleVariableDeclaration) parent, offset, doc, project, processLiveData); + return provideHoverForMethodParameter(cancelToken, (SingleVariableDeclaration) parent, offset, doc, project, processLiveData); } } return null; } - private Hover provideHoverForMethodParameter(SingleVariableDeclaration parameter, int offset, TextDocument doc, + private Hover provideHoverForMethodParameter(CancelChecker cancelToken, SingleVariableDeclaration parameter, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) { if (processLiveData.length > 0) { for (HoverProvider provider : this.hoverProviders.getAll()) { + + cancelToken.checkCanceled(); + Hover hover = provider.provideMethodParameterHover(parameter, offset, doc, project, processLiveData); if (hover != null) { return hover; @@ -259,10 +268,13 @@ public class BootJavaHoverProvider implements HoverHandler { return null; } - private Hover provideHoverForMethodDeclaration(MethodDeclaration methodDeclaration, int offset, TextDocument doc, + private Hover provideHoverForMethodDeclaration(CancelChecker cancelToken, MethodDeclaration methodDeclaration, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) { if (processLiveData.length > 0) { for (HoverProvider provider : this.hoverProviders.getAll()) { + + cancelToken.checkCanceled(); + Hover hover = provider.provideHover(methodDeclaration, offset, doc, project, processLiveData); if (hover != null) { //TODO: compose multiple hovers somehow instead of just returning the first one? @@ -273,7 +285,7 @@ public class BootJavaHoverProvider implements HoverHandler { return null; } - private Hover provideHoverForAnnotation(ASTNode exactNode, Annotation annotation, int offset, TextDocument doc, IJavaProject project, + private Hover provideHoverForAnnotation(CancelChecker cancelToken, ASTNode exactNode, Annotation annotation, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) { ITypeBinding type = annotation.resolveTypeBinding(); if (type != null) { @@ -282,6 +294,9 @@ public class BootJavaHoverProvider implements HoverHandler { if (processLiveData.length > 0) { for (HoverProvider provider : this.hoverProviders.get(type)) { + + cancelToken.checkCanceled(); + Hover hover = provider.provideHover(exactNode, annotation, type, offset, doc, project, processLiveData); if (hover != null) { logger.debug("Hover found: "+hover); @@ -303,12 +318,15 @@ public class BootJavaHoverProvider implements HoverHandler { return null; } - private Hover provideHoverForTypeDeclaration(ASTNode exactNode, TypeDeclaration typeDeclaration, int offset, TextDocument doc, + private Hover provideHoverForTypeDeclaration(CancelChecker cancelToken, ASTNode exactNode, TypeDeclaration typeDeclaration, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) { if (processLiveData.length > 0) { ITypeBinding type = typeDeclaration.resolveBinding(); for (HoverProvider provider : this.hoverProviders.getAll()) { + + cancelToken.checkCanceled(); + Hover hover = provider.provideHover(exactNode, typeDeclaration, type, offset, doc, project, processLiveData); if (hover!=null) { //TODO: compose multiple hovers somehow instead of just returning the first one? diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java index 0cdcda2c0..b6b484889 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java @@ -16,6 +16,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -193,6 +194,9 @@ public final class CompilationUnitCache implements DocumentContentProvider { logger.info("CU Cache: start work on AST for {}", uri.toString()); return requestor.apply(cu); } + catch (CancellationException e) { + throw e; + } catch (Exception e) { logger.error("", e); }