diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaCompletionEngineConfigurer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaCompletionEngineConfigurer.java new file mode 100644 index 000000000..10e758d1e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaCompletionEngineConfigurer.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2020 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.app; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.lsp4j.CompletionItemKind; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ide.vscode.boot.java.Annotations; +import org.springframework.ide.vscode.boot.java.data.DataRepositoryCompletionProcessor; +import org.springframework.ide.vscode.boot.java.handlers.BootJavaCompletionEngine; +import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider; +import org.springframework.ide.vscode.boot.java.scope.ScopeCompletionProcessor; +import org.springframework.ide.vscode.boot.java.snippets.JavaSnippet; +import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetContext; +import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager; +import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; +import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor; +import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; +import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.languageserver.util.LspClient; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; + +import com.google.common.collect.ImmutableList; + +@Configuration +public class BootJavaCompletionEngineConfigurer { + + + @Bean JavaSnippetManager javaSnippetManager(SimpleLanguageServer server) { + JavaSnippetManager snippetManager = new JavaSnippetManager(server::createSnippetBuilder); + + // PT 160529904: Eclipse templates are duplicated, due to templates in Eclipse also being contributed by + // STS3 bundle. Therefore do not include templates if client is Eclipse + // TODO: REMOVE this check once STS3 is no longer supported + if (LspClient.currentClient() != LspClient.Client.ECLIPSE) { + snippetManager.add( + new JavaSnippet("RequestMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method, + ImmutableList.of("org.springframework.web.bind.annotation.RequestMapping", + "org.springframework.web.bind.annotation.RequestMethod", + "org.springframework.web.bind.annotation.RequestParam"), + "@RequestMapping(value=\"${path}\", method=RequestMethod.${GET})\n" + + "public ${SomeData} ${requestMethodName}(@RequestParam ${String} ${param}) {\n" + + " return new ${SomeData}(${cursor});\n" + "}\n")); + snippetManager + .add(new JavaSnippet("GetMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method, + ImmutableList.of("org.springframework.web.bind.annotation.GetMapping", + "org.springframework.web.bind.annotation.RequestParam"), + "@GetMapping(value=\"${path}\")\n" + + "public ${SomeData} ${getMethodName}(@RequestParam ${String} ${param}) {\n" + + " return new ${SomeData}(${cursor});\n" + "}\n")); + snippetManager.add(new JavaSnippet("PostMapping method", JavaSnippetContext.BOOT_MEMBERS, + CompletionItemKind.Method, + ImmutableList.of("org.springframework.web.bind.annotation.PostMapping", + "org.springframework.web.bind.annotation.RequestBody"), + "@PostMapping(value=\"${path}\")\n" + + "public ${SomeEnityData} ${postMethodName}(@RequestBody ${SomeEnityData} ${entity}) {\n" + + " //TODO: process POST request\n" + " ${cursor}\n" + " return ${entity};\n" + "}\n")); + snippetManager.add(new JavaSnippet("PutMapping method", JavaSnippetContext.BOOT_MEMBERS, + CompletionItemKind.Method, + ImmutableList.of("org.springframework.web.bind.annotation.PutMapping", + "org.springframework.web.bind.annotation.RequestBody", + "org.springframework.web.bind.annotation.PathVariable"), + "@PutMapping(value=\"${path}/{${id}}\")\n" + + "public ${SomeEnityData} ${putMethodName}(@PathVariable ${pvt:String} ${id}, @RequestBody ${SomeEnityData} ${entity}) {\n" + + " //TODO: process PUT request\n" + " ${cursor}\n" + " return ${entity};\n" + "}")); + } + + return snippetManager; + } + + @Bean + BootJavaCompletionEngine javaCompletionEngine( + BootLanguageServerParams params, + @Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties, + JavaSnippetManager snippetManager, + CompilationUnitCache cuCache + ) { + SpringPropertyIndexProvider indexProvider = params.indexProvider; + JavaProjectFinder javaProjectFinder = params.projectFinder; + Map providers = new HashMap<>(); + providers.put(org.springframework.ide.vscode.boot.java.scope.Constants.SPRING_SCOPE, + new ScopeCompletionProcessor()); + providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, + new ValueCompletionProcessor(javaProjectFinder, indexProvider, adHocProperties)); + providers.put(Annotations.REPOSITORY, new DataRepositoryCompletionProcessor()); + return new BootJavaCompletionEngine(cuCache, providers, snippetManager); + } +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java index 33220840f..d55a05f1f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java @@ -108,7 +108,6 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent private final BootLanguageServerParams serverParams; private final SpringPropertyIndexProvider propertyIndexProvider; - private final ProjectBasedPropertyIndexProvider adHocPropertyIndexProvider; private final SpringProcessConnectorService liveDataService; @@ -143,7 +142,6 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent this.cuCache = cuCache; propertyIndexProvider = serverParams.indexProvider; - this.adHocPropertyIndexProvider = adHocIndexProvider; SimpleWorkspaceService workspaceService = server.getWorkspaceService(); SimpleTextDocumentService documents = server.getTextDocumentService(); @@ -232,11 +230,6 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent return server; } - @Override - public Optional getCompletionEngine() { - return Optional.of(createCompletionEngine(projectFinder, propertyIndexProvider, adHocPropertyIndexProvider)); - } - @Override public HoverHandler getHoverProvider() { return hoverProvider; @@ -266,63 +259,6 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent this.cuCache.dispose(); } - protected ICompletionEngine createCompletionEngine( - JavaProjectFinder javaProjectFinder, - SpringPropertyIndexProvider indexProvider, - ProjectBasedPropertyIndexProvider adHocIndexProvider) { - - Map providers = new HashMap<>(); - providers.put(org.springframework.ide.vscode.boot.java.scope.Constants.SPRING_SCOPE, - new ScopeCompletionProcessor()); - providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, - new ValueCompletionProcessor(javaProjectFinder, indexProvider, adHocIndexProvider)); - providers.put(Annotations.REPOSITORY, new DataRepositoryCompletionProcessor()); - - JavaSnippetManager snippetManager = getSnippets(); - return new BootJavaCompletionEngine(this, providers, snippetManager); - } - - protected JavaSnippetManager getSnippets() { - JavaSnippetManager snippetManager = new JavaSnippetManager(server::createSnippetBuilder); - - // PT 160529904: Eclipse templates are duplicated, due to templates in Eclipse also being contributed by - // STS3 bundle. Therefore do not include templates if client is Eclipse - // TODO: REMOVE this check once STS3 is no longer supported - if (LspClient.currentClient() != LspClient.Client.ECLIPSE) { - snippetManager.add( - new JavaSnippet("RequestMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method, - ImmutableList.of("org.springframework.web.bind.annotation.RequestMapping", - "org.springframework.web.bind.annotation.RequestMethod", - "org.springframework.web.bind.annotation.RequestParam"), - "@RequestMapping(value=\"${path}\", method=RequestMethod.${GET})\n" - + "public ${SomeData} ${requestMethodName}(@RequestParam ${String} ${param}) {\n" - + " return new ${SomeData}(${cursor});\n" + "}\n")); - snippetManager - .add(new JavaSnippet("GetMapping method", JavaSnippetContext.BOOT_MEMBERS, CompletionItemKind.Method, - ImmutableList.of("org.springframework.web.bind.annotation.GetMapping", - "org.springframework.web.bind.annotation.RequestParam"), - "@GetMapping(value=\"${path}\")\n" - + "public ${SomeData} ${getMethodName}(@RequestParam ${String} ${param}) {\n" - + " return new ${SomeData}(${cursor});\n" + "}\n")); - snippetManager.add(new JavaSnippet("PostMapping method", JavaSnippetContext.BOOT_MEMBERS, - CompletionItemKind.Method, - ImmutableList.of("org.springframework.web.bind.annotation.PostMapping", - "org.springframework.web.bind.annotation.RequestBody"), - "@PostMapping(value=\"${path}\")\n" - + "public ${SomeEnityData} ${postMethodName}(@RequestBody ${SomeEnityData} ${entity}) {\n" - + " //TODO: process POST request\n" + " ${cursor}\n" + " return ${entity};\n" + "}\n")); - snippetManager.add(new JavaSnippet("PutMapping method", JavaSnippetContext.BOOT_MEMBERS, - CompletionItemKind.Method, - ImmutableList.of("org.springframework.web.bind.annotation.PutMapping", - "org.springframework.web.bind.annotation.RequestBody", - "org.springframework.web.bind.annotation.PathVariable"), - "@PutMapping(value=\"${path}/{${id}}\")\n" - + "public ${SomeEnityData} ${putMethodName}(@PathVariable ${pvt:String} ${id}, @RequestBody ${SomeEnityData} ${entity}) {\n" - + " //TODO: process PUT request\n" + " ${cursor}\n" + " return ${entity};\n" + "}")); - } - - return snippetManager; - } protected BootJavaHoverProvider createHoverHandler(JavaProjectFinder javaProjectFinder, SourceLinks sourceLinks, SpringProcessLiveDataProvider liveDataProvider) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaCompletionEngine.java index fe4557235..4d66d003a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaCompletionEngine.java @@ -21,29 +21,34 @@ import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.NodeFinder; import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents; import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager; +import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.util.text.IDocument; +import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.commons.util.text.TextDocument; +import com.google.common.collect.ImmutableList; + /** * @author Martin Lippert */ -public class BootJavaCompletionEngine implements ICompletionEngine { +public class BootJavaCompletionEngine implements ICompletionEngine, LanguageSpecific { private Map completionProviders; private JavaSnippetManager snippets; - private BootJavaLanguageServerComponents server; + private CompilationUnitCache cuCache; - public BootJavaCompletionEngine(BootJavaLanguageServerComponents server, Map specificProviders, JavaSnippetManager snippets) { - this.server = server; + public BootJavaCompletionEngine(CompilationUnitCache cuCache, Map specificProviders, JavaSnippetManager snippets) { + this.cuCache = cuCache; this.completionProviders = specificProviders; this.snippets = snippets; } @Override public Collection getCompletions(TextDocument document, int offset) throws Exception { - return server.getCompilationUnitCache().withCompilationUnit(document, cu -> { + return cuCache.withCompilationUnit(document, cu -> { if (cu != null) { ASTNode node = NodeFinder.perform(cu, offset, 0); @@ -91,4 +96,9 @@ public class BootJavaCompletionEngine implements ICompletionEngine { } } + @Override + public Collection supportedLanguages() { + return ImmutableList.of(LanguageId.JAVA); + } + }