GH-758: further improvements to where exactly to show up the snippets for mappings

This commit is contained in:
Martin Lippert
2023-11-27 12:28:05 +01:00
parent 58c804cf44
commit 9c32fc3001
6 changed files with 120 additions and 5 deletions

View File

@@ -55,7 +55,7 @@ public class BootJavaCompletionEngineConfigurer {
if (LspClient.currentClient() != LspClient.Client.ECLIPSE) {
JavaSnippetContext webControllerContext = new CompositeJavaSnippetContext(
JavaSnippetContext.AT_ROOT_LEVEL,
// JavaSnippetContext.AT_ROOT_LEVEL,
new AnnotatedTypeDeclarationContext(Annotations.CONTROLLER));
snippetManager.add(

View File

@@ -21,6 +21,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal;
import org.springframework.ide.vscode.commons.languageserver.util.PrefixFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SnippetBuilder;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
import org.springframework.ide.vscode.commons.util.text.IDocument;
@@ -43,7 +44,6 @@ public class JavaSnippetManager {
public void add(JavaSnippet javaSnippet) {
snippets.add(javaSnippet);
}
public void getCompletions(IDocument doc, int offset, ASTNode node, CompilationUnit cu,
@@ -54,6 +54,18 @@ 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) {

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.boot.java.requestmapping.test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import java.io.InputStream;
import java.util.List;
@@ -22,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Import;
import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest;
import org.springframework.ide.vscode.boot.bootiful.HoverTestConf;
@@ -38,6 +40,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
public class RequestMappingSnippetTests {
private static final String CONTROLLER_CLASSNAME = "SampleController";
private static final String CONTROLLER_WITH_EXISTING_CODE_CLASSNAME = "SampleControllerWithExistingCode";
private static final String CONTROLLER_WITH_RANDOM_CODE_CLASSNAME = "SampleControllerWithRandomCode";
private static final String NON_CONTROLLER_CLASSNAME = "SampleNonController";
@Autowired private BootLanguageServerHarness harness;
@@ -51,7 +55,7 @@ public class RequestMappingSnippetTests {
}
@Test
void testAnnotationMarkerOnkyPrefix() throws Exception {
void testAnnotationMarkerOnlyPrefix() throws Exception {
prepareCase(CONTROLLER_CLASSNAME, "@<*>");
List<CompletionItem> completions = editor.getCompletions();
@@ -73,6 +77,17 @@ public class RequestMappingSnippetTests {
assertEquals("@RequestMapping(..) {..}", completions.get(3).getFilterText());
}
@Test
void testAnnotationMarkerOnlyPrefixWithExistingCode() throws Exception {
prepareCase(CONTROLLER_WITH_EXISTING_CODE_CLASSNAME, "// <*>", "@G<*>");
List<CompletionItem> completions = editor.getCompletions();
assertEquals(1, completions.size());
assertEquals("@GetMapping(..) {..}", completions.get(0).getLabel());
assertEquals("@GetMapping(..) {..}", completions.get(0).getFilterText());
}
@Test
void testSimpleGetPrefix() throws Exception {
prepareCase(CONTROLLER_CLASSNAME, "Get<*>");
@@ -162,12 +177,46 @@ public class RequestMappingSnippetTests {
List<CompletionItem> completions = editor.getCompletions();
assertEquals(0, completions.size());
}
@Test
void testSnippetNotShowUpForPrefixInMethodName() throws Exception {
prepareCase(CONTROLLER_WITH_RANDOM_CODE_CLASSNAME, "getSomethingMethod", "get<*>SomethingMethod");
List<CompletionItem> completions = editor.getCompletions();
for (CompletionItem completionItem : completions) {
assertNotEquals("@GetMapping(..) {..}", completionItem.getLabel());
}
}
@Test
void testSnippetNotShowUpForPrefixInAnnotationPropertyValue() throws Exception {
prepareCase(CONTROLLER_WITH_RANDOM_CODE_CLASSNAME, "@Value(\"${getValueProperty}\")", "@Value(\"${get<*>ValueProperty}\")");
List<CompletionItem> completions = editor.getCompletions();
for (CompletionItem completionItem : completions) {
assertNotEquals("@GetMapping(..) {..}", completionItem.getLabel());
}
}
@Test
void testSnippetNotShowUpForPrefixInMethodReturnType() throws Exception {
prepareCase(CONTROLLER_WITH_RANDOM_CODE_CLASSNAME, "public GetSomeService getSomethingMethod", "public Get<*>SomeService getSomethingMethod");
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);
}
private void prepareCase(String className, String prefix) throws Exception {
private void prepareCase(String className, String replace, String replaceWith) throws Exception {
InputStream resource = this.getClass().getResourceAsStream("/test-projects/test-request-mapping-completions/src/main/java/example/" + className + ".java");
String content = IOUtils.toString(resource);
content = content.replace("class " + className + " {", "class " + className + " {\n\n" + prefix);
content = content.replace(replace, replaceWith);
editor = new Editor(harness, content, LanguageId.JAVA);
}

View File

@@ -0,0 +1,26 @@
package example;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleControllerWithExistingCode {
private static final String template = "Hello, %s!";
@GetMapping("/greeting1")
public String greeting1(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format(template, name);
}
// <*>
@GetMapping("/greeting2")
public String greeting2(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format(template, name);
}
}

View File

@@ -0,0 +1,24 @@
package example;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;
@RestController
public class SampleControllerWithRandomCode {
private static final String template = "Hello, %s!";
@Value("${getValueProperty}")
private String someValue;
@GetMapping("/greeting1")
public GetSomeService getSomethingMethod(@RequestParam(value = "name", defaultValue = "World") String name) {
return new GetSomeService();
}
}