Bean completion invocation fixes

This commit is contained in:
aboyko
2025-02-25 22:50:04 -05:00
parent f78a41a481
commit 251221285e
16 changed files with 284 additions and 76 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Pivotal, Inc.
* Copyright (c) 2016, 2025 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,7 +15,7 @@ import java.util.Comparator;
import org.springframework.ide.vscode.commons.util.Assert;
public abstract class ScoreableProposal implements ICompletionProposal {
public abstract class AbstractScoreableProposal implements ICompletionProposalWithScore {
public static final double DEEMP_EXISTS = 0.1;
public static final double DEEMP_DEPRECATION = 0.2;
@@ -34,21 +34,21 @@ public abstract class ScoreableProposal implements ICompletionProposal {
public static final Comparator<ICompletionProposal> COMPARATOR = new Comparator<ICompletionProposal>() {
@Override
public int compare(ICompletionProposal p1, ICompletionProposal p2) {
if (p1 instanceof ScoreableProposal && p2 instanceof ScoreableProposal) {
double s1 = ((ScoreableProposal)p1).getScore();
double s2 = ((ScoreableProposal)p2).getScore();
if (p1 instanceof ICompletionProposalWithScore && p2 instanceof ICompletionProposalWithScore) {
double s1 = ((ICompletionProposalWithScore)p1).getScore();
double s2 = ((ICompletionProposalWithScore)p2).getScore();
if (s1 == s2) {
String name1 = ((ScoreableProposal)p1).getLabel();
String name2 = ((ScoreableProposal)p2).getLabel();
String name1 = ((ICompletionProposalWithScore)p1).getLabel();
String name2 = ((ICompletionProposalWithScore)p2).getLabel();
return name1.compareTo(name2);
} else {
return Double.compare(s2, s1);
}
}
if (p1 instanceof ScoreableProposal) {
if (p1 instanceof ICompletionProposalWithScore) {
return -1;
}
if (p2 instanceof ScoreableProposal) {
if (p2 instanceof ICompletionProposalWithScore) {
return +1;
}
return p1.getLabel().compareTo(p2.getLabel());
@@ -59,7 +59,7 @@ public abstract class ScoreableProposal implements ICompletionProposal {
return getBaseScore() - deemphasizedBy;
}
@Override
public ScoreableProposal deemphasize(double howmuch) {
public AbstractScoreableProposal deemphasize(double howmuch) {
Assert.isLegal(howmuch>=0.0);
deemphasizedBy+= howmuch*DEEMP_VALUE;
return this;

View File

@@ -0,0 +1,17 @@
/*******************************************************************************
* Copyright (c) 2025 Broadcom, 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:
* Broadcom, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.commons.languageserver.completion;
public interface ICompletionProposalWithScore extends ICompletionProposal {
double getScore();
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2023 Pivotal, Inc.
* Copyright (c) 2017, 2025 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
@@ -23,7 +23,7 @@ import org.springframework.ide.vscode.commons.util.Renderable;
*
* @author Kris De Volder
*/
public abstract class TransformedCompletion extends ScoreableProposal {
public abstract class TransformedCompletion extends AbstractScoreableProposal {
protected final ICompletionProposal original;
@@ -71,8 +71,8 @@ public abstract class TransformedCompletion extends ScoreableProposal {
@Override
public double getBaseScore() {
if (original instanceof ScoreableProposal) {
return ((ScoreableProposal) original).getScore();
if (original instanceof AbstractScoreableProposal) {
return ((AbstractScoreableProposal) original).getScore();
}
return 0;
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2023 VMware Inc.
* Copyright (c) 2016, 2025 VMware 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
@@ -218,7 +218,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine {
cancelToken.checkCanceled();
List<ICompletionProposal> completions = filter(rawCompletionList.completionItems());
Collections.sort(completions, ScoreableProposal.COMPARATOR);
Collections.sort(completions, AbstractScoreableProposal.COMPARATOR);
cancelToken.checkCanceled();

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2017 Pivotal, Inc.
* Copyright (c) 2016, 2025 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
@@ -14,7 +14,7 @@ package org.springframework.ide.vscode.commons.yaml.completion;
import org.eclipse.lsp4j.CompletionItemKind;
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.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.Renderables;
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -27,7 +27,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
private static final int ERROR_COMPLETION_SCORE = -10000000;
public static class BeanPropertyProposal extends ScoreableProposal {
public static class BeanPropertyProposal extends AbstractScoreableProposal {
// private IDocument doc;
private String contextProperty;
@@ -81,7 +81,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
}
}
public class ValueProposal extends ScoreableProposal {
public class ValueProposal extends AbstractScoreableProposal {
private String value;
private String label;
@@ -137,7 +137,7 @@ public class DefaultCompletionFactory implements CompletionFactory {
}
}
public static final class ErrorProposal extends ScoreableProposal {
public static final class ErrorProposal extends AbstractScoreableProposal {
private final String longMessage;
private String shortMessage;
private String filterText;

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2019 Pivotal, Inc.
* Copyright (c) 2016, 2025 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,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.yaml.completion;
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_DASH_PROPOSAL;
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_DEPRECATION;
import static org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal.DEEMP_DASH_PROPOSAL;
import static org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal.DEEMP_DEPRECATION;
import java.util.ArrayList;
import java.util.Collection;
@@ -25,7 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.TransformedCompletion;
import org.springframework.ide.vscode.commons.languageserver.util.PlaceHolderString;
import org.springframework.ide.vscode.commons.util.CollectionUtil;
@@ -206,7 +206,7 @@ public class YTypeAssistContext extends AbstractYamlAssistContext {
ICompletionProposal completion = completionFactory().beanProperty(doc.getDocument(),
contextPath.toPropString(), getType(),
query, p, score, edits, typeUtil);
if (p.isDeprecated() && completion instanceof ScoreableProposal) {
if (p.isDeprecated() && completion instanceof AbstractScoreableProposal) {
completion.deemphasize(DEEMP_DEPRECATION);
}
proposals.add(completion);

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016, 2024 Pivotal, Inc.
* Copyright (c) 2016, 2025 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,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.yaml.completion;
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_DEDENTED_PROPOSAL;
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_INDENTED_PROPOSAL;
import static org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal.DEEMP_DEDENTED_PROPOSAL;
import static org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal.DEEMP_INDENTED_PROPOSAL;
import java.util.ArrayList;
import java.util.Collection;
@@ -26,7 +26,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Document
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.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.TransformedCompletion;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.Unicodes;
@@ -97,7 +97,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
double deempasizeBy = 0.0;
for (SNode contextNode : contextNodes) {
completions.addAll(getRelaxedCompletions(offset, doc, current, contextNode, baseIndent, deempasizeBy));
deempasizeBy += ScoreableProposal.DEEMP_NEXT_CONTEXT;
deempasizeBy += AbstractScoreableProposal.DEEMP_NEXT_CONTEXT;
}
return new InternalCompletionList(completions, false);
} else {
@@ -129,7 +129,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
List<ICompletionProposal> transformed = new ArrayList<>();
for (ICompletionProposal p : completions) {
int targetIndent = p.getLabel().startsWith("- ") ? dashyIndent : plainIndent;
ScoreableProposal p_fixed = indentFix((ScoreableProposal)p, targetIndent - baseIndent, currentNode, contextNode, doc);
AbstractScoreableProposal p_fixed = indentFix((AbstractScoreableProposal)p, targetIndent - baseIndent, currentNode, contextNode, doc);
if (p_fixed!=null) {
p_fixed.deemphasize(deempasizeBy);
transformed.add(p_fixed);
@@ -140,7 +140,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
return Collections.emptyList();
}
protected ScoreableProposal indentFix(ScoreableProposal p, int fixIndentBy, SNode currentNode, SNode contextNode, YamlDocument doc) {
protected AbstractScoreableProposal indentFix(AbstractScoreableProposal p, int fixIndentBy, SNode currentNode, SNode contextNode, YamlDocument doc) {
if (fixIndentBy==0) {
return p;
} else if (fixIndentBy>0) {
@@ -190,7 +190,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
: contextNode.getIndent() + YamlIndentUtil.INDENT_BY;
}
public ScoreableProposal dedented(ICompletionProposal proposal, int numSpacesToRemove, IDocument doc) {
public AbstractScoreableProposal dedented(ICompletionProposal proposal, int numSpacesToRemove, IDocument doc) {
Assert.isLegal(numSpacesToRemove>0);
int spacesEnd = proposal.getTextEdit().getFirstEditStart();
int spacesStart = spacesEnd-numSpacesToRemove;
@@ -198,7 +198,7 @@ public class YamlCompletionEngine implements ICompletionEngine {
String spaces = new DocumentRegion(doc, spacesStart, spacesEnd).toString();
YamlIndentUtil indenter = new YamlIndentUtil(doc);
if (spaces.length()==numSpacesToRemove && SPACES.matcher(spaces).matches()) {
ScoreableProposal transformed = new TransformedCompletion(proposal) {
AbstractScoreableProposal transformed = new TransformedCompletion(proposal) {
@Override public String tranformLabel(String originalLabel) {
return Strings.repeat(Unicodes.LEFT_ARROW+" ", numArrows) + originalLabel;
}
@@ -228,9 +228,9 @@ public class YamlCompletionEngine implements ICompletionEngine {
return null;
}
public ScoreableProposal indented(ICompletionProposal proposal, String indentStr, YamlDocument doc) {
public AbstractScoreableProposal indented(ICompletionProposal proposal, String indentStr, YamlDocument doc) {
int numArrows = (indentStr.length()+1)/2;
ScoreableProposal transformed = new TransformedCompletion(proposal) {
AbstractScoreableProposal transformed = new TransformedCompletion(proposal) {
@Override public String tranformLabel(String originalLabel) {
return Strings.repeat(Unicodes.RIGHT_ARROW+" ", numArrows) + originalLabel;
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015, 2023 Pivotal, Inc.
* Copyright (c) 2015, 2025 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,11 +12,11 @@ package org.springframework.ide.vscode.boot.common;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.yaml.schema.YType;
public abstract class AbstractPropertyProposal extends ScoreableProposal {
public abstract class AbstractPropertyProposal extends AbstractScoreableProposal {
@Override
public String getDetail() {

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2014, 2023 Pivotal, Inc.
* Copyright (c) 2014, 2025 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
@@ -18,7 +18,7 @@ import org.springframework.ide.vscode.boot.metadata.types.TypeUtil;
import org.springframework.ide.vscode.boot.metadata.types.TypedProperty;
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.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.FuzzyMap.Match;
import org.springframework.ide.vscode.commons.util.Renderable;
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -28,7 +28,7 @@ import org.springframework.ide.vscode.commons.yaml.schema.YType;
public class PropertyCompletionFactory {
public ICompletionProposal valueProposal(String value, String query, String niceTypeName, double score, DocumentEdits edits, Renderable info) {
return new ScoreableProposal() {
return new AbstractScoreableProposal() {
@Override
public DocumentEdits getTextEdit() {

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 Broadcom
* Copyright (c) 2024, 2025 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
@@ -12,13 +12,13 @@ package org.springframework.ide.vscode.boot.java.annotations;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.Renderable;
/**
* @author Martin Lippert
*/
public class AnnotationAttributeCompletionProposal extends ScoreableProposal {
public class AnnotationAttributeCompletionProposal extends AbstractScoreableProposal {
private final AnnotationAttributeProposal coreProposal;

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2024 Broadcom, Inc.
* Copyright (c) 2017, 2025 Broadcom, 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
@@ -18,7 +18,7 @@ import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.boot.java.rewrite.RewriteRefactorings;
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.ICompletionProposalWithScore;
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
import org.springframework.ide.vscode.commons.rewrite.java.InjectBeanCompletionRecipe;
@@ -30,7 +30,7 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
* @author Udayani V
* @author Alex Boyko
*/
public class BeanCompletionProposal implements ICompletionProposal {
public class BeanCompletionProposal implements ICompletionProposalWithScore {
private DocumentEdits edits;
private IDocument doc;
@@ -38,14 +38,17 @@ public class BeanCompletionProposal implements ICompletionProposal {
private String beanType;
private String className;
private RewriteRefactorings rewriteRefactorings;
private double score;
public BeanCompletionProposal(DocumentEdits edits, IDocument doc, String beanId, String beanType, String className,
double score,
RewriteRefactorings rewriteRefactorings) {
this.edits = edits;
this.doc = doc;
this.beanId = beanId;
this.beanType = beanType;
this.className = className;
this.score = score;
this.rewriteRefactorings = rewriteRefactorings;
}
@@ -82,6 +85,10 @@ public class BeanCompletionProposal implements ICompletionProposal {
.withRecipeScope(RecipeScope.NODE);
return Optional.of(rewriteRefactorings.createFixCommand("Inject bean '%s'".formatted(beanId), f));
}
@Override
public double getScore() {
return score;
}
}

View File

@@ -10,13 +10,19 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.beans;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclaration;
@@ -30,6 +36,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Document
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
@@ -53,7 +60,7 @@ public class BeanCompletionProvider implements CompletionProvider {
@Override
public void provideCompletions(ASTNode node, int offset, TextDocument doc,
Collection<ICompletionProposal> completions) {
if (node instanceof SimpleName) {
if (node instanceof SimpleName || node instanceof Block) {
try {
// Don't look at anything inside Annotation or VariableDelcaration node
for (ASTNode n = node; n != null; n = n.getParent()) {
@@ -77,14 +84,36 @@ public class BeanCompletionProvider implements CompletionProvider {
if (isSpringComponent(topLevelClass)) {
String className = getFullyQualifiedName(topLevelClass);
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
ITypeBinding topLevelBeanType = topLevelClass.resolveBinding();
Set<String> declaredFiledsTypes = Arrays.stream(topLevelBeanType.getDeclaredFields())
.map(vd -> vd.getType())
.filter(Objects::nonNull)
.map(t -> t.getQualifiedName())
.collect(Collectors.toSet());
final String prefix = node instanceof Block ? "" : node.toString();
for (Bean bean : beans) {
DocumentEdits edits = new DocumentEdits(doc, false);
edits.replace(offset - node.toString().length(), offset, bean.getName());
// If current class is a bean - ignore it
if (className.equals(bean.getType())) {
continue;
}
// Filter out beans already injected into this class
if (declaredFiledsTypes.contains(bean.getType())) {
continue;
}
double score = FuzzyMatcher.matchScore(prefix, bean.getName());
if (score > 0) {
DocumentEdits edits = new DocumentEdits(doc, false);
if (node instanceof Block) {
edits.insert(offset, bean.getName());
} else {
edits.replace(offset - prefix.length(), offset, bean.getName());
}
BeanCompletionProposal proposal = new BeanCompletionProposal(edits, doc, bean.getName(),
bean.getType(), className, rewriteRefactorings);
BeanCompletionProposal proposal = new BeanCompletionProposal(edits, doc, bean.getName(),
bean.getType(), className, score, rewriteRefactorings);
completions.add(proposal);
completions.add(proposal);
}
}
}
} catch (Exception e) {
@@ -127,9 +156,10 @@ public class BeanCompletionProvider implements CompletionProvider {
}
private static String getFullyQualifiedName(TypeDeclaration typeDecl) {
if (typeDecl.resolveBinding() != null) {
String qualifiedName = typeDecl.resolveBinding().getQualifiedName();
return qualifiedName.replaceAll("\\.(?=[^\\.]+$)", "\\$");
ITypeBinding binding = typeDecl.resolveBinding();
if (binding != null) {
String qualifiedName = binding.getQualifiedName();
return qualifiedName/*.replaceAll("\\.(?=[^\\.]+$)", "\\$")*/;
}
CompilationUnit cu = (CompilationUnit) typeDecl.getRoot();
String packageName = cu.getPackage() != null ? cu.getPackage().getName().getFullyQualifiedName() : "";

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2020 Pivotal, Inc.
* Copyright (c) 2017, 2025 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
@@ -14,14 +14,14 @@ import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.boot.common.InformationTemplates;
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.FuzzyMap.Match;
import org.springframework.ide.vscode.commons.util.Renderable;
/**
* @author Martin Lippert
*/
public class ValuePropertyKeyProposal extends ScoreableProposal {
public class ValuePropertyKeyProposal extends AbstractScoreableProposal {
private static final String EMPTY_DETAIL = "";

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2024 Pivotal, Inc.
* Copyright (c) 2019, 2025 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,13 +15,13 @@ import java.util.function.Supplier;
import org.eclipse.lsp4j.CompletionItemKind;
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.Renderable;
/**
* @author Martin Lippert
*/
public class GenericXMLCompletionProposal extends ScoreableProposal {
public class GenericXMLCompletionProposal extends AbstractScoreableProposal {
private final String label;
private final CompletionItemKind kind;

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2015, 2023 Pivotal, Inc.
* Copyright (c) 2015, 2025 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,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.yaml.completions;
import static org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal.DEEMP_EXISTS;
import static org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal.DEEMP_EXISTS;
import java.util.ArrayList;
import java.util.Collection;
@@ -53,7 +53,7 @@ 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.LazyProposalApplier;
import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal;
import org.springframework.ide.vscode.commons.languageserver.completion.AbstractScoreableProposal;
import org.springframework.ide.vscode.commons.util.CollectionUtil;
import org.springframework.ide.vscode.commons.util.FuzzyMap.Match;
import org.springframework.ide.vscode.commons.util.FuzzyMatcher;
@@ -466,7 +466,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon
matchingProps.stream().forEach(match -> {
try {
DocumentEdits edits = createEdits(doc, node, offset, query, match);
ScoreableProposal completion = completionFactory.property(
AbstractScoreableProposal completion = completionFactory.property(
doc.getDocument(), edits, match, typeUtil
);
String prefix = indexNav.getPrefix();

View File

@@ -65,6 +65,7 @@ public class BeanCompletionProviderTest {
private Bean bean3;
private Bean bean4;
private Bean bean5;
private Bean bean6;
@BeforeEach
public void setup() throws Exception {
@@ -86,8 +87,9 @@ public class BeanCompletionProviderTest {
bean3 = new Bean("visitRepository", "org.springframework.samples.petclinic.owner.VisitRepository", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
bean4 = new Bean("visitService", "org.springframework.samples.petclinic.owner.VisitService", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
bean5 = new Bean("petService", "org.springframework.samples.petclinic.pet.Inner.PetService", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
bean6 = new Bean("testBeanCompletionClass", "org.sample.test.TestBeanCompletionClass", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null, false, "symbolLabel");
springIndex.updateBeans(project.getElementName(), new Bean[] {bean1, bean2, bean3, bean4, bean5});
springIndex.updateBeans(project.getElementName(), new Bean[] {bean1, bean2, bean3, bean4, bean5, bean6});
}
@AfterEach
@@ -97,7 +99,7 @@ public class BeanCompletionProviderTest {
@Test
public void testBeanCompletion_firstCompletion() throws Exception {
assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService"}, 0,
"""
package org.sample.test;
@@ -122,7 +124,32 @@ ownerRepository<*>
@Test
public void testBeanCompletion_secondCompletion() throws Exception {
assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 1,
assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService"}, 1,
"""
package org.sample.test;
import org.springframework.samples.petclinic.owner.OwnerService;
import org.springframework.stereotype.Controller;
@Controller
public class TestBeanCompletionClass {
private final OwnerService ownerService;
TestBeanCompletionClass(OwnerService ownerService) {
this.ownerService = ownerService;
}
public void test() {
ownerService<*>
}
}
""");
}
@Test
public void noPrefix_secondCompletion() throws Exception {
assertCompletions(getCompletion("<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 1,
"""
package org.sample.test;
@@ -147,7 +174,7 @@ ownerService<*>
@Test
public void testBeanCompletion_injectInnerClass() throws Exception {
assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 2,
assertCompletions(getCompletion("<*>"), new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 2,
"""
package org.sample.test;
@@ -199,7 +226,72 @@ petService<*>
}
""";
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 1,
assertCompletions(content, new String[] {"ownerRepository", "ownerService"}, 1,
"""
package org.sample.test;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.samples.petclinic.owner.OwnerService;
import org.springframework.stereotype.Controller;
@Controller
public class TestBeanCompletionClass {
private final OwnerRepository ownerRepository;
TestBeanCompletionClass(OwnerRepository ownerRepository) {
this.ownerRepository = ownerRepository;
}
public void test() {
}
}
@Controller
public class TestBeanCompletionSecondClass {
private final OwnerService ownerService;
TestBeanCompletionSecondClass(OwnerService ownerService) {
this.ownerService = ownerService;
}
public void test() {
ownerService<*>
}
}
""");
}
@Test
public void noPrefix_multipleClasses() throws Exception {
String content = """
package org.sample.test;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.stereotype.Controller;
@Controller
public class TestBeanCompletionClass {
private final OwnerRepository ownerRepository;
TestBeanCompletionClass(OwnerRepository ownerRepository) {
this.ownerRepository = ownerRepository;
}
public void test() {
}
}
@Controller
public class TestBeanCompletionSecondClass {
public void test() {
<*>
}
}
""";
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "testBeanCompletionClass", "visitRepository", "visitService"}, 1,
"""
package org.sample.test;
@@ -279,13 +371,13 @@ public class TestBeanCompletionClass {
public class Inner {
public void test() {
ownerRe<*>
owner<*>
}
}
}
""";
assertCompletions(content, new String[] {"ownerRepository", "ownerService", "petService", "visitRepository", "visitService"}, 0,
assertCompletions(content, new String[] {"ownerRepository", "ownerService"}, 0,
"""
package org.sample.test;
@@ -330,6 +422,68 @@ public class TestBeanCompletionClass {
return content;
}
@Test
public void beansPresent() throws Exception {
String content = """
package org.sample.test;
import org.springframework.stereotype.Controller;
@Controller
public class TestBeanCompletionSecondClass {
private final TestBeanCompletionClass testBeanCompletionClass;
TestBeanCompletionSecondClass(TestBeanCompletionClass testBeanCompletionClass) {
this.testBeanCompletionClass = testBeanCompletionClass;
}
public void test() {
owner<*>
}
}
@Controller
public class TestBeanCompletionClass {
public void test() {
}
}
""";
assertCompletions(content, new String[] {"ownerRepository", "ownerService"}, 0,
"""
package org.sample.test;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.stereotype.Controller;
@Controller
public class TestBeanCompletionSecondClass {
private final OwnerRepository ownerRepository;
private final TestBeanCompletionClass testBeanCompletionClass;
TestBeanCompletionSecondClass(TestBeanCompletionClass testBeanCompletionClass, OwnerRepository ownerRepository) {
this.testBeanCompletionClass = testBeanCompletionClass;
this.ownerRepository = ownerRepository;
}
public void test() {
ownerRepository<*>
}
}
@Controller
public class TestBeanCompletionClass {
public void test() {
}
}
""");
}
private void assertCompletions(String completionLine, String[] expectedCompletions, int chosenCompletion, String expectedResult) throws Exception {
assertCompletions(completionLine, expectedCompletions.length, expectedCompletions, chosenCompletion, expectedResult);
}