-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Improved completion sorting that takes into account the current word and prefix (strict then camel-hump) #705
base: main
Are you sure you want to change the base?
Changes from 11 commits
723f68f
373fc08
0aaba07
8ef74d0
43063be
c115402
8f2a3df
291fbad
63e6637
3316257
4edcca2
78feed2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
import com.intellij.openapi.editor.Editor; | ||
import com.intellij.openapi.progress.ProcessCanceledException; | ||
import com.intellij.openapi.progress.ProgressManager; | ||
import com.intellij.openapi.util.TextRange; | ||
import com.intellij.openapi.util.UserDataHolder; | ||
import com.intellij.openapi.vfs.VirtualFile; | ||
import com.intellij.psi.PsiFile; | ||
|
@@ -25,6 +26,7 @@ | |
import com.redhat.devtools.lsp4ij.LSPIJUtils; | ||
import com.redhat.devtools.lsp4ij.LanguageServerItem; | ||
import com.redhat.devtools.lsp4ij.client.ExecuteLSPFeatureStatus; | ||
import com.redhat.devtools.lsp4ij.client.features.LSPClientFeatures; | ||
import com.redhat.devtools.lsp4ij.client.features.LSPCompletionFeature; | ||
import com.redhat.devtools.lsp4ij.client.features.LSPCompletionProposal; | ||
import com.redhat.devtools.lsp4ij.client.indexing.ProjectIndexingManager; | ||
|
@@ -102,8 +104,6 @@ public void fillCompletionVariants(@NotNull CompletionParameters parameters, @No | |
} | ||
} | ||
|
||
private static final CompletionItemComparator completionProposalComparator = new CompletionItemComparator(); | ||
|
||
private void addCompletionItems(@NotNull CompletionParameters parameters, | ||
@NotNull CompletionPrefix completionPrefix, | ||
@NotNull Either<List<CompletionItem>, CompletionList> completion, | ||
|
@@ -119,12 +119,19 @@ private void addCompletionItems(@NotNull CompletionParameters parameters, | |
items.addAll(completionList.getItems()); | ||
} | ||
|
||
// Sort by item.sortText | ||
items.sort(completionProposalComparator); | ||
PsiFile originalFile = parameters.getOriginalFile(); | ||
LSPClientFeatures clientFeatures = languageServer.getClientFeatures(); | ||
|
||
// Sort the completions as appropriate based on client configuration | ||
boolean useContextAwareSorting = clientFeatures.getCompletionFeature().useContextAwareSorting(originalFile); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new features are now opt-in. When disabled (which is the default), the only difference vs. prior behavior should be properly respecting the language case-sensitivity config setting. |
||
PrefixMatcher prefixMatcher = useContextAwareSorting ? result.getPrefixMatcher() : null; | ||
String currentWord = useContextAwareSorting ? getCurrentWord(parameters) : null; | ||
boolean caseSensitive = clientFeatures.isCaseSensitive(originalFile); | ||
items.sort(new CompletionItemComparator(prefixMatcher, currentWord, caseSensitive)); | ||
int size = items.size(); | ||
|
||
Set<String> addedLookupStrings = new HashSet<>(); | ||
var completionFeature = languageServer.getClientFeatures().getCompletionFeature(); | ||
var completionFeature = clientFeatures.getCompletionFeature(); | ||
LSPCompletionFeature.LSPCompletionContext context = new LSPCompletionFeature.LSPCompletionContext(parameters, languageServer); | ||
// Items now sorted by priority, low index == high priority | ||
for (int i = 0; i < size; i++) { | ||
|
@@ -186,6 +193,23 @@ private void addCompletionItems(@NotNull CompletionParameters parameters, | |
} | ||
} | ||
|
||
@Nullable | ||
private static String getCurrentWord(@NotNull CompletionParameters parameters) { | ||
PsiFile originalFile = parameters.getOriginalFile(); | ||
VirtualFile virtualFile = originalFile.getVirtualFile(); | ||
Document document = virtualFile != null ? LSPIJUtils.getDocument(virtualFile) : null; | ||
if (document != null) { | ||
int offset = parameters.getOffset(); | ||
TextRange wordTextRange = LSPIJUtils.getWordRangeAt(document, originalFile, offset); | ||
if (wordTextRange != null) { | ||
CharSequence documentChars = document.getCharsSequence(); | ||
CharSequence wordChars = documentChars.subSequence(wordTextRange.getStartOffset(), wordTextRange.getEndOffset()); | ||
return wordChars.toString(); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
protected void updateWithItemDefaults(@NotNull CompletionItem item, | ||
@Nullable CompletionItemDefaults itemDefaults) { | ||
if (itemDefaults == null) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,17 @@ | |
*/ | ||
public class ClientConfigurationSettings { | ||
/** | ||
* Client-side code workspace symbol settings. | ||
* Client-side code completion settings. | ||
*/ | ||
public static class ClientConfigurationCompletionSettings { | ||
/** | ||
* Whether or not client-side context-aware completion sorting should be used. Defaults to false. | ||
*/ | ||
public boolean useContextAwareSorting = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The opt-in config option. |
||
} | ||
|
||
/** | ||
* Client-side workspace symbol settings. | ||
*/ | ||
public static class ClientConfigurationWorkspaceSymbolSettings { | ||
/** | ||
|
@@ -35,7 +45,12 @@ public static class ClientConfigurationWorkspaceSymbolSettings { | |
public boolean caseSensitive = false; | ||
|
||
/** | ||
* Client-side code workspace symbol settings | ||
* Client-side code completion settings | ||
*/ | ||
public @NotNull ClientConfigurationCompletionSettings completion = new ClientConfigurationCompletionSettings(); | ||
|
||
/** | ||
* Client-side workspace symbol settings | ||
*/ | ||
public @NotNull ClientConfigurationWorkspaceSymbolSettings workspaceSymbol = new ClientConfigurationWorkspaceSymbolSettings(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2024 Red Hat Inc. and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
* which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package com.redhat.devtools.lsp4ij.server.definition.launching; | ||
|
||
import com.intellij.psi.PsiFile; | ||
import com.redhat.devtools.lsp4ij.client.features.LSPCompletionFeature; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
/** | ||
* Adds client-side code completion configuration features. | ||
*/ | ||
public class UserDefinedCompletionFeature extends LSPCompletionFeature { | ||
|
||
@Override | ||
public boolean useContextAwareSorting(@NotNull PsiFile file) { | ||
UserDefinedLanguageServerDefinition serverDefinition = (UserDefinedLanguageServerDefinition) getClientFeatures().getServerDefinition(); | ||
ClientConfigurationSettings clientConfiguration = serverDefinition.getLanguageServerClientConfiguration(); | ||
return clientConfiguration != null ? clientConfiguration.completion.useContextAwareSorting : super.useContextAwareSorting(file); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,10 +16,11 @@ | |
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
public class CompletionItemComparatorTest { | ||
private final CompletionItemComparator comparator = new CompletionItemComparator(); | ||
private final CompletionItemComparator comparator = new CompletionItemComparator(null, null, false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add more test cases here to confirm proper behavior of the new context-aware features of this comparator. |
||
|
||
private final CompletionItem one = newItem("one", "1"); | ||
private final CompletionItem nil = newItem("", null); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All callers were passing non-null values and the
isResolveCompletionSupported()
expects a non-null argument, so I changed the nullability annotation to match reality.