Skip to content

Commit

Permalink
Introduce completion item collapse for method overloads
Browse files Browse the repository at this point in the history
Signed-off-by: Hope Hadfield <[email protected]>
  • Loading branch information
hopehadfield committed Feb 15, 2024
1 parent 975e1c3 commit 19d03b9
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ public void updateDescription(CompletionProposal proposal, CompletionItem item)
// change the proposal to required type proposal when the
// argument guessing is turned off and the proposal is a constructor.
if (JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getGuessMethodArgumentsMode() ==
CompletionGuessMethodArgumentsMode.OFF) {
CompletionGuessMethodArgumentsMode.OFF || JavaLanguageServerPlugin.getPreferencesManager().getPreferences().isCollapseCompletionItemsEnabled()) {
CompletionProposal requiredTypeProposal = CompletionProposalUtils.getRequiredTypeProposal(proposal);
if (requiredTypeProposal != null) {
proposal = requiredTypeProposal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ private String getTextEditText(CompletionProposal proposal, CompletionItem item,
if (!completionBuffer.isEmpty()) {
return completionBuffer.toString();
}

String defaultText = getDefaultTextEditText(item);
int start = proposal.getReplaceStart();
int end = proposal.getReplaceEnd();
Expand Down Expand Up @@ -627,7 +627,7 @@ private void appendGuessingCompletion(StringBuilder buffer, CompletionProposal p
}

CompletionGuessMethodArgumentsMode guessMethodArgumentsMode = JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getGuessMethodArgumentsMode();
if (guessMethodArgumentsMode == CompletionGuessMethodArgumentsMode.OFF) {
if (guessMethodArgumentsMode == CompletionGuessMethodArgumentsMode.OFF || JavaLanguageServerPlugin.getPreferencesManager().getPreferences().isCollapseCompletionItemsEnabled()) {
buffer.append(CURSOR_POSITION);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -57,6 +56,7 @@
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemDefaults;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.CompletionItemLabelDetails;
import org.eclipse.lsp4j.CompletionItemTag;
import org.eclipse.lsp4j.InsertReplaceRange;
import org.eclipse.lsp4j.InsertTextMode;
Expand All @@ -69,7 +69,7 @@ public final class CompletionProposalRequestor extends CompletionRequestor {

private List<CompletionProposal> proposals = new ArrayList<>();
// Cache to store all the types that has been collapsed, due to off mode of argument guessing.
private Set<String> collapsedTypes = new HashSet<>();
private Map<String, Integer> collapsedTypes = new HashMap<>();
private final ICompilationUnit unit;
private final String uri; // URI of this.unit, used in future "resolve" requests
private CompletionProposalDescriptionProvider descriptionProvider;
Expand Down Expand Up @@ -430,6 +430,19 @@ public CompletionItem toCompletionItem(CompletionProposal proposal, int index) {
} else if (labelDetailsEnabled && $.getKind() == CompletionItemKind.Constructor && $.getLabelDetails() != null && $.getLabelDetails().getDetail() != null) {
filterText = newText.concat($.getLabelDetails().getDetail());
}
if (proposal.getKind() == CompletionProposal.METHOD_REF
&& collapsedTypes.containsKey(String.valueOf(proposal.getName())) && collapsedTypes.get(String.valueOf(proposal.getName())) > 1) {
if (labelDetailsEnabled) {
CompletionItemLabelDetails newLabelDetails = new CompletionItemLabelDetails();
newLabelDetails.setDetail("(...)");
newLabelDetails.setDescription(collapsedTypes.get(String.valueOf(proposal.getName())).toString() + " overloads");
$.setLabelDetails(newLabelDetails);
$.setDetail(null);
} else {
$.setLabel(String.valueOf(proposal.getName()) + "(...)");
$.setDetail(collapsedTypes.get(String.valueOf(proposal.getName())).toString() + " overloads");
}
}
if (range != null && !filterText.isEmpty()) {
$.setFilterText(filterText);
} else if (range != null && newText != null) {
Expand Down Expand Up @@ -739,15 +752,21 @@ private boolean matchCase(CompletionProposal proposal) {
* Check if the current completion proposal needs to be collapsed.
*/
private boolean needToCollapse(CompletionProposal proposal) {
if (preferenceManager.getPreferences().getGuessMethodArgumentsMode() != CompletionGuessMethodArgumentsMode.OFF) {
return false;
}
if (preferenceManager.getPreferences().isCollapseCompletionItemsEnabled() || preferenceManager.getPreferences().getGuessMethodArgumentsMode() == CompletionGuessMethodArgumentsMode.OFF) {

CompletionProposal requiredProposal = CompletionProposalUtils.getRequiredTypeProposal(proposal);
if (requiredProposal == null) {
return false;
if (proposal.getKind() == CompletionProposal.METHOD_REF && preferenceManager.getPreferences().isCollapseCompletionItemsEnabled()) {
return collapsedTypes.merge(String.valueOf(proposal.getName()), 1, Integer::sum) > 1;
}

CompletionProposal requiredProposal = CompletionProposalUtils.getRequiredTypeProposal(proposal);

if (requiredProposal == null) {
return false;
}

return collapsedTypes.merge(String.valueOf(requiredProposal.getSignature()), 1, Integer::sum) > 1;
}

return !collapsedTypes.add(String.valueOf(requiredProposal.getSignature()));
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ public CompletionItem resolve(CompletionItem param, IProgressMonitor monitor) {
// resolving documentation
// 1. get the required type proposal when the argument guessing is
// turned off and the proposal is a constructor.
if (manager.getPreferences().getGuessMethodArgumentsMode() == CompletionGuessMethodArgumentsMode.OFF) {
if (manager.getPreferences().getGuessMethodArgumentsMode() == CompletionGuessMethodArgumentsMode.OFF ||
JavaLanguageServerPlugin.getPreferencesManager().getPreferences().isCollapseCompletionItemsEnabled()) {
CompletionProposal requiredTypeProposal = CompletionProposalUtils.getRequiredTypeProposal(proposal);
if (requiredTypeProposal != null) {
proposal = requiredTypeProposal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ public class Preferences {
*/
public static final String JAVA_COMPLETION_GUESS_METHOD_ARGUMENTS_KEY = "java.completion.guessMethodArguments";

public static final String JAVA_COMPLETION_COLLAPSE_KEY = "java.completion.collapseCompletionItems";

/**
* A named preference that defines how member elements are ordered by code
* actions.
Expand Down Expand Up @@ -621,6 +623,7 @@ public class Preferences {
private boolean foldingRangeEnabled;
private boolean selectionRangeEnabled;
private CompletionGuessMethodArgumentsMode guessMethodArguments;
private boolean collapseCompletionItems;

private boolean javaFormatComments;
private boolean hashCodeEqualsTemplateUseJava7Objects;
Expand Down Expand Up @@ -877,6 +880,7 @@ public Preferences() {
foldingRangeEnabled = true;
selectionRangeEnabled = true;
guessMethodArguments = CompletionGuessMethodArgumentsMode.INSERT_PARAMETER_NAMES;
collapseCompletionItems = false;
javaFormatComments = true;
hashCodeEqualsTemplateUseJava7Objects = false;
hashCodeEqualsTemplateUseInstanceof = false;
Expand Down Expand Up @@ -1080,6 +1084,9 @@ public static Preferences createFrom(Map<String, Object> configuration) {
CompletionGuessMethodArgumentsMode.INSERT_PARAMETER_NAMES));
}

boolean collapseCompletionItemsEnabled = getBoolean(configuration, JAVA_COMPLETION_COLLAPSE_KEY, false);
prefs.setCollapseCompletionItemsEnabled(collapseCompletionItemsEnabled);

boolean hashCodeEqualsTemplateUseJava7Objects = getBoolean(configuration, JAVA_CODEGENERATION_HASHCODEEQUALS_USEJAVA7OBJECTS, false);
prefs.setHashCodeEqualsTemplateUseJava7Objects(hashCodeEqualsTemplateUseJava7Objects);
boolean hashCodeEqualsTemplateUseInstanceof = getBoolean(configuration, JAVA_CODEGENERATION_HASHCODEEQUALS_USEINSTANCEOF, false);
Expand Down Expand Up @@ -1544,6 +1551,11 @@ public Preferences setGuessMethodArgumentsMode(CompletionGuessMethodArgumentsMod
return this;
}

public Preferences setCollapseCompletionItemsEnabled(boolean enabled) {
this.collapseCompletionItems = enabled;
return this;
}

public Preferences setJavaFormatEnabled(boolean enabled) {
this.javaFormatEnabled = enabled;
return this;
Expand Down Expand Up @@ -1864,6 +1876,10 @@ public CompletionGuessMethodArgumentsMode getGuessMethodArgumentsMode() {
return guessMethodArguments;
}

public boolean isCollapseCompletionItemsEnabled() {
return collapseCompletionItems;
}

public boolean isHashCodeEqualsTemplateUseJava7Objects() {
return hashCodeEqualsTemplateUseJava7Objects;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4087,6 +4087,53 @@ public void testCompletion_order() throws Exception {
assertTrue(list.getItems().get(2).getFilterText().startsWith("test(String x, int y, boolean z)"));
}

@Test
public void testCompletion_collapse() throws Exception {
when(preferenceManager.getClientPreferences().isCompletionItemLabelDetailsSupport()).thenReturn(true);
preferenceManager.getPreferences().setCollapseCompletionItemsEnabled(true);
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", String.join("\n",
//@formatter:off
"package org.sample",
"public class Test {",
" public void test(String x){}",
" public void test(String x, int y){}",
" public void test(String x, int y, boolean z){}",
" public static void main(String[] args) {",
" Test obj = new Test();",
" obj.test",
" }",
"}"));
//@formatter:on
CompletionList list = requestCompletions(unit, "obj.test");
assertFalse(list.getItems().isEmpty());
assertTrue(list.getItems().get(0).getLabelDetails().getDetail().startsWith("(...)"));
assertTrue(list.getItems().get(0).getLabelDetails().getDescription().startsWith("3 overloads"));
}

@Test
public void testCompletion_collapse_extends() throws Exception {
when(preferenceManager.getClientPreferences().isCompletionItemLabelDetailsSupport()).thenReturn(true);
preferenceManager.getPreferences().setCollapseCompletionItemsEnabled(true);
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java", String.join("\n",
//@formatter:off
"package org.sample",
"class Test extends TestSuper {",
" public void test(String x){}",
" public static void main(String[] args) {",
" Test obj = new Test();",
" obj.test",
" }",
"}",
"public class TestSuper {",
" public void test(String x, int y){}",
"}"));
//@formatter:on
CompletionList list = requestCompletions(unit, "obj.test");
assertFalse(list.getItems().isEmpty());
assertTrue(list.getItems().get(0).getLabelDetails().getDetail().startsWith("(...)"));
assertTrue(list.getItems().get(0).getLabelDetails().getDescription().startsWith("2 overloads"));
}

private CompletionList requestCompletions(ICompilationUnit unit, String completeBehind) throws JavaModelException {
return requestCompletions(unit, completeBehind, 0);
}
Expand Down

0 comments on commit 19d03b9

Please sign in to comment.