From 5fd13719f21dd2d05ade94dae8c7f1c653eb52d6 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 17 Feb 2017 10:05:04 +0100 Subject: [PATCH] improved value content assist to work with member value pairs and refactored code to reduce code duplications --- .../completions/ValueCompletionProcessor.java | 124 +++++++++++------- .../completions/test/ValueCompletionTest.java | 51 +++++++ 2 files changed, 124 insertions(+), 51 deletions(-) diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java index e448f1dfc..f0bfa5194 100644 --- a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/completions/ValueCompletionProcessor.java @@ -17,11 +17,13 @@ import java.util.List; 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.SimpleName; import org.eclipse.jdt.core.dom.StringLiteral; import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; +import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.util.text.IDocument; @@ -56,61 +58,24 @@ public class ValueCompletionProcessor { } // case: @Value(prefix<*>) else if (node instanceof SimpleName && node.getParent() instanceof Annotation) { - String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition()); - - int startOffset = node.getStartPosition(); - int endOffset = node.getStartPosition() + node.getLength(); - - String proposalPrefix = "\""; - String proposalPostfix = "\""; - - List> matches = findMatches(prefix); - - for (Match match : matches) { - - DocumentEdits edits = new DocumentEdits(doc); - edits.replace(startOffset, endOffset, proposalPrefix + "${" + match.data.getId() + "}" + proposalPostfix); - - ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); - completions.add(proposal); - } + computeProposalsForSimpleName(node, 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); } // case: @Value("prefix<*>") else if (node instanceof StringLiteral && node.getParent() instanceof Annotation) { if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - - String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, offset - (node.getStartPosition() + 1)), offset - (node.getStartPosition() + 1)); - - int startOffset = offset - prefix.length(); - int endOffset = offset; - - - String prePrefix = doc.get(node.getStartPosition() + 1, offset - prefix.length() - node.getStartPosition() - 1); - - String preCompletion; - if (prePrefix.endsWith("${")) { - preCompletion = ""; - } - else if (prePrefix.endsWith("$")) { - preCompletion = "{"; - } - else { - preCompletion = "${"; - } - - String fullNodeContent = doc.get(node.getStartPosition(), node.getLength()); - String postCompletion = isClosingBracketMissing(fullNodeContent + preCompletion) ? "}" : ""; - - List> matches = findMatches(prefix); - - for (Match match : matches) { - - DocumentEdits edits = new DocumentEdits(doc); - edits.replace(startOffset, endOffset, preCompletion + match.data.getId() + postCompletion); - - ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); - completions.add(proposal); - } + computeProposalsForStringLiteral(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); } } } @@ -118,6 +83,63 @@ public class ValueCompletionProcessor { e.printStackTrace(); } } + + private void computeProposalsForSimpleName(ASTNode node, List completions, int offset, + IDocument doc) { + String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition()); + + int startOffset = node.getStartPosition(); + int endOffset = node.getStartPosition() + node.getLength(); + + String proposalPrefix = "\""; + String proposalPostfix = "\""; + + List> matches = findMatches(prefix); + + for (Match match : matches) { + + DocumentEdits edits = new DocumentEdits(doc); + edits.replace(startOffset, endOffset, proposalPrefix + "${" + match.data.getId() + "}" + proposalPostfix); + + ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); + completions.add(proposal); + } + } + + private void computeProposalsForStringLiteral(ASTNode node, List completions, int offset, + IDocument doc) throws BadLocationException { + String prefix = identifyPropertyPrefix(doc.get(node.getStartPosition() + 1, offset - (node.getStartPosition() + 1)), offset - (node.getStartPosition() + 1)); + + int startOffset = offset - prefix.length(); + int endOffset = offset; + + String prePrefix = doc.get(node.getStartPosition() + 1, offset - prefix.length() - node.getStartPosition() - 1); + + String preCompletion; + if (prePrefix.endsWith("${")) { + preCompletion = ""; + } + else if (prePrefix.endsWith("$")) { + preCompletion = "{"; + } + else { + preCompletion = "${"; + } + + String fullNodeContent = doc.get(node.getStartPosition(), node.getLength()); + String postCompletion = isClosingBracketMissing(fullNodeContent + preCompletion) ? "}" : ""; + + List> matches = findMatches(prefix); + + for (Match match : matches) { + + DocumentEdits edits = new DocumentEdits(doc); + edits.replace(startOffset, endOffset, preCompletion + match.data.getId() + postCompletion); + + ValuePropertyKeyProposal proposal = new ValuePropertyKeyProposal(edits, match.data.getId(), match.data.getName(), null); + completions.add(proposal); + } + } private boolean isClosingBracketMissing(String fullNodeContent) { int bracketOpens = 0; diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java index 637096e01..3a4e25eb2 100644 --- a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/completions/test/ValueCompletionTest.java @@ -95,6 +95,24 @@ public class ValueCompletionTest { "@Value(\"${spring.prop1}\"<*>)"); } + @Test + public void testEmptyBracketsCompletionWithParamName() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2}\"<*>)", + "@Value(value=\"${else.prop3}\"<*>)", + "@Value(value=\"${spring.prop1}\"<*>)"); + } + + @Test + public void testEmptyBracketsCompletionWithWrongParamName() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(another=<*>)"); + prepareDefaultIndexData(); + assertAnnotationCompletions(); + } + @Test public void testOnlyDollarNoQoutesCompletion() throws Exception { prepareCase("@Value(\"onField\")", "@Value($<*>)"); @@ -106,6 +124,17 @@ public class ValueCompletionTest { "@Value(\"${spring.prop1}\"<*>)"); } + @Test + public void testOnlyDollarNoQoutesWithParamCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=$<*>)"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2}\"<*>)", + "@Value(value=\"${else.prop3}\"<*>)", + "@Value(value=\"${spring.prop1}\"<*>)"); + } + @Test public void testOnlyDollarCompletion() throws Exception { prepareCase("@Value(\"onField\")", "@Value(\"$<*>\")"); @@ -117,6 +146,17 @@ public class ValueCompletionTest { "@Value(\"${spring.prop1}<*>\")"); } + @Test + public void testOnlyDollarWithParamCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=\"$<*>\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2}<*>\")", + "@Value(value=\"${else.prop3}<*>\")", + "@Value(value=\"${spring.prop1}<*>\")"); + } + @Test public void testDollarWithBracketsCompletion() throws Exception { prepareCase("@Value(\"onField\")", "@Value(\"${<*>}\")"); @@ -128,6 +168,17 @@ public class ValueCompletionTest { "@Value(\"${spring.prop1<*>}\")"); } + @Test + public void testDollarWithBracketsWithParamCompletion() throws Exception { + prepareCase("@Value(\"onField\")", "@Value(value=\"${<*>}\")"); + prepareDefaultIndexData(); + + assertAnnotationCompletions( + "@Value(value=\"${data.prop2<*>}\")", + "@Value(value=\"${else.prop3<*>}\")", + "@Value(value=\"${spring.prop1<*>}\")"); + } + @Test public void testEmptyStringLiteralCompletion() throws Exception { prepareCase("@Value(\"onField\")", "@Value(\"<*>\")");