GH-1285: add support for code completion for classpath resources in value annotation
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2019 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
|
||||
@@ -22,13 +22,18 @@ import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.QualifiedName;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.beans.QualifierCompletionProposal;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||
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;
|
||||
@@ -43,6 +48,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class ValueCompletionProcessor implements CompletionProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ValueCompletionProcessor.class);
|
||||
|
||||
private final SpringPropertyIndexProvider indexProvider;
|
||||
private final ProjectBasedPropertyIndexProvider adHocIndexProvider;
|
||||
@@ -59,6 +66,13 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
int offset, TextDocument doc, Collection<ICompletionProposal> completions) {
|
||||
|
||||
try {
|
||||
Optional<IJavaProject> optionalProject = this.projectFinder.find(doc.getId());
|
||||
if (optionalProject.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IJavaProject project = optionalProject.get();
|
||||
|
||||
// case: @Value(<*>)
|
||||
if (node == annotation && doc.get(offset - 1, 2).endsWith("()")) {
|
||||
List<Match<PropertyInfo>> matches = findMatches("", doc);
|
||||
@@ -75,37 +89,70 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
|
||||
addClasspathResourceProposals(project, doc, offset, offset, "", true, completions);
|
||||
}
|
||||
// case: @Value(prefix<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof Annotation) {
|
||||
computeProposalsForSimpleName(node, completions, offset, doc);
|
||||
computeProposalsForSimpleName(project, node, completions, offset, doc);
|
||||
}
|
||||
// case: @Value(file.ext<*>) - the "." causes a QualifierNode to be generated
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof QualifiedName && node.getParent().getParent() instanceof Annotation) {
|
||||
computeProposalsForSimpleName(project, node.getParent(), completions, offset, doc);
|
||||
}
|
||||
// case: @Value(value=<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
computeProposalsForSimpleName(node, completions, offset, doc);
|
||||
computeProposalsForSimpleName(project, node, completions, offset, doc);
|
||||
}
|
||||
// case: @Value(value=<*>)
|
||||
else if (node instanceof SimpleName && node.getParent() instanceof QualifiedName && node.getParent().getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent().getParent()).getName().toString())) {
|
||||
computeProposalsForSimpleName(project, node.getParent(), completions, offset, doc);
|
||||
}
|
||||
// case: @Value("prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForStringLiteral(node, completions, offset, doc);
|
||||
computeProposalsForStringLiteral(project, (StringLiteral) node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
// case: @Value(value="prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
computeProposalsForStringLiteral(node, completions, offset, doc);
|
||||
computeProposalsForStringLiteral(project, (StringLiteral) node, completions, offset, doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("problem while looking for value annotation proposals", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void computeProposalsForSimpleName(ASTNode node, Collection<ICompletionProposal> completions, int offset,
|
||||
IDocument doc) {
|
||||
private void addClasspathResourceProposals(IJavaProject project, TextDocument doc, int startOffset, int endOffset, String prefix, boolean includeQuotes, Collection<ICompletionProposal> completions) {
|
||||
String[] resources = findResources(project, prefix);
|
||||
|
||||
double score = resources.length + 1000;
|
||||
for (String resource : resources) {
|
||||
|
||||
DocumentEdits edits = new DocumentEdits(doc, false);
|
||||
|
||||
if (includeQuotes) {
|
||||
edits.replace(startOffset, endOffset, "\"classpath:" + resource + "\"");
|
||||
}
|
||||
else {
|
||||
edits.replace(startOffset, endOffset, "classpath:" + resource);
|
||||
}
|
||||
|
||||
String label = "classpath:" + resource;
|
||||
|
||||
ICompletionProposal proposal = new QualifierCompletionProposal(edits, label, label, null, score--);
|
||||
completions.add(proposal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void computeProposalsForSimpleName(IJavaProject project, ASTNode node, Collection<ICompletionProposal> completions, int offset, TextDocument doc) {
|
||||
String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition());
|
||||
|
||||
int startOffset = node.getStartPosition();
|
||||
@@ -125,10 +172,12 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
|
||||
String unfilteredPrefix = node.toString().substring(0, offset - node.getStartPosition());
|
||||
addClasspathResourceProposals(project, doc, startOffset, endOffset, unfilteredPrefix, true, completions);
|
||||
}
|
||||
|
||||
private void computeProposalsForStringLiteral(ASTNode node, Collection<ICompletionProposal> completions, int offset,
|
||||
IDocument doc) throws BadLocationException {
|
||||
private void computeProposalsForStringLiteral(IJavaProject project, StringLiteral node, Collection<ICompletionProposal> completions, int offset, TextDocument doc) throws BadLocationException {
|
||||
String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, offset - (node.getStartPosition() + 1)), offset - (node.getStartPosition() + 1));
|
||||
|
||||
int startOffset = offset - prefix.length();
|
||||
@@ -164,6 +213,9 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
|
||||
completions.add(proposal);
|
||||
}
|
||||
|
||||
String unfilteredPrefix = node.getLiteralValue().substring(0, offset - (node.getStartPosition() + 1));
|
||||
addClasspathResourceProposals(project, doc, startOffset, endOffset, unfilteredPrefix, false, completions);
|
||||
}
|
||||
|
||||
private boolean isClosingBracketMissing(String fullNodeContent) {
|
||||
@@ -220,4 +272,14 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
return matches;
|
||||
}
|
||||
|
||||
private String[] findResources(IJavaProject project, String prefix) {
|
||||
String[] resources = IClasspathUtil.getClasspathResources(project.getClasspath()).stream()
|
||||
.distinct()
|
||||
.map(r -> r.replaceAll("\\\\", "/"))
|
||||
.filter(r -> ("classpath:" + r).contains(prefix))
|
||||
.toArray(String[]::new);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -153,10 +153,15 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${data.prop2}\"<*>)",
|
||||
"@Value(\"${else.prop3}\"<*>)",
|
||||
"@Value(\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md\"<*>)",
|
||||
"@Value(\"classpath:org/random-resource-org.md\"<*>)",
|
||||
"@Value(\"classpath:org/test/random-resource-org-test.txt\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,17 +169,23 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(value=\"${data.prop2}\"<*>)",
|
||||
"@Value(value=\"${else.prop3}\"<*>)",
|
||||
"@Value(value=\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(value=\"classpath:random-resource-root.md\"<*>)",
|
||||
"@Value(value=\"classpath:org/random-resource-org.md\"<*>)",
|
||||
"@Value(value=\"classpath:org/test/random-resource-org-test.txt\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEmptyBracketsCompletionWithWrongParamName() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(another=<*>)");
|
||||
prepareDefaultIndexData();
|
||||
assertAnnotationCompletions();
|
||||
assertPropertyCompletions();
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -182,10 +193,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value($<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${data.prop2}\"<*>)",
|
||||
"@Value(\"${else.prop3}\"<*>)",
|
||||
"@Value(\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -193,10 +206,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=$<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(value=\"${data.prop2}\"<*>)",
|
||||
"@Value(value=\"${else.prop3}\"<*>)",
|
||||
"@Value(value=\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -204,10 +219,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"$<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${data.prop2}<*>\")",
|
||||
"@Value(\"${else.prop3}<*>\")",
|
||||
"@Value(\"${spring.prop1}<*>\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -215,10 +232,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=\"$<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(value=\"${data.prop2}<*>\")",
|
||||
"@Value(value=\"${else.prop3}<*>\")",
|
||||
"@Value(value=\"${spring.prop1}<*>\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -226,10 +245,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"${<*>}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${data.prop2<*>}\")",
|
||||
"@Value(\"${else.prop3<*>}\")",
|
||||
"@Value(\"${spring.prop1<*>}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -237,10 +258,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=\"${<*>}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(value=\"${data.prop2<*>}\")",
|
||||
"@Value(value=\"${else.prop3<*>}\")",
|
||||
"@Value(value=\"${spring.prop1<*>}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -248,10 +271,15 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${data.prop2}<*>\")",
|
||||
"@Value(\"${else.prop3}<*>\")",
|
||||
"@Value(\"${spring.prop1}<*>\")");
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md<*>\")",
|
||||
"@Value(\"classpath:org/random-resource-org.md<*>\")",
|
||||
"@Value(\"classpath:org/test/random-resource-org-test.txt<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -259,8 +287,124 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(spri<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexPrefixCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(spring.pr<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrefixCompletionWithParamName() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=sprin<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions(
|
||||
"@Value(value=\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexPrefixCompletionWithParamName() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=spring.pr<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions(
|
||||
"@Value(value=\"${spring.prop1}\"<*>)");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClasspathPrefixCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(cla<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md\"<*>)",
|
||||
"@Value(\"classpath:org/random-resource-org.md\"<*>)",
|
||||
"@Value(\"classpath:org/test/random-resource-org-test.txt\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResourceNameInPrefixCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(root<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexResourceNameInPrefixCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(root.md<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexResourceNameInPrefixWithinQoutesCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"root.md<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexResourceNameInPrefixWithParamNameCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=root.md<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(value=\"classpath:random-resource-root.md\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexResourceNameInPrefixWithinQoutesAndParamNameCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=\"root.md<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(value=\"classpath:random-resource-root.md<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClasspathPrefixCompletionWithParamName() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(value=cla<*>)");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(value=\"classpath:random-resource-root.md\"<*>)",
|
||||
"@Value(value=\"classpath:org/random-resource-org.md\"<*>)",
|
||||
"@Value(value=\"classpath:org/test/random-resource-org-test.txt\"<*>)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -268,8 +412,34 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"spri<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${spring.prop1}<*>\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComplexPrefixCompletionWithQuotes() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"spring.pr<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"${spring.prop1}<*>\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testQuotedClasspathPrefixCompletion() throws Exception {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"cla<*>\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertPropertyCompletions();
|
||||
|
||||
assertClasspathCompletions(
|
||||
"@Value(\"classpath:random-resource-root.md<*>\")",
|
||||
"@Value(\"classpath:org/random-resource-org.md<*>\")",
|
||||
"@Value(\"classpath:org/test/random-resource-org-test.txt<*>\")");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -277,10 +447,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"#{<*>}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"#{${data.prop2}<*>}\")",
|
||||
"@Value(\"#{${else.prop3}<*>}\")",
|
||||
"@Value(\"#{${spring.prop1}<*>}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -288,10 +460,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"#{345$<*>}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"#{345${data.prop2}<*>}\")",
|
||||
"@Value(\"#{345${else.prop3}<*>}\")",
|
||||
"@Value(\"#{345${spring.prop1}<*>}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -299,10 +473,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"#{345${<*>}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"#{345${data.prop2}<*>}\")",
|
||||
"@Value(\"#{345${else.prop3}<*>}\")",
|
||||
"@Value(\"#{345${spring.prop1}<*>}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -310,10 +486,12 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"#{345${<*>}}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"#{345${data.prop2<*>}}\")",
|
||||
"@Value(\"#{345${else.prop3<*>}}\")",
|
||||
"@Value(\"#{345${spring.prop1<*>}}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -321,8 +499,10 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"#{345${spri<*>}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"#{345${spring.prop1}<*>}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -330,8 +510,10 @@ public class ValueCompletionTest {
|
||||
prepareCase("@Value(\"onField\")", "@Value(\"#{345${spri<*>}}\")");
|
||||
prepareDefaultIndexData();
|
||||
|
||||
assertAnnotationCompletions(
|
||||
assertPropertyCompletions(
|
||||
"@Value(\"#{345${spring.prop1<*>}}\")");
|
||||
|
||||
assertClasspathCompletions();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -353,6 +535,10 @@ public class ValueCompletionTest {
|
||||
editor.assertContextualCompletions(
|
||||
"<*>"
|
||||
, //==>
|
||||
"classpath:random-resource-root.md<*>",
|
||||
"classpath:org/random-resource-org.md<*>",
|
||||
"classpath:org/test/random-resource-org-test.txt<*>",
|
||||
|
||||
"${data.prop2}<*>",
|
||||
"${else.prop3}<*>",
|
||||
"${spring.prop1}<*>"
|
||||
@@ -364,7 +550,11 @@ public class ValueCompletionTest {
|
||||
editor.assertContextualCompletions(
|
||||
"<*>"
|
||||
, //==>
|
||||
"${data.prop2}<*>",
|
||||
"classpath:random-resource-root.md<*>",
|
||||
"classpath:org/random-resource-org.md<*>",
|
||||
"classpath:org/test/random-resource-org-test.txt<*>",
|
||||
|
||||
"${data.prop2}<*>",
|
||||
"${else.prop3}<*>",
|
||||
"${spring.ad-hoc.other-thingy}<*>",
|
||||
"${spring.ad-hoc.thingy}<*>",
|
||||
@@ -394,18 +584,47 @@ public class ValueCompletionTest {
|
||||
editor = new Editor(harness, content, LanguageId.JAVA);
|
||||
}
|
||||
|
||||
private void assertAnnotationCompletions(String... completedAnnotations) throws Exception {
|
||||
private void assertPropertyCompletions(String... completedAnnotations) throws Exception {
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
int i = 0;
|
||||
for (String expectedCompleted : completedAnnotations) {
|
||||
|
||||
List<CompletionItem> filteredCompletions = completions.stream()
|
||||
.filter(item -> !item.getTextEdit().getLeft().getNewText().contains("classpath"))
|
||||
.toList();
|
||||
|
||||
assertEquals(completedAnnotations.length, filteredCompletions.size());
|
||||
|
||||
for (int i = 0; i < completedAnnotations.length; i++) {
|
||||
CompletionItem completion = filteredCompletions.get(i);
|
||||
|
||||
Editor clonedEditor = editor.clone();
|
||||
clonedEditor.apply(completions.get(i++));
|
||||
if (!clonedEditor.getText().contains(expectedCompleted)) {
|
||||
fail("Not found '"+expectedCompleted+"' in \n"+clonedEditor.getText());
|
||||
clonedEditor.apply(completion);
|
||||
|
||||
String expected = completedAnnotations[i];
|
||||
if (!clonedEditor.getText().contains(expected)) {
|
||||
fail("Not found '" + expected +"' in \n" + clonedEditor.getText());
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(i, completions.size());
|
||||
}
|
||||
|
||||
private void assertClasspathCompletions(String... completedAnnotations) throws Exception {
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
|
||||
List<CompletionItem> filteredCompletions = completions.stream()
|
||||
.filter(item -> item.getTextEdit().getLeft().getNewText().contains("classpath"))
|
||||
.toList();
|
||||
|
||||
assertEquals(completedAnnotations.length, filteredCompletions.size());
|
||||
|
||||
for (int i = 0; i < completedAnnotations.length; i++) {
|
||||
CompletionItem completion = filteredCompletions.get(i);
|
||||
|
||||
Editor clonedEditor = editor.clone();
|
||||
clonedEditor.apply(completion);
|
||||
|
||||
String expected = completedAnnotations[i];
|
||||
if (!clonedEditor.getText().contains(expected)) {
|
||||
fail("Not found '" + expected +"' in \n" + clonedEditor.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user