GH-758: improved verification of whether to show mapping method snippets or not at a certain position in the code
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.app;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -37,7 +36,6 @@ import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -52,10 +50,10 @@ public class BootJavaCompletionEngineConfigurer {
|
||||
// PT 160529904: Eclipse templates are duplicated, due to templates in Eclipse also being contributed by
|
||||
// STS3 bundle. Therefore do not include templates if client is Eclipse
|
||||
// TODO: REMOVE this check once STS3 is no longer supported
|
||||
if (LspClient.currentClient() != LspClient.Client.ECLIPSE) {
|
||||
// if (LspClient.currentClient() != LspClient.Client.ECLIPSE) {
|
||||
|
||||
JavaSnippetContext webControllerContext = new CompositeJavaSnippetContext(
|
||||
// JavaSnippetContext.AT_ROOT_LEVEL,
|
||||
JavaSnippetContext.AT_ROOT_LEVEL,
|
||||
new AnnotatedTypeDeclarationContext(Annotations.CONTROLLER));
|
||||
|
||||
snippetManager.add(
|
||||
@@ -92,7 +90,7 @@ public class BootJavaCompletionEngineConfigurer {
|
||||
+ "public ${SomeEnityData} ${putMethodName}(@PathVariable ${pvt:String} ${id}, @RequestBody ${SomeEnityData} ${entity}) {\n"
|
||||
+ " //TODO: process PUT request\n" + " ${cursor}\n" + " return ${entity};\n" + "}",
|
||||
"PutMapping"));
|
||||
}
|
||||
// }
|
||||
|
||||
return snippetManager;
|
||||
}
|
||||
@@ -126,7 +124,7 @@ public class BootJavaCompletionEngineConfigurer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(ASTNode node) {
|
||||
public boolean appliesTo(ASTNode node, int offset, CharSequence prefix) {
|
||||
TypeDeclaration type = ASTUtils.findDeclaringType(node);
|
||||
if (type != null) {
|
||||
ITypeBinding binding = type.resolveBinding();
|
||||
@@ -159,9 +157,9 @@ public class BootJavaCompletionEngineConfigurer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean appliesTo(ASTNode node) {
|
||||
public boolean appliesTo(ASTNode node, int offset, CharSequence prefix) {
|
||||
for (JavaSnippetContext context : contexts) {
|
||||
if (!context.appliesTo(node)) {
|
||||
if (!context.appliesTo(node, offset, prefix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,21 +43,14 @@ public class JavaSnippet {
|
||||
this.additionalTriggerPrefix = additionalTriggerPrefix;
|
||||
}
|
||||
|
||||
public Optional<ICompletionProposal> generateCompletion(Supplier<SnippetBuilder> snippetBuilderFactory,
|
||||
public ICompletionProposal generateCompletion(Supplier<SnippetBuilder> snippetBuilderFactory,
|
||||
DocumentRegion query, ASTNode node, CompilationUnit cu, String filterText) {
|
||||
|
||||
if (context.appliesTo(node)) {
|
||||
return Optional.of(
|
||||
new JavaSnippetCompletion(snippetBuilderFactory,
|
||||
query,
|
||||
cu,
|
||||
this,
|
||||
filterText
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
return new JavaSnippetCompletion(snippetBuilderFactory,
|
||||
query,
|
||||
cu,
|
||||
this,
|
||||
filterText);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -79,5 +72,9 @@ public class JavaSnippet {
|
||||
public String getAdditionalTriggerPrefix() {
|
||||
return additionalTriggerPrefix;
|
||||
}
|
||||
|
||||
public JavaSnippetContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,16 +11,20 @@
|
||||
package org.springframework.ide.vscode.boot.java.snippets;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
|
||||
public interface JavaSnippetContext {
|
||||
|
||||
JavaSnippetContext BOOT_MEMBERS = (node) -> node instanceof TypeDeclaration || node instanceof SimpleName;
|
||||
JavaSnippetContext BOOT_MEMBERS = (node, offset, prefix) -> node instanceof TypeDeclaration || node instanceof SimpleName;
|
||||
|
||||
JavaSnippetContext AT_ROOT_LEVEL = (node) -> {
|
||||
return (node instanceof TypeDeclaration) || (node instanceof SimpleName && node.getParent() != null && node.getParent() instanceof TypeDeclaration);
|
||||
JavaSnippetContext AT_ROOT_LEVEL = (node, offset, prefix) -> {
|
||||
if (node instanceof TypeDeclaration) return true;
|
||||
|
||||
ASTNode nodeBeforePrefix = NodeFinder.perform(node.getRoot(), offset - (prefix.length() + 1), 0);
|
||||
return nodeBeforePrefix != null && nodeBeforePrefix instanceof TypeDeclaration;
|
||||
};
|
||||
|
||||
boolean appliesTo(ASTNode node);
|
||||
boolean appliesTo(ASTNode node, int offset, CharSequence prefix);
|
||||
}
|
||||
|
||||
@@ -54,29 +54,27 @@ public class JavaSnippetManager {
|
||||
}
|
||||
|
||||
DocumentRegion query = PREFIX_FINDER.getPrefixRegion(doc, offset);
|
||||
boolean isEndOfDocument = offset == doc.getLength() - 1;
|
||||
|
||||
// check if the next character is a space or a new line
|
||||
if (!isEndOfDocument) {
|
||||
try {
|
||||
char nextCharacter = doc.getChar(offset + 1);
|
||||
if (!Character.isWhitespace(nextCharacter) && nextCharacter != '\n' && nextCharacter != '\r') {
|
||||
return;
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (JavaSnippet javaSnippet : snippets) {
|
||||
|
||||
|
||||
String filterText = null;
|
||||
|
||||
if (javaSnippet.getName().toLowerCase().startsWith(query.toString().toLowerCase())) {
|
||||
javaSnippet.generateCompletion(snippetBuilderFactory, query, node, cu, javaSnippet.getName())
|
||||
.ifPresent((completion) -> completions.add(completion));
|
||||
|
||||
} else if (javaSnippet.getAdditionalTriggerPrefix().toLowerCase().startsWith(query.toString().toLowerCase())) {
|
||||
javaSnippet.generateCompletion(snippetBuilderFactory, query, node, cu, javaSnippet.getAdditionalTriggerPrefix())
|
||||
.ifPresent((completion) -> completions.add(completion));
|
||||
filterText = javaSnippet.getName();
|
||||
}
|
||||
else if (javaSnippet.getAdditionalTriggerPrefix().toLowerCase().startsWith(query.toString().toLowerCase())) {
|
||||
filterText = javaSnippet.getAdditionalTriggerPrefix();
|
||||
}
|
||||
|
||||
if (filterText != null) {
|
||||
JavaSnippetContext context = javaSnippet.getContext();
|
||||
if (context.appliesTo(node, offset, query)) {
|
||||
ICompletionProposal proposal = javaSnippet.generateCompletion(snippetBuilderFactory, query, node, cu, filterText);
|
||||
completions.add(proposal);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.ide.vscode.languageserver.testharness.Editor;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@BootLanguageServerTest
|
||||
@@ -208,6 +209,26 @@ public class RequestMappingSnippetTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSnippetNotShowUpWithinMethodBody() throws Exception {
|
||||
prepareCase(CONTROLLER_WITH_RANDOM_CODE_CLASSNAME, "return new GetSomeService();", "get<*>\n return new GetSomeService();");
|
||||
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
for (CompletionItem completionItem : completions) {
|
||||
assertNotEquals("@GetMapping(..) {..}", completionItem.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSnippetNotShowUpWithinMethodParamDeclaration() throws Exception {
|
||||
prepareCase(CONTROLLER_WITH_RANDOM_CODE_CLASSNAME, "@RequestParam(value = \"name\"", "@Get<*> @RequestParam(value = \"name\"");
|
||||
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
for (CompletionItem completionItem : completions) {
|
||||
assertNotEquals("@GetMapping(..) {..}", completionItem.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareCase(String className, String prefix) throws Exception {
|
||||
prepareCase(className, "class " + className + " {", "class " + className + " {\n\n" + prefix);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user