diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java index 1044f41c1..aeb934047 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/CompositeCompletionEngine.java @@ -16,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.util.Assert; +import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -78,5 +79,19 @@ public class CompositeCompletionEngine implements ICompletionEngine { return new InternalCompletionList(completions.build(), isIncomplete); } }; + + @Override + public boolean keepCompletionsOrder(IDocument doc) { + Collection engines = subEngines.get(doc.getLanguageId()); + if (engines != null) { + for (ICompletionEngine e : engines) { + if (e.keepCompletionsOrder(doc)) { + return true; + } + } + } + return false; + } + } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java index 284395602..a310737b6 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/ICompletionEngine.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.commons.languageserver.completion; +import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -19,4 +20,6 @@ public interface ICompletionEngine { InternalCompletionList getCompletions(TextDocument document, int offset) throws Exception; + default boolean keepCompletionsOrder(IDocument doc) { return false; }; + } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java index 0156129b6..7fbdcc919 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/completion/VscodeCompletionEngineAdapter.java @@ -225,7 +225,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { boolean isIncomplete = rawCompletionList.isIncomplete(); List items = new ArrayList<>(completions.size()); - SortKeys sortkeys = new SortKeys(); + Optional sortkeysOpt = engine.keepCompletionsOrder(doc) ? Optional.of(new SortKeys()) : Optional.empty(); int count = 0; for (ICompletionProposal c : completions) { @@ -237,7 +237,7 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { break; } try { - items.add(adaptItem(doc, c, sortkeys)); + items.add(adaptItem(doc, c, sortkeysOpt)); } catch (Exception e) { log.error("error computing completion", e); } @@ -274,11 +274,11 @@ public class VscodeCompletionEngineAdapter implements VscodeCompletionEngine { return SimpleTextDocumentService.NO_COMPLETIONS; } - private CompletionItem adaptItem(TextDocument doc, ICompletionProposal completion, SortKeys sortkeys) throws Exception { + private CompletionItem adaptItem(TextDocument doc, ICompletionProposal completion, Optional sortkeysOpt) throws Exception { CompletionItem item = new CompletionItem(); item.setLabel(completion.getLabel()); item.setKind(completion.getKind()); - item.setSortText(sortkeys.next()); + sortkeysOpt.ifPresent(sortkeys -> item.setSortText(sortkeys.next())); item.setFilterText(completion.getFilterText()); item.setInsertTextMode(InsertTextMode.AsIs); item.setLabelDetails(completion.getLabelDetails()); diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java index 94d2f3fd5..501ac0733 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/DefaultCompletionFactory.java @@ -113,7 +113,7 @@ public class DefaultCompletionFactory implements CompletionFactory { @Override public CompletionItemKind getKind() { - return CompletionItemKind.Keyword; + return CompletionItemKind.Value; } @Override diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java index 8d43e58a7..f745726b7 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/completion/YamlCompletionEngine.java @@ -480,4 +480,10 @@ public class YamlCompletionEngine implements ICompletionEngine { throw new IllegalStateException("Missing case"); } } + + @Override + public boolean keepCompletionsOrder(IDocument doc) { + return true; + } + } diff --git a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java index cdacac99a..62c7436ec 100644 --- a/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java +++ b/headless-services/commons/language-server-test-harness/src/main/java/org/springframework/ide/vscode/languageserver/testharness/Editor.java @@ -585,21 +585,6 @@ public class Editor { public List getCompletions() throws Exception { CompletionList cl = harness.getCompletions(this.doc, this.getCursor()); ArrayList items = new ArrayList<>(cl.getItems()); - Collections.sort(items, new Comparator() { - - @Override - public int compare(CompletionItem o1, CompletionItem o2) { - return sortKey(o1).compareTo(sortKey(o2)); - } - - private String sortKey(CompletionItem item) { - String k = item.getSortText(); - if (k == null) { - k = item.getLabel(); - } - return k; - } - }); return items; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanCompletionProposal.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanCompletionProposal.java index 22b8024bf..b2393c863 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanCompletionProposal.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanCompletionProposal.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import org.apache.commons.text.similarity.JaroWinklerSimilarity; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.Block; @@ -36,7 +37,6 @@ 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; import org.springframework.ide.vscode.commons.util.BadLocationException; -import org.springframework.ide.vscode.commons.util.FuzzyMatcher; 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; @@ -76,7 +76,7 @@ public class BeanCompletionProposal implements ICompletionProposalWithScore { this.rewriteRefactorings = rewriteRefactorings; this.prefix = computePrefix(); this.edits = computeEdit(); - this.score = FuzzyMatcher.matchScore(prefix, beanId); + this.score = /*FuzzyMatcher.matchScore*/computeJaroWinklerScore(prefix, beanId); } @Override @@ -88,6 +88,10 @@ public class BeanCompletionProposal implements ICompletionProposalWithScore { public CompletionItemKind getKind() { return CompletionItemKind.Field; } + + private static double computeJaroWinklerScore(CharSequence pattern, CharSequence data) { + return pattern.isEmpty() ? 1 / (double) Integer.MAX_VALUE : new JaroWinklerSimilarity().apply(pattern, data); + } private String computePrefix() { String prefix = ""; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/DataRepositoryQueryStartCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/DataRepositoryQueryStartCompletionProvider.java index 6d071fe43..c2d3ae168 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/DataRepositoryQueryStartCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/DataRepositoryQueryStartCompletionProvider.java @@ -33,7 +33,7 @@ public class DataRepositoryQueryStartCompletionProvider implements DataRepositor for(QueryMethodSubject queryMethodSubject : QueryMethodSubject.QUERY_METHOD_SUBJECTS){ String toInsert = queryMethodSubject.key() + "By"; if(prefix == null || (toInsert.length() > localPrefix.length() && toInsert.startsWith(localPrefix)) || isOffsetAfterWhitespace(doc, offset)) { - completions.add(FindByCompletionProposal.createProposal(offset, CompletionItemKind.Text, prefix, toInsert, toInsert, true, null)); + completions.add(FindByCompletionProposal.createProposal(offset, CompletionItemKind.Method, prefix, toInsert, toInsert, true, null)); } } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/prefixsensitive/DataRepositoryPrefixSensitiveCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/prefixsensitive/DataRepositoryPrefixSensitiveCompletionProvider.java index 6742d58a7..972057964 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/prefixsensitive/DataRepositoryPrefixSensitiveCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/providers/prefixsensitive/DataRepositoryPrefixSensitiveCompletionProvider.java @@ -114,7 +114,7 @@ public class DataRepositoryPrefixSensitiveCompletionProvider implements DataRepo if (toReplace.startsWith(lastWord)) { DocumentEdits edits = new DocumentEdits(null, false); edits.replace(offset - lastWord.length(), offset, toReplace); - ICompletionProposal proposal = new FindByCompletionProposal(toReplace, CompletionItemKind.Text, edits, "property " + toReplace, null, null, lastWord, true); + ICompletionProposal proposal = new FindByCompletionProposal(toReplace, CompletionItemKind.Property, edits, "property " + toReplace, null, null, lastWord, true); completions.add(proposal); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java index fd2311e36..7606a1df3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java @@ -24,6 +24,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.Internal import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.languageserver.util.LanguageSpecific; import org.springframework.ide.vscode.commons.util.BadLocationException; +import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.LanguageId; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -79,4 +80,9 @@ public class SpringPropertiesCompletionEngine implements ICompletionEngine, Lang return ImmutableList.of(LanguageId.BOOT_PROPERTIES); } + @Override + public boolean keepCompletionsOrder(IDocument doc) { + return true; + } + } \ No newline at end of file diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/BeanCompletionProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/BeanCompletionProviderTest.java index e9e8749d9..b96130973 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/BeanCompletionProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/BeanCompletionProviderTest.java @@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.java.beans.test; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.File; import java.util.List; @@ -107,7 +108,7 @@ public class BeanCompletionProviderTest { @Test public void testBeanCompletion_firstCompletion() throws Exception { - assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService"}, 0, + assertCompletions(getCompletion("ownerRe<*>"), new String[] {"ownerRepository", "ownerService"}, 0, """ package org.sample.test; @@ -132,7 +133,7 @@ ownerRepository<*> @Test public void testBeanCompletion_secondCompletion() throws Exception { - assertCompletions(getCompletion("owner<*>"), new String[] {"ownerRepository", "ownerService"}, 1, + assertCompletions(getCompletion("ownerRe<*>"), new String[] {"ownerRepository", "ownerService"}, 1, """ package org.sample.test; @@ -229,7 +230,7 @@ petService<*> public class TestBeanCompletionSecondClass { public void test() { - owner<*> + ownerRe<*> } } """; @@ -379,7 +380,7 @@ public class TestBeanCompletionClass { public class Inner { public void test() { - owner<*> + ownerRe<*> } } } @@ -446,7 +447,7 @@ public class TestBeanCompletionClass { } public void test() { - owner<*> + ownerRe<*> } } @@ -500,7 +501,7 @@ public class TestBeanCompletionClass { @Controller public class TestBeanCompletionClass { public void test() { - this.owner<*> + this.ownerRe<*> } } """; @@ -618,7 +619,7 @@ public class TestBeanCompletionClass { @RestController public class TestBeanCompletionClass { public void test() { - owner<*> + ownerRe<*> } } """; @@ -656,7 +657,7 @@ public class TestBeanCompletionClass { @RestController public class TestBeanCompletionClass { public void test() { - owner<*> + ownerRe<*> System.out.println(); } } @@ -738,7 +739,7 @@ public class TestBeanCompletionClass { String ownerRepository; public TestBeanCompletionClass(String ownerRepository) { this.ownerRepository = ownerRepository; - ow<*> + ownerRe<*> } } """; @@ -775,7 +776,7 @@ public class TestBeanCompletionClass { public class TestBeanCompletionClass { String ownerRepository; public void test() { - ow<*> + ownerRe<*> } } """; @@ -814,7 +815,7 @@ public class TestBeanCompletionClass { @RestController public class TestBeanCompletionClass { public void test() { - this.ow<*> + this.ownerRe<*> System.out.println(); } } @@ -855,7 +856,7 @@ public class TestBeanCompletionClass { public class TestBeanCompletionClass { public TestBeanCompletionClass() { super(); - this.ow<*> + this.ownerRe<*> } } """; @@ -891,7 +892,7 @@ public class TestBeanCompletionClass { public class TestBeanCompletionClass { public TestBeanCompletionClass() { super(); - this.ow<*> + this.ownerRe<*> System.out.println(); } } @@ -929,7 +930,7 @@ public class TestBeanCompletionClass { public class TestBeanCompletionClass { public TestBeanCompletionClass() { super(); - ow<*> + ownerRe<*> } } """; @@ -965,7 +966,7 @@ public class TestBeanCompletionClass { public class TestBeanCompletionClass { public TestBeanCompletionClass() { super(); - ow<*> + ownerRe<*> System.out.println(); } } @@ -1177,24 +1178,22 @@ public class TestBeanCompletionClass { } private void assertCompletions(String completionLine, String[] expectedCompletions, int chosenCompletion, String expectedResult) throws Exception { - assertCompletions(completionLine, expectedCompletions.length, expectedCompletions, chosenCompletion, expectedResult); - } - - private void assertCompletions(String editorContent, int noOfExcpectedCompletions, String[] expectedCompletions, int chosenCompletion, String expectedResult) throws Exception { - Editor editor = harness.newEditor(LanguageId.JAVA, editorContent, tempJavaDocUri); + Editor editor = harness.newEditor(LanguageId.JAVA, completionLine, tempJavaDocUri); List completions = editor.getCompletions(); - assertEquals(noOfExcpectedCompletions, completions.size()); +// assertEquals(noOfExcpectedCompletions, completions.size()); + assertTrue(expectedCompletions.length <= completions.size()); if (expectedCompletions != null) { String[] completionItems = completions.stream() .map(item -> item.getLabel()) + .limit(expectedCompletions.length) .toArray(size -> new String[size]); assertArrayEquals(expectedCompletions, completionItems); } - if (noOfExcpectedCompletions > 0) { + if (expectedCompletions.length > 0) { editor.apply(completions.get(chosenCompletion)); assertEquals(expectedResult, editor.getText()); }