diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java index bc4a238e4..1044f41c1 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019 Pivotal, Inc. + * Copyright (c) 2019, 2024 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 @@ -50,23 +50,32 @@ public class CompositeCompletionEngine implements ICompletionEngine { } @Override - public Collection getCompletions(TextDocument document, int offset) throws Exception { + public InternalCompletionList getCompletions(TextDocument document, int offset) throws Exception { LanguageId language = document.getLanguageId(); log.info("languageId = {}", language); Collection engines = subEngines.get(language); + if (engines.size()==1) { + //Special case to avoid some collection copying ICompletionEngine engine = engines.iterator().next(); return engine.getCompletions(document, offset); + } else { + + boolean isIncomplete = false; ImmutableList.Builder completions = ImmutableList.builder(); + for (ICompletionEngine engine : engines) { - Collection c = engine.getCompletions(document, offset); - if (c!=null) { - completions.addAll(c); + InternalCompletionList c = engine.getCompletions(document, offset); + if (c != null && c.completionItems() != null) { + completions.addAll(c.completionItems()); + if (c.isIncomplete()) { + isIncomplete = true; + } } } - return completions.build(); + return new InternalCompletionList(completions.build(), isIncomplete); } }; diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java index 72d14c2c6..284395602 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2018 Pivotal, Inc. + * Copyright (c) 2015, 2024 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 @@ -10,8 +10,6 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.languageserver.completion; -import java.util.Collection; - import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -19,6 +17,6 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ public interface ICompletionEngine { - Collection getCompletions(TextDocument document, int offset) throws Exception; + InternalCompletionList getCompletions(TextDocument document, int offset) throws Exception; } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java index 3fd9ec129..5de922a57 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionProposal.java @@ -22,7 +22,6 @@ import org.springframework.ide.vscode.commons.util.Renderable; */ public interface ICompletionProposal { - String getLabel(); CompletionItemKind getKind(); DocumentEdits getTextEdit(); diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/InternalCompletionList.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/InternalCompletionList.java new file mode 100644 index 000000000..5845d0f2e --- /dev/null +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/InternalCompletionList.java @@ -0,0 +1,16 @@ +/******************************************************************************* + * Copyright (c) 2024 Broadcom + * 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: + * Broadcom - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.languageserver.completion; + +import java.util.Collection; + +public record InternalCompletionList (Collection completionItems, boolean isIncomplete) { +} diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java index 9e478d1db..8090636be 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java @@ -213,16 +213,17 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { int offset = doc.toOffset(params.getPosition()); // get completions - Collection rawCompletions = engine.getCompletions(doc, offset); + InternalCompletionList rawCompletionList = engine.getCompletions(doc, offset); cancelToken.checkCanceled(); - List completions = filter(rawCompletions); + List completions = filter(rawCompletionList.completionItems()); Collections.sort(completions, ScoreableProposal.COMPARATOR); cancelToken.checkCanceled(); - list.setIsIncomplete(false); + boolean isIncomplete = rawCompletionList.isIncomplete(); + List items = new ArrayList<>(completions.size()); SortKeys sortkeys = new SortKeys(); int count = 0; @@ -230,8 +231,9 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { for (ICompletionProposal c : completions) { count++; - if (maxCompletions > 0 && count>maxCompletions) { - list.setIsIncomplete(true); + if (maxCompletions > 0 && count > maxCompletions) { + // override whatever completion engines said about being incomplete + isIncomplete = true; break; } try { @@ -244,6 +246,8 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { cancelToken.checkCanceled(); list.setItems(items); + list.setIsIncomplete(isIncomplete); + //This is a hack is no longer needed but keeping it as a reference: // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=535823 // Reason hack is not needed is because of the fix in: https://www.pivotaltracker.com/story/show/159667257 diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java index a00cbbf3d..fd5e4b808 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2018 Pivotal, Inc. + * Copyright (c) 2016, 2024 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 @@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; 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.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal; import org.springframework.ide.vscode.commons.languageserver.completion.TransformedCompletion; import org.springframework.ide.vscode.commons.util.Assert; @@ -81,7 +82,7 @@ public class YamlCompletionEngine implements ICompletionEngine { } @Override - public Collection getCompletions(TextDocument _doc, int offset) throws Exception { + public InternalCompletionList getCompletions(TextDocument _doc, int offset) throws Exception { YamlDocument doc = new YamlDocument(_doc, structureProvider); if (!doc.isCommented(offset)) { SRootNode root = doc.getStructure(); @@ -98,16 +99,16 @@ public class YamlCompletionEngine implements ICompletionEngine { completions.addAll(getRelaxedCompletions(offset, doc, current, contextNode, baseIndent, deempasizeBy)); deempasizeBy += ScoreableProposal.DEEMP_NEXT_CONTEXT; } - return completions; + return new InternalCompletionList(completions, false); } else { //precise indentation only Assert.isLegal(contextNodes.size()<=1); for (SNode contextNode : contextNodes) { - return getBaseCompletions(offset, doc, current, contextNode); + return new InternalCompletionList(getBaseCompletions(offset, doc, current, contextNode), false); } } } - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } protected Collection getRelaxedCompletions(int offset, YamlDocument doc, SNode current, SNode contextNode, int baseIndent, double deempasizeBy) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ClasspathResourceCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ClasspathResourceCompletionProvider.java index 2810ab931..9425baf5c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ClasspathResourceCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ClasspathResourceCompletionProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020 Pivotal, Inc. + * Copyright (c) 2020, 2024 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 @@ -22,6 +22,7 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; 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.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder; @@ -73,7 +74,7 @@ public class ClasspathResourceCompletionProvider implements ICompletionEngine, L private PropertyCompletionFactory completionFactory = new PropertyCompletionFactory(); @Override - public Collection getCompletions(TextDocument doc, int offset) { + public InternalCompletionList getCompletions(TextDocument doc, int offset) { ImmutableList.Builder proposals = ImmutableList.builder(); IJavaProject jp = projectFinder.find(doc.getId()).orElse(null); if (jp!=null) { @@ -98,7 +99,7 @@ public class ClasspathResourceCompletionProvider implements ICompletionEngine, L } } } - return proposals.build(); + return new InternalCompletionList(proposals.build(), false); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/DollarPropertyCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/DollarPropertyCompletionProvider.java index 82331ee7a..c7d098fa6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/DollarPropertyCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/DollarPropertyCompletionProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020 Pivotal, Inc. + * Copyright (c) 2020, 2024 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 @@ -19,6 +19,7 @@ import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; 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.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder; import org.springframework.ide.vscode.commons.util.BadLocationException; @@ -51,7 +52,7 @@ public class DollarPropertyCompletionProvider implements ICompletionEngine, Lang } @Override - public Collection getCompletions(TextDocument doc, int offset) { + public InternalCompletionList getCompletions(TextDocument doc, int offset) { ImmutableList.Builder proposals = ImmutableList.builder(); String prefix = PREFIX_FINDER.getPrefix(doc, offset); int prefixStart = offset-prefix.length(); @@ -74,7 +75,7 @@ public class DollarPropertyCompletionProvider implements ICompletionEngine, Lang } catch (BadLocationException e) { //ignore. Didn't find the '${' } - return proposals.build(); + return new InternalCompletionList(proposals.build(), false); } @Override 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 cbcfe225c..b430cec18 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2024 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 @@ -25,6 +25,7 @@ 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.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -48,7 +49,7 @@ public class BootJavaCompletionEngine implements ICompletionEngine, LanguageSpec } @Override - public Collection getCompletions(TextDocument document, int offset) throws Exception { + public InternalCompletionList getCompletions(TextDocument document, int offset) throws Exception { return cuCache.withCompilationUnit(document, cu -> { if (cu != null) { ASTNode node = findNode(document, offset, cu); @@ -58,11 +59,12 @@ public class BootJavaCompletionEngine implements ICompletionEngine, LanguageSpec collectCompletionsForAnnotations(node, offset, document, completions); collectCompletions(node, offset, document, completions); snippets.getCompletions(document, offset, node, cu, completions); - return completions; + + return new InternalCompletionList(completions, false); } } - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); }); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java index 119ac9cf0..25e25b443 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2019 Pivotal, Inc. + * Copyright (c) 2016, 2024 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 @@ -19,6 +19,7 @@ import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.types.TypeUtilProvider; 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.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.util.BadLocationException; @@ -54,9 +55,11 @@ public class SpringPropertiesCompletionEngine implements ICompletionEngine, Lang * Create completions proposals in the context of a properties text editor. */ @Override - public Collection getCompletions(TextDocument doc, int offset) throws BadLocationException { - return new PropertiesCompletionProposalsCalculator(indexProvider.getIndex(doc).getProperties(), + public InternalCompletionList getCompletions(TextDocument doc, int offset) throws BadLocationException { + Collection completionItems = new PropertiesCompletionProposalsCalculator(indexProvider.getIndex(doc).getProperties(), typeUtilProvider.getTypeUtil(sourceLinks, doc), completionFactory, doc, offset, preferLowerCaseEnums).calculate(); + + return new InternalCompletionList(completionItems, false); } public boolean getPreferLowerCaseEnums() { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java index 9290963f1..7238997b0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java @@ -68,6 +68,7 @@ import org.springframework.ide.vscode.boot.xml.completions.TypeCompletionProposa import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; 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.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; @@ -135,9 +136,9 @@ public class SpringXMLCompletionEngine implements ICompletionEngine, LanguageSpe } @Override - public Collection getCompletions(TextDocument doc, int offset) throws Exception { + public InternalCompletionList getCompletions(TextDocument doc, int offset) throws Exception { if (!config.isSpringXMLSupportEnabled() || !config.isXmlContentAssistEnabled()) { - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } String content = doc.get(); @@ -175,7 +176,7 @@ public class SpringXMLCompletionEngine implements ICompletionEngine, LanguageSpe XMLCompletionProvider completionProvider = this.completionProviders.get(key); if (completionProvider != null) { - Collection completions = completionProvider.getCompletions(doc, namespace, node, attributeAt, scanner, offset); + InternalCompletionList completions = completionProvider.getCompletions(doc, namespace, node, attributeAt, scanner, offset); return completions; } } @@ -185,7 +186,7 @@ public class SpringXMLCompletionEngine implements ICompletionEngine, LanguageSpe if (scanner.getTokenOffset() <= offset && offset < scanner.getTokenEnd()) { if (node.getParentNode() != null && node.getParentNode() instanceof DOMDocument && namespace.equals("http://www.springframework.org/schema/beans") && node.getLocalName().equals("beans")) { - return NamespaceCompletionProvider.createNamespaceCompletionProposals(doc, offset, token, node); + return new InternalCompletionList(NamespaceCompletionProvider.createNamespaceCompletionProposals(doc, offset, token, node), false); } } break; @@ -193,7 +194,7 @@ public class SpringXMLCompletionEngine implements ICompletionEngine, LanguageSpe if (scanner.getTokenOffset() <= offset && offset < scanner.getTokenEnd()) { if (node.getParentNode() != null && node.getParentNode() instanceof DOMDocument && namespace.equals("http://www.springframework.org/schema/beans") && node.getLocalName().equals("beans")) { - return NamespaceCompletionProvider.createNamespaceCompletionProposals(doc, offset, token, node); + return new InternalCompletionList(NamespaceCompletionProvider.createNamespaceCompletionProposals(doc, offset, token, node), false); } } break; @@ -203,10 +204,10 @@ public class SpringXMLCompletionEngine implements ICompletionEngine, LanguageSpe token = scanner.scan(); } } - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } - private Collection emptySpringXMLConfigSnippet(TextDocument doc) { + private InternalCompletionList emptySpringXMLConfigSnippet(TextDocument doc) { CompletionItemKind kind = CompletionItemKind.Snippet; @@ -244,7 +245,7 @@ public class SpringXMLCompletionEngine implements ICompletionEngine, LanguageSpe Collection completions = new ArrayList<>(1); completions.add(proposal); - return completions; + return new InternalCompletionList(completions, false); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/XMLCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/XMLCompletionProvider.java index 26196d3ed..b28fbbaf0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/XMLCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/XMLCompletionProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2024 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 @@ -10,12 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.xml; -import java.util.Collection; - import org.eclipse.lemminx.dom.DOMAttr; import org.eclipse.lemminx.dom.DOMNode; import org.eclipse.lemminx.dom.parser.Scanner; -import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -23,7 +21,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument; */ public interface XMLCompletionProvider { - Collection getCompletions(TextDocument doc, String namespace, DOMNode node, + InternalCompletionList getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, Scanner scanner, int offset); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java index 0d7017833..4aff7a5f9 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2024 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 @@ -10,7 +10,6 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.xml.completions; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -27,6 +26,7 @@ import org.springframework.ide.vscode.boot.xml.XMLCompletionProvider; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Renderable; @@ -48,7 +48,7 @@ public class BeanRefCompletionProposalProvider implements XMLCompletionProvider } @Override - public Collection getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, + public InternalCompletionList getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, Scanner scanner, int offset) { int tokenOffset = scanner.getTokenOffset(); @@ -68,7 +68,7 @@ public class BeanRefCompletionProposalProvider implements XMLCompletionProvider List addonInfos = symbolIndex.getAllAdditionalInformation(addonInfo -> addonInfo instanceof BeansSymbolAddOnInformation); - return addonInfos.stream() + List completionItems = addonInfos.stream() .map(info -> (BeansSymbolAddOnInformation) info) .map(beanInfo -> beanInfo.getBeanID()) .filter(beanID -> beanID != null && beanID.length() > 0) @@ -76,9 +76,11 @@ public class BeanRefCompletionProposalProvider implements XMLCompletionProvider .filter(tuple -> tuple.getT2() != 0.0) .map(tuple -> createProposal(tuple.getT1(), doc, offset, searchPrefix, tuple.getT2())) .collect(Collectors.toList()); + + return new InternalCompletionList(completionItems, false); }; - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } private ICompletionProposal createProposal(String beanID, TextDocument doc, int offset, String prefix, Double score) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/ConstructorArgNameCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/ConstructorArgNameCompletionProposalProvider.java index 0b11c4cad..551c118fa 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/ConstructorArgNameCompletionProposalProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/ConstructorArgNameCompletionProposalProvider.java @@ -36,6 +36,7 @@ import org.springframework.ide.vscode.commons.java.IMethod; import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -54,7 +55,7 @@ public class ConstructorArgNameCompletionProposalProvider implements XMLCompleti } @Override - public Collection getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, + public InternalCompletionList getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, Scanner scanner, int offset) { int tokenOffset = scanner.getTokenOffset(); @@ -82,14 +83,16 @@ public class ConstructorArgNameCompletionProposalProvider implements XMLCompleti log.info("Bean class '{}'", beanClass); final String searchPrefix = prefix; - return constructorArgNameCandidates(project, beanClass) + List completionItems = constructorArgNameCandidates(project, beanClass) .filter(constructorArg -> constructorArg.getRight().startsWith(searchPrefix)) .map(constructorArg -> createProposal(constructorArg, doc, offset, tokenOffset, tokenEnd)) .collect(Collectors.toList()); + + return new InternalCompletionList(completionItems, false); } }; - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } public static String identifyBeanClass(DOMNode node) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java index 773a6f610..c57908c20 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2024 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 @@ -15,6 +15,7 @@ import static org.springframework.ide.vscode.boot.xml.XmlConfigConstants.CLASS_A import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -30,6 +31,7 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.IMethod; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.StringUtil; @@ -49,7 +51,7 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv } @Override - public Collection getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, + public InternalCompletionList getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, Scanner scanner, int offset) { int tokenOffset = scanner.getTokenOffset(); @@ -77,14 +79,16 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv log.info("Bean class '{}'", beanClass); final String searchPrefix = prefix; - return propertyNameCandidateMethods(project, beanClass) + List completionItems = propertyNameCandidateMethods(project, beanClass) .filter(method -> getPropertyName(method).startsWith(searchPrefix)) .map(method -> createProposal(method, doc, offset, tokenOffset, tokenEnd)) .collect(Collectors.toList()); + + return new InternalCompletionList(completionItems, false); } }; - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } public static String identifyBeanClass(DOMNode node) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/TypeCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/TypeCompletionProposalProvider.java index 5f6908b39..86a874eae 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/TypeCompletionProposalProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/TypeCompletionProposalProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2019, 2020 Pivotal, Inc. + * Copyright (c) 2019, 2024 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 @@ -10,7 +10,6 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.xml.completions; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -27,6 +26,7 @@ import org.springframework.ide.vscode.boot.xml.XMLCompletionProvider; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.languageserver.completion.InternalCompletionList; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; import org.springframework.ide.vscode.commons.protocol.java.JavaCodeCompleteData; @@ -59,7 +59,7 @@ public class TypeCompletionProposalProvider implements XMLCompletionProvider { } @Override - public Collection getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, + public InternalCompletionList getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, Scanner scanner, int offset) { int tokenOffset = scanner.getTokenOffset(); @@ -92,7 +92,7 @@ public class TypeCompletionProposalProvider implements XMLCompletionProvider { try { List list = completions.get(); - return list.stream() + List completionItems = list.stream() .filter(proposal -> { if (proposal.isClassProposal()) return classesAllowed; if (proposal.isInterfaceProposal()) return interfacesAllowed; @@ -103,13 +103,15 @@ public class TypeCompletionProposalProvider implements XMLCompletionProvider { .map(proposal -> createProposal(proposal, doc, finalPrefix, offset)) .filter(proposal -> proposal != null) .collect(Collectors.toList()); + + return new InternalCompletionList(completionItems, true); } catch (Exception e) { log.error("{}", e); } }; - return Collections.emptyList(); + return new InternalCompletionList(Collections.emptyList(), false); } private ICompletionProposal createProposal(JavaCodeCompleteData proposal, TextDocument doc, String prefix, int offset) { @@ -130,11 +132,12 @@ public class TypeCompletionProposalProvider implements XMLCompletionProvider { CompletionItemKind kind = CompletionItemKind.Module; DocumentEdits edits = new DocumentEdits(doc, false); - if (fqName.startsWith(prefix)) { - edits.insert(offset, fqName.substring(prefix.length())); - } else { - edits.replace(offset - prefix.length(), offset, fqName); - } + edits.replace(offset - prefix.length(), offset, fqName); +// if (fqName.startsWith(prefix)) { +// edits.insert(offset, fqName.substring(prefix.length())); +// } else { +// edits.replace(offset - prefix.length(), offset, fqName); +// } Renderable renderable = null; @@ -160,15 +163,18 @@ public class TypeCompletionProposalProvider implements XMLCompletionProvider { } DocumentEdits edits = new DocumentEdits(doc, false); - if (fqName.startsWith(prefix)) { - edits.insert(offset, fqName.substring(prefix.length())); - } else { - edits.replace(offset - prefix.length(), offset, fqName); - } + edits.replace(offset - prefix.length(), offset, fqName); +// if (fqName.startsWith(prefix)) { +// edits.insert(offset, fqName.substring(prefix.length())); +// } else { +// edits.replace(offset - prefix.length(), offset, fqName); +// } Renderable renderable = null; + + String filterText = prefix; - return new GenericXMLCompletionProposal(label, kind, edits, fqName, renderable, proposal.getRelevance()); + return new GenericXMLCompletionProposal(label, kind, edits, fqName, renderable, proposal.getRelevance(), filterText, null); } }