This is an automated email from the ASF dual-hosted git repository.
dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new b081810632 LSP: Using labelDetails in CompletionItems for better
rendering in VSCode.
new 46477fc680 Merge pull request #6904 from
dbalek/dbalek/lsp-completion-label-details
b081810632 is described below
commit b08181063216e71e93e299cca234a052f4721385
Author: Dusan Balek <[email protected]>
AuthorDate: Tue Jan 2 14:44:22 2024 +0100
LSP: Using labelDetails in CompletionItems for better rendering in VSCode.
---
enterprise/micronaut/nbproject/project.xml | 2 +-
.../MicronautDataCompletionCollector.java | 33 ++++----
...ronautExpressionLanguageCompletionTestBase.java | 6 ++
ide/api.lsp/apichanges.xml | 20 ++++-
ide/api.lsp/manifest.mf | 2 +-
.../src/org/netbeans/api/lsp/Completion.java | 34 +++++++-
.../netbeans/modules/lsp/CompletionAccessor.java | 2 +-
.../org/netbeans/spi/lsp/CompletionCollector.java | 36 +++++++-
java/java.editor/nbproject/project.xml | 2 +-
.../editor/java/JavaCompletionCollector.java | 95 ++++++++++++----------
java/java.lsp.server/nbproject/project.xml | 2 +-
.../server/protocol/TextDocumentServiceImpl.java | 7 ++
.../java/lsp/server/protocol/ServerTest.java | 42 +++++++---
13 files changed, 197 insertions(+), 86 deletions(-)
diff --git a/enterprise/micronaut/nbproject/project.xml
b/enterprise/micronaut/nbproject/project.xml
index 1b39c39dfa..4454124894 100644
--- a/enterprise/micronaut/nbproject/project.xml
+++ b/enterprise/micronaut/nbproject/project.xml
@@ -57,7 +57,7 @@
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>1.23</specification-version>
+ <specification-version>1.24</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
index 53067455be..c742913313 100644
---
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
+++
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautDataCompletionCollector.java
@@ -74,9 +74,9 @@ public class MicronautDataCompletionCollector implements
CompletionCollector {
ExecutableType type = (ExecutableType)
info.getTypes().asMemberOf((DeclaredType) delegateRepositoryType,
delegateMethod);
Iterator<? extends VariableElement> it =
delegateMethod.getParameters().iterator();
Iterator<? extends TypeMirror> tIt =
type.getParameterTypes().iterator();
- StringBuilder label = new StringBuilder();
+ StringBuilder labelDetail = new StringBuilder();
StringBuilder sortParams = new StringBuilder();
- label.append(methodName).append("(");
+ labelDetail.append("(");
sortParams.append('(');
int cnt = 0;
while(it.hasNext() && tIt.hasNext()) {
@@ -87,15 +87,15 @@ public class MicronautDataCompletionCollector implements
CompletionCollector {
cnt++;
String paramTypeName =
MicronautDataCompletionTask.getTypeName(info, tm, false,
delegateMethod.isVarArgs() && !tIt.hasNext()).toString();
String paramName =
it.next().getSimpleName().toString();
- label.append(paramTypeName).append('
').append(paramName);
+ labelDetail.append(paramTypeName).append('
').append(paramName);
sortParams.append(paramTypeName);
if (tIt.hasNext()) {
- label.append(", ");
+ labelDetail.append(", ");
sortParams.append(',');
}
}
sortParams.append(')');
- label.append(')');
+ labelDetail.append(')');
TypeMirror returnType = type.getReturnType();
if
("findAll".contentEquals(delegateMethod.getSimpleName()) &&
!delegateMethod.getParameters().isEmpty() && returnType.getKind() ==
TypeKind.DECLARED) {
TypeElement te = (TypeElement) ((DeclaredType)
returnType).asElement();
@@ -104,12 +104,13 @@ public class MicronautDataCompletionCollector implements
CompletionCollector {
returnType = (ExecutableType)
info.getTypes().asMemberOf((DeclaredType) returnType, getContentMethod.get());
}
}
- label.append(" :
").append(MicronautDataCompletionTask.getTypeName(info, returnType, false,
false));
FileObject fo = info.getFileObject();
ElementHandle<VariableElement> repositoryHandle =
ElementHandle.create(delegateRepository);
ElementHandle<ExecutableElement> methodHandle =
ElementHandle.create(delegateMethod);
- return CompletionCollector.newBuilder(String.format("%s -
generate", label.toString()))
+ return CompletionCollector.newBuilder(methodName)
.kind(Completion.Kind.Method)
+ .labelDetail(String.format("%s - generate",
labelDetail.toString()))
+
.labelDescription(MicronautDataCompletionTask.getTypeName(info, returnType,
false, false).toString())
.sortText(String.format("%04d%s#%02d%s", 1500,
methodName, cnt, sortParams.toString()))
.insertTextFormat(Completion.TextFormat.PlainText)
.textEdit(new TextEdit(offset, offset, ""))
@@ -203,11 +204,11 @@ public class MicronautDataCompletionCollector implements
CompletionCollector {
if (element.getKind() == ElementKind.METHOD) {
Iterator<? extends VariableElement> it =
((ExecutableElement)element).getParameters().iterator();
Iterator<? extends TypeMirror> tIt = ((ExecutableType)
element.asType()).getParameterTypes().iterator();
- StringBuilder label = new StringBuilder();
+ StringBuilder labelDetail = new StringBuilder();
StringBuilder insertText = new StringBuilder();
StringBuilder sortParams = new StringBuilder();
- label.append(simpleName).append("(");
- insertText.append(simpleName).append("(");
+ labelDetail.append('(');
+ insertText.append(simpleName).append('(');
sortParams.append('(');
int cnt = 0;
boolean asTemplate = false;
@@ -219,21 +220,23 @@ public class MicronautDataCompletionCollector implements
CompletionCollector {
cnt++;
String paramTypeName =
MicronautDataCompletionTask.getTypeName(info, tm, false,
((ExecutableElement)element).isVarArgs() && !tIt.hasNext()).toString();
String paramName =
it.next().getSimpleName().toString();
- label.append(paramTypeName).append('
').append(paramName);
+ labelDetail.append(paramTypeName).append('
').append(paramName);
sortParams.append(paramTypeName);
-
insertText.append("${").append(cnt).append(":").append(paramName).append("}");
+
insertText.append("${").append(cnt).append(':').append(paramName).append('}');
asTemplate = true;
if (tIt.hasNext()) {
- label.append(", ");
+ labelDetail.append(", ");
sortParams.append(',');
insertText.append(", ");
}
}
- label.append(") :
").append(MicronautDataCompletionTask.getTypeName(info,
((ExecutableElement)element).getReturnType(), false, false).toString());
+ labelDetail.append(')');
insertText.append(')');
sortParams.append(')');
- return CompletionCollector.newBuilder(label.toString())
+ return CompletionCollector.newBuilder(simpleName)
.kind(Completion.Kind.Method)
+ .labelDetail(labelDetail.toString())
+
.labelDescription(MicronautDataCompletionTask.getTypeName(info,
((ExecutableElement)element).getReturnType(), false, false).toString())
.sortText(String.format("%04d%s#%02d%s", 100,
simpleName, cnt, sortParams.toString()))
.insertText(insertText.toString())
.insertTextFormat(asTemplate ?
Completion.TextFormat.Snippet : Completion.TextFormat.PlainText)
diff --git
a/enterprise/micronaut/test/unit/src/org/netbeans/modules/micronaut/completion/MicronautExpressionLanguageCompletionTestBase.java
b/enterprise/micronaut/test/unit/src/org/netbeans/modules/micronaut/completion/MicronautExpressionLanguageCompletionTestBase.java
index 780f03c1b5..656965520b 100644
---
a/enterprise/micronaut/test/unit/src/org/netbeans/modules/micronaut/completion/MicronautExpressionLanguageCompletionTestBase.java
+++
b/enterprise/micronaut/test/unit/src/org/netbeans/modules/micronaut/completion/MicronautExpressionLanguageCompletionTestBase.java
@@ -88,6 +88,12 @@ public class MicronautExpressionLanguageCompletionTestBase
extends NbTestCase {
|| item.getLabel().equals("nbjavac") //ignoring
'nbjavac' package from nbjavac
|| item.getLabel().equals("oracle"))) { //ignoring
'oracle' package present in some JDK builds
out.write(item.getLabel());
+ if (item.getLabelDetail() != null) {
+ out.write(item.getLabelDetail());
+ }
+ if (item.getLabelDescription() != null) {
+ out.write(" : " + item.getLabelDescription());
+ }
out.write("\n");
}
}
diff --git a/ide/api.lsp/apichanges.xml b/ide/api.lsp/apichanges.xml
index ec98400315..d535b3a993 100644
--- a/ide/api.lsp/apichanges.xml
+++ b/ide/api.lsp/apichanges.xml
@@ -51,6 +51,22 @@
<!-- ACTUAL CHANGES BEGIN HERE: -->
<changes>
+ <change id="Completion_getLabelDetail">
+ <api name="LSP_API"/>
+ <summary>Added Completion.getLabelDetail() and
Completion.getLabelDescription() methods.</summary>
+ <version major="1" minor="24"/>
+ <date day="2" month="1" year="2024"/>
+ <author login="dbalek"/>
+ <compatibility binary="compatible" source="compatible" addition="yes"
deletion="no"/>
+ <description>
+ <a
href="@TOP@/org/netbeans/api/lsp/Completion.html#getLabelDetail--">Completion.getLabelDetail()</a>
+ to get an optional string describing function signatures or type
annotations.
+ <a
href="@TOP@/org/netbeans/api/lsp/Completion.html#getLabelDescription--">Completion.getLabelDescription()</a>
+ to get an optional string describing fully qualified names or file
path.
+ </description>
+ <class package="org.netbeans.api.lsp" name="Completion"/>
+ <class package="org.netbeans.spi.lsp" name="CompletionCollector"/>
+ </change>
<change id="CodeActionProvider">
<api name="LSP_API"/>
<summary>Added CodeActionProvider interface</summary>
@@ -108,13 +124,13 @@
</change>
<change id="Completion_getCommand">
<api name="LSP_API"/>
- <summary>Added URL to diagnostic code description</summary>
+ <summary>Added Completion.getCommand() to get an optional
command</summary>
<version major="1" minor="17"/>
<date day="23" month="5" year="2023"/>
<author login="dbalek"/>
<compatibility binary="compatible" source="compatible" addition="yes"
deletion="no"/>
<description>
- <a
href="@TOP@/org/netbeans/api/lsp/Completion.html#getCommand--">Completion.getCommand</a>
to get an optional command
+ <a
href="@TOP@/org/netbeans/api/lsp/Completion.html#getCommand--">Completion.getCommand()</a>
to get an optional command
that is executed after inserting the completion.
</description>
<class package="org.netbeans.api.lsp" name="Completion"/>
diff --git a/ide/api.lsp/manifest.mf b/ide/api.lsp/manifest.mf
index 2eaadac4f9..5ac5b8f333 100644
--- a/ide/api.lsp/manifest.mf
+++ b/ide/api.lsp/manifest.mf
@@ -1,5 +1,5 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.api.lsp/1
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/lsp/Bundle.properties
-OpenIDE-Module-Specification-Version: 1.23
+OpenIDE-Module-Specification-Version: 1.24
AutoUpdate-Show-In-Client: false
diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java
b/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java
index 072f9832a9..142ebf2239 100644
--- a/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java
@@ -43,15 +43,17 @@ public final class Completion {
static {
CompletionAccessor.setDefault(new CompletionAccessor() {
@Override
- public Completion createCompletion(String label, Kind kind,
List<Tag> tags, CompletableFuture<String> detail, CompletableFuture<String>
documentation,
+ public Completion createCompletion(String label, String
labelDetail, String description, Kind kind, List<Tag> tags,
CompletableFuture<String> detail, CompletableFuture<String> documentation,
boolean preselect, String sortText, String filterText,
String insertText, TextFormat insertTextFormat, TextEdit textEdit, Command
command,
CompletableFuture<List<TextEdit>> additionalTextEdits,
List<Character> commitCharacters) {
- return new Completion(label, kind, tags, detail,
documentation, preselect, sortText, filterText, insertText, insertTextFormat,
textEdit, command, additionalTextEdits, commitCharacters);
+ return new Completion(label, labelDetail, description, kind,
tags, detail, documentation, preselect, sortText, filterText, insertText,
insertTextFormat, textEdit, command, additionalTextEdits, commitCharacters);
}
});
}
private final String label;
+ private final String labelDetail;
+ private final String labelDescription;
private final Kind kind;
private final List<Tag> tags;
private final CompletableFuture<String> detail;
@@ -66,10 +68,12 @@ public final class Completion {
private final CompletableFuture<List<TextEdit>> additionalTextEdits;
private final List<Character> commitCharacters;
- private Completion(String label, Kind kind, List<Tag> tags,
CompletableFuture<String> detail, CompletableFuture<String> documentation,
+ private Completion(String label, String labelDetail, String
labelDescription, Kind kind, List<Tag> tags, CompletableFuture<String> detail,
CompletableFuture<String> documentation,
boolean preselect, String sortText, String filterText, String
insertText, TextFormat insertTextFormat,
TextEdit textEdit, Command command,
CompletableFuture<List<TextEdit>> additionalTextEdits, List<Character>
commitCharacters) {
this.label = label;
+ this.labelDetail = labelDetail;
+ this.labelDescription = labelDescription;
this.kind = kind;
this.tags = tags;
this.detail = detail;
@@ -96,6 +100,30 @@ public final class Completion {
return label;
}
+ /**
+ * An optional string which is rendered less prominently directly after
+ * {@link Completion#getLabel() label}, without any spacing. Should be
+ * used for function signatures or type annotations.
+ *
+ * @since 1.24
+ */
+ @CheckForNull
+ public String getLabelDetail() {
+ return labelDetail;
+ }
+
+ /**
+ * An optional string which is rendered less prominently after
+ * {@link Completion#getLabelDetail() label detail}. Should be used for
fully qualified
+ * names or file path.
+ *
+ * @since 1.24
+ */
+ @CheckForNull
+ public String getLabelDescription() {
+ return labelDescription;
+ }
+
/**
* The kind of this completion.
*
diff --git a/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java
b/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java
index 6a40e63554..e799f848e5 100644
--- a/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java
+++ b/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java
@@ -55,7 +55,7 @@ public abstract class CompletionAccessor {
DEFAULT = accessor;
}
- public abstract Completion createCompletion(String label, Completion.Kind
kind, List<Completion.Tag> tags, CompletableFuture<String> detail,
CompletableFuture<String> documentation,
+ public abstract Completion createCompletion(String label, String
labelDetail, String labelDescription, Completion.Kind kind,
List<Completion.Tag> tags, CompletableFuture<String> detail,
CompletableFuture<String> documentation,
boolean preselect, String sortText, String filterText, String
insertText, Completion.TextFormat insertTextFormat,
TextEdit textEdit, Command command,
CompletableFuture<List<TextEdit>> additionalTextEdits, List<Character>
commitCharacters);
}
diff --git a/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java
b/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java
index 34b964ce0e..79b497c324 100644
--- a/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java
+++ b/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java
@@ -90,6 +90,8 @@ public interface CompletionCollector {
public static final class Builder {
private String label;
+ private String labelDetail;
+ private String labelDescription;
private Completion.Kind kind;
private List<Completion.Tag> tags;
private CompletableFuture<String> detail;
@@ -120,6 +122,32 @@ public interface CompletionCollector {
return this;
}
+ /**
+ * An optional string which is rendered less prominently directly after
+ * {@link Completion#getLabel() label}, without any spacing. Should be
+ * used for function signatures or type annotations.
+ *
+ * @since 1.24
+ */
+ @NonNull
+ public Builder labelDetail(@NonNull String labelDetail) {
+ this.labelDetail = labelDetail;
+ return this;
+ }
+
+ /**
+ * An optional string which is rendered less prominently after
+ * {@link Completion#getLabelDetail() label detail}. Should be used
for fully qualified
+ * names or file path.
+ *
+ * @since 1.24
+ */
+ @NonNull
+ public Builder labelDescription(@NonNull String labelDescription) {
+ this.labelDescription = labelDescription;
+ return this;
+ }
+
/**
* The kind of this completion.
*
@@ -344,10 +372,10 @@ public interface CompletionCollector {
*/
@NonNull
public Completion build() {
- return CompletionAccessor.getDefault().createCompletion(label,
kind,
- tags, detail, documentation, preselect, sortText,
filterText,
- insertText, insertTextFormat, textEdit, command,
additionalTextEdits,
- commitCharacters);
+ return CompletionAccessor.getDefault().createCompletion(label,
labelDetail,
+ labelDescription, kind, tags, detail, documentation,
preselect, sortText,
+ filterText, insertText, insertTextFormat, textEdit,
command,
+ additionalTextEdits, commitCharacters);
}
private static class LazyCompletableFuture<T> extends
CompletableFuture<T> {
diff --git a/java/java.editor/nbproject/project.xml
b/java/java.editor/nbproject/project.xml
index 42b86a983b..0b5a6e5d58 100644
--- a/java/java.editor/nbproject/project.xml
+++ b/java/java.editor/nbproject/project.xml
@@ -58,7 +58,7 @@
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>1.20</specification-version>
+ <specification-version>1.24</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git
a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
index e3677c6a3b..8c0376cd22 100644
---
a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
+++
b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
@@ -416,13 +416,13 @@ public class JavaCompletionCollector implements
CompletionCollector {
int priority = elem.getKind() == ElementKind.ENUM_CONSTANT ||
elem.getKind() == ElementKind.FIELD ? smartType ? 300 : 1300 : smartType ? 200
: 1200;
StringBuilder label = new StringBuilder();
label.append(elem.getSimpleName());
- if (type != null) {
- label.append(" : ").append(Utilities.getTypeName(info, type,
false));
- }
CompletionCollector.Builder builder =
CompletionCollector.newBuilder(label.toString())
.kind(elementKind2CompletionItemKind(elem.getKind()))
.sortText(String.format("%04d%s", priority,
elem.getSimpleName().toString()))
.insertTextFormat(Completion.TextFormat.PlainText);
+ if (type != null) {
+ builder.labelDescription(Utilities.getTypeName(info, type,
false).toString());
+ }
TextEdit textEdit = null;
String filter = null;
if (castType != null) {
@@ -491,8 +491,10 @@ public class JavaCompletionCollector implements
CompletionCollector {
@Override
public Completion createOverrideMethodItem(CompilationInfo info,
ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean
implement) {
Completion item = createExecutableItem(info, elem, type,
substitutionOffset, null, false, false, false, false, false, -1, false);
- CompletionCollector.Builder builder =
CompletionCollector.newBuilder(String.format("%s - %s", item.getLabel(),
implement ? "implement" : "override"))
+ CompletionCollector.Builder builder =
CompletionCollector.newBuilder(item.getLabel())
.kind(elementKind2CompletionItemKind(elem.getKind()))
+ .labelDetail(String.format("%s - %s",
item.getLabelDetail(), implement ? "implement" : "override"))
+ .labelDescription(item.getLabelDescription())
.sortText(item.getSortText())
.insertTextFormat(Completion.TextFormat.PlainText)
.textEdit(new TextEdit(substitutionOffset,
substitutionOffset, EMPTY))
@@ -515,9 +517,9 @@ public class JavaCompletionCollector implements
CompletionCollector {
@Override
public Completion createGetterSetterMethodItem(CompilationInfo info,
VariableElement elem, TypeMirror type, int substitutionOffset, String name,
boolean setter) {
String typeName = Utilities.getTypeName(info, type,
false).toString();
- StringBuilder label = new StringBuilder();
+ StringBuilder labelDetail = new StringBuilder();
StringBuilder sortParams = new StringBuilder();
- label.append(name).append('(');
+ labelDetail.append('(');
sortParams.append('(');
if (setter) {
CodeStyle cs = null;
@@ -536,16 +538,13 @@ public class JavaCompletionCollector implements
CompletionCollector {
simpleName,
cs.getParameterNamePrefix(),
cs.getParameterNameSuffix());
- label.append(typeName).append(' ').append(paramName);
+ labelDetail.append(typeName).append(' ').append(paramName);
sortParams.append(typeName);
}
- label.append(')');
- if (!setter) {
- label.append(": ").append(typeName);
- }
- label.append(" - generate");
- return CompletionCollector.newBuilder(label.toString())
+ labelDetail.append(") - generate");
+ Builder builder = CompletionCollector.newBuilder(name)
.kind(Completion.Kind.Method)
+ .labelDetail(labelDetail.toString())
.insertTextFormat(Completion.TextFormat.PlainText)
.sortText(String.format("%04d%s#%02d%s", 1500, name,
setter ? 1 : 0, sortParams.toString()))
.textEdit(new TextEdit(substitutionOffset,
substitutionOffset, EMPTY))
@@ -564,13 +563,18 @@ public class JavaCompletionCollector implements
CompletionCollector {
wc.rewrite(tp.getLeaf(), decl);
}
}
- })).build();
+ }));
+ if (!setter) {
+ builder.labelDescription(typeName);
+ }
+ return builder.build();
}
@Override
public Completion createDefaultConstructorItem(TypeElement elem, int
substitutionOffset, boolean smartType) {
- Builder builder =
CompletionCollector.newBuilder(elem.getSimpleName().toString() + "()")
+ Builder builder =
CompletionCollector.newBuilder(elem.getSimpleName().toString())
.kind(Completion.Kind.Constructor)
+ .labelDetail("()")
.sortText(String.format("%04d%s#0", smartType ? 650 :
1650, elem.getSimpleName().toString()));
StringBuilder insertText = new StringBuilder();
if (substitutionOffset < offset) {
@@ -737,9 +741,9 @@ public class JavaCompletionCollector implements
CompletionCollector {
@Override
public Completion createInitializeAllConstructorItem(CompilationInfo
info, boolean isDefault, Iterable<? extends VariableElement> fields,
ExecutableElement superConstructor, TypeElement parent, int substitutionOffset)
{
String simpleName = parent.getSimpleName().toString();
- StringBuilder label = new StringBuilder();
+ StringBuilder labelDetail = new StringBuilder();
StringBuilder sortParams = new StringBuilder();
- label.append(simpleName).append('(');
+ labelDetail.append('(');
sortParams.append('(');
CodeStyle cs = null;
try {
@@ -753,7 +757,7 @@ public class JavaCompletionCollector implements
CompletionCollector {
if (!isDefault) {
for (VariableElement ve : fields) {
if (cnt > 0) {
- label.append(", ");
+ labelDetail.append(", ");
sortParams.append(",");
}
boolean isStatic =
ve.getModifiers().contains(Modifier.STATIC);
@@ -765,14 +769,14 @@ public class JavaCompletionCollector implements
CompletionCollector {
cs.getParameterNamePrefix(),
cs.getParameterNameSuffix());
String paramTypeName = Utilities.getTypeName(info,
ve.asType(), false).toString();
- label.append(paramTypeName).append(' ').append(sName);
+ labelDetail.append(paramTypeName).append('
').append(sName);
sortParams.append(paramTypeName);
cnt++;
}
if (superConstructor != null) {
for (VariableElement ve :
superConstructor.getParameters()) {
if (cnt > 0) {
- label.append(", ");
+ labelDetail.append(", ");
sortParams.append(",");
}
String sName =
CodeStyleUtils.removePrefixSuffix(ve.getSimpleName(),
cs.getParameterNamePrefix(), cs.getParameterNameSuffix());
@@ -781,16 +785,17 @@ public class JavaCompletionCollector implements
CompletionCollector {
cs.getParameterNamePrefix(),
cs.getParameterNameSuffix());
String paramTypeName = Utilities.getTypeName(info,
ve.asType(), false).toString();
- label.append(paramTypeName).append(' ').append(sName);
+ labelDetail.append(paramTypeName).append('
').append(sName);
sortParams.append(paramTypeName);
cnt++;
}
}
}
- label.append(") - generate");
+ labelDetail.append(") - generate");
sortParams.append(')');
- return CompletionCollector.newBuilder(label.toString())
+ return CompletionCollector.newBuilder(simpleName)
.kind(Completion.Kind.Constructor)
+ .labelDetail(labelDetail.toString())
.insertTextFormat(Completion.TextFormat.PlainText)
.sortText(String.format("%04d%s#%02d%s", 1400, simpleName,
cnt, sortParams.toString()))
.textEdit(new TextEdit(substitutionOffset,
substitutionOffset, EMPTY))
@@ -880,30 +885,31 @@ public class JavaCompletionCollector implements
CompletionCollector {
public Completion createRecordPatternItem(CompilationInfo info,
TypeElement elem, DeclaredType type, int substitutionOffset, ReferencesCount
referencesCount, boolean isDeprecated, boolean insideNew, boolean addTypeVars) {
String simpleName = elem.getSimpleName().toString();
Iterator<? extends RecordComponentElement> it =
elem.getRecordComponents().iterator();
- StringBuilder label = new StringBuilder(elem.getSimpleName());
- StringBuilder insertText = new StringBuilder(elem.getSimpleName());
+ StringBuilder labelDetail = new StringBuilder();
+ StringBuilder insertText = new StringBuilder(simpleName);
RecordComponentElement recordComponent;
int cnt = 1;
- label.append("(");
+ labelDetail.append("(");
insertText.append("(");
while (it.hasNext()) {
recordComponent = it.next();
CharSequence typeName = Utilities.getTypeName(info,
recordComponent.getAccessor().getReturnType(), false);
- label.append(typeName);
+ labelDetail.append(typeName);
insertText.append("${").append(cnt++).append(":").append(typeName).append("}");
- label.append(" ");
+ labelDetail.append(" ");
insertText.append(" ");
- label.append(recordComponent.getSimpleName());
+ labelDetail.append(recordComponent.getSimpleName());
insertText.append("${").append(cnt++).append(":").append(recordComponent.getSimpleName()).append("}");
if (it.hasNext()) {
- label.append(", ");
+ labelDetail.append(", ");
insertText.append(", ");
}
}
- label.append(")");
+ labelDetail.append(")");
insertText.append(")");
- return CompletionCollector.newBuilder(label.toString())
+ return CompletionCollector.newBuilder(simpleName)
.kind(Completion.Kind.Struct)
+ .labelDetail(labelDetail.toString())
.insertText(insertText.toString())
.insertTextFormat(Completion.TextFormat.Snippet)
.sortText(String.format("%04d%s#", 650, simpleName))
@@ -922,9 +928,6 @@ public class JavaCompletionCollector implements
CompletionCollector {
insertText.append(prefix);
}
label.append(elem.getSimpleName());
- if (pkgName.length() > 0) {
- label.append(" (").append(pkgName).append(')');
- }
boolean asTemplate = false;
boolean inImport = false;
int cnt = 1;
@@ -1003,6 +1006,9 @@ public class JavaCompletionCollector implements
CompletionCollector {
builder.insertTextFormat(Completion.TextFormat.Snippet)
.addCommitCharacter('.');
}
+ if (pkgName.length() > 0) {
+ builder.labelDescription(pkgName);
+ }
if (insideNew) {
builder.command(new Command("Invoke Completion",
"editor.action.triggerSuggest"));
}
@@ -1022,11 +1028,11 @@ public class JavaCompletionCollector implements
CompletionCollector {
String simpleName = name != null ? name : (elem.getKind() ==
ElementKind.METHOD ? elem :
elem.getEnclosingElement()).getSimpleName().toString();
Iterator<? extends VariableElement> it =
elem.getParameters().iterator();
Iterator<? extends TypeMirror> tIt =
type.getParameterTypes().iterator();
- StringBuilder label = new StringBuilder();
+ StringBuilder labelDetail = new StringBuilder();
StringBuilder insertText = new StringBuilder();
StringBuilder sortParams = new StringBuilder();
- label.append(simpleName).append("(");
insertText.append(simpleName);
+ labelDetail.append("(");
if (!inImport && !memberRef) {
insertText.append(CodeStyle.getDefault(doc).spaceBeforeMethodCallParen() ? " ("
: "(");
}
@@ -1042,7 +1048,7 @@ public class JavaCompletionCollector implements
CompletionCollector {
cnt++;
String paramTypeName = Utilities.getTypeName(info, tm, false,
elem.isVarArgs() && !tIt.hasNext()).toString();
String paramName = it.next().getSimpleName().toString();
- label.append(paramTypeName).append(' ').append(paramName);
+ labelDetail.append(paramTypeName).append('
').append(paramName);
sortParams.append(paramTypeName);
if (!inImport && !memberRef) {
VariableElement inst = instanceOf(tm, paramName);
@@ -1050,7 +1056,7 @@ public class JavaCompletionCollector implements
CompletionCollector {
asTemplate = true;
}
if (tIt.hasNext()) {
- label.append(", ");
+ labelDetail.append(", ");
sortParams.append(',');
if (!inImport && !memberRef) {
insertText.append(", ");
@@ -1058,11 +1064,8 @@ public class JavaCompletionCollector implements
CompletionCollector {
}
}
sortParams.append(')');
- label.append(')');
+ labelDetail.append(')');
TypeMirror retType = type.getReturnType();
- if (elem.getKind() == ElementKind.METHOD) {
- label.append(" : ").append(Utilities.getTypeName(info,
retType, false).toString());
- }
if (inImport) {
insertText.append(';');
} else if (!memberRef) {
@@ -1089,10 +1092,14 @@ public class JavaCompletionCollector implements
CompletionCollector {
}
}
int priority = elem.getKind() == ElementKind.METHOD ? smartType ?
500 : 1500 : smartType ? 650 : name != null ? 1550 : 1650;
- CompletionCollector.Builder builder =
CompletionCollector.newBuilder(label.toString())
+ CompletionCollector.Builder builder =
CompletionCollector.newBuilder(simpleName)
.kind(elementKind2CompletionItemKind(elem.getKind()))
+ .labelDetail(labelDetail.toString())
.insertTextFormat(asTemplate ?
Completion.TextFormat.Snippet : Completion.TextFormat.PlainText)
.sortText(String.format("%04d%s#%02d%s", priority,
simpleName, cnt, sortParams.toString()));
+ if (elem.getKind() == ElementKind.METHOD) {
+ builder.labelDescription(Utilities.getTypeName(info, retType,
false).toString());
+ }
TextEdit textEdit = null;
String filter = null;
if (castType != null) {
diff --git a/java/java.lsp.server/nbproject/project.xml
b/java/java.lsp.server/nbproject/project.xml
index 2994df98cf..3fb4b6839b 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -136,7 +136,7 @@
<compile-dependency/>
<run-dependency>
<release-version>1</release-version>
- <specification-version>1.23</specification-version>
+ <specification-version>1.24</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
index 4a101d81ce..75da7c24a6 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
@@ -94,6 +94,7 @@ import org.eclipse.lsp4j.CodeLensParams;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
+import org.eclipse.lsp4j.CompletionItemLabelDetails;
import org.eclipse.lsp4j.CompletionItemTag;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
@@ -372,6 +373,12 @@ public class TextDocumentServiceImpl implements
TextDocumentService, LanguageCli
prefs.put("classMemberInsertionPoint",
CodeStyle.InsertionPoint.CARET_LOCATION.name());
boolean isComplete = Completion.collect(doc, caret,
context, completion -> {
CompletionItem item = new
CompletionItem(completion.getLabel());
+ if (completion.getLabelDetail() != null ||
completion.getLabelDescription() != null) {
+ CompletionItemLabelDetails labelDetails = new
CompletionItemLabelDetails();
+
labelDetails.setDetail(completion.getLabelDetail());
+
labelDetails.setDescription(completion.getLabelDescription());
+ item.setLabelDetails(labelDetails);
+ }
if (completion.getKind() != null) {
item.setKind(CompletionItemKind.valueOf(completion.getKind().name()));
}
diff --git
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
index a1e6d53ab3..b741fcb493 100644
---
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
+++
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java
@@ -59,6 +59,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.stream.Collectors;
import javax.lang.model.element.ElementKind;
import javax.swing.Icon;
@@ -78,6 +79,7 @@ import org.eclipse.lsp4j.CodeActionParams;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
+import org.eclipse.lsp4j.CompletionItemLabelDetails;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.ConfigurationParams;
@@ -223,6 +225,20 @@ public class ServerTest extends NbTestCase {
private final Gson gson = new Gson();
private Socket client;
private Thread serverThread;
+ private Function<CompletionItem, String> completionItemToString = ci -> {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ci.getKind()).append(':').append(ci.getLabel());
+ if (ci.getLabelDetails() != null) {
+ CompletionItemLabelDetails labelDetails = ci.getLabelDetails();
+ if (labelDetails.getDetail() != null) {
+ sb.append(labelDetails.getDetail());
+ }
+ if (labelDetails.getDescription() != null) {
+ sb.append(" : ").append(labelDetails.getDescription());
+ }
+ }
+ return sb.toString();
+ };
public ServerTest(String name) {
super(name);
@@ -385,7 +401,7 @@ public class ServerTest extends NbTestCase {
int hashCodeStart = code.indexOf("hashCode");
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), new Position(0, hashCodeStart + 2))).get();
assertTrue(completion.isRight());
- List<String> actualItems =
completion.getRight().getItems().stream().map(ci -> ci.getKind() + ":" +
ci.getLabel()).collect(Collectors.toList());
+ List<String> actualItems =
completion.getRight().getItems().stream().map(completionItemToString).collect(Collectors.toList());
assertEquals(Arrays.asList("Method:hashCode() : int"), actualItems);
VersionedTextDocumentIdentifier id = new
VersionedTextDocumentIdentifier(1);
id.setUri(toURI(src));
@@ -393,14 +409,14 @@ public class ServerTest extends NbTestCase {
assertDiags(diags, "Error:0:38-0:41");//errors
assertDiags(diags, "Error:0:38-0:41");//hints
completion = server.getTextDocumentService().completion(new
CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(0,
hashCodeStart + 2))).get();
- actualItems = completion.getRight().getItems().stream().map(ci ->
ci.getKind() + ":" + ci.getLabel()).collect(Collectors.toList());
+ actualItems =
completion.getRight().getItems().stream().map(completionItemToString).collect(Collectors.toList());
if (jdk9Plus()) {
assertEquals(Arrays.asList("Method:equals(Object anObject) :
boolean", "Method:equalsIgnoreCase(String anotherString) : boolean"),
actualItems);
}
int testStart = code.indexOf("test") + "equ".length() -
"hashCode".length();
completion = server.getTextDocumentService().completion(new
CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(0,
testStart + 3))).get();
List<CompletionItem> actualCompletionItem =
completion.getRight().getItems();
- actualItems = actualCompletionItem.stream().map(ci -> ci.getKind() +
":" + ci.getLabel()).collect(Collectors.toList());
+ actualItems =
actualCompletionItem.stream().map(completionItemToString).collect(Collectors.toList());
assertEquals(Arrays.asList("Method:test() : void"), actualItems);
assertEquals(null, actualCompletionItem.get(0).getDocumentation());
CompletionItem resolvedItem =
server.getTextDocumentService().resolveCompletionItem(actualCompletionItem.get(0)).get();
@@ -414,7 +430,7 @@ public class ServerTest extends NbTestCase {
"\n",
resolvedItem.getDocumentation().getRight().getValue());
completion = server.getTextDocumentService().completion(new
CompletionParams(new TextDocumentIdentifier(toURI(src)), new Position(0,
0))).get();
- actualItems = completion.getRight().getItems().stream().map(ci ->
ci.getKind() + ":" + ci.getLabel()).collect(Collectors.toList());
+ actualItems =
completion.getRight().getItems().stream().map(completionItemToString).collect(Collectors.toList());
assertTrue(actualItems.contains("Keyword:interface"));
server.getTextDocumentService().didChange(new
DidChangeTextDocumentParams(id, Arrays.asList(new
TextDocumentContentChangeEvent(new Range(new Position(0, hashCodeStart), new
Position(0, hashCodeStart + "equ".length())), "equ".length(), "hashCode"))));
int closingBrace = code.lastIndexOf("}");
@@ -1516,11 +1532,11 @@ public class ServerTest extends NbTestCase {
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), new Position(2, 8 + "s.".length()))).get();
assertTrue(completion.isRight());
- Optional<CompletionItem> lengthItem =
completion.getRight().getItems().stream().filter(ci -> "length() :
int".equals(ci.getLabel())).findAny();
+ Optional<CompletionItem> lengthItem =
completion.getRight().getItems().stream().filter(ci ->
"length".equals(ci.getLabel())).findAny();
assertTrue("Expecting length field: " +
completion.getRight().getItems(), lengthItem.isPresent());
assertEquals(InsertTextFormat.PlainText,
lengthItem.get().getInsertTextFormat());
assertEquals("length()", lengthItem.get().getInsertText());
- Optional<CompletionItem> substringItem =
completion.getRight().getItems().stream().filter(ci ->
ci.getLabel().startsWith("substring(") &&
ci.getLabel().contains(",")).findAny();
+ Optional<CompletionItem> substringItem =
completion.getRight().getItems().stream().filter(ci ->
"substring".equals(ci.getLabel()) &&
ci.getLabelDetails().getDetail().contains(",")).findAny();
assertTrue(substringItem.isPresent());
assertEquals(InsertTextFormat.Snippet,
substringItem.get().getInsertTextFormat());
if ("1.8".equals(javaVersion)) {
@@ -1552,9 +1568,9 @@ public class ServerTest extends NbTestCase {
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), afterJavaLangAnnotation)).get();
assertTrue(completion.isRight());
completion.getRight().getItems().stream().forEach(ci ->
System.err.println(ci.getLabel()));
- Optional<CompletionItem> targetItem =
completion.getRight().getItems().stream().filter(ci -> "Target
(java.lang.annotation)".equals(ci.getLabel())).findAny();
+ Optional<CompletionItem> targetItem =
completion.getRight().getItems().stream().filter(ci ->
"Target".equals(ci.getLabel())).findAny();
assertTrue(targetItem.isPresent());
- assertEquals("Target (java.lang.annotation)",
targetItem.get().getLabel()); //TODO: insert text '('!
+ assertEquals("Target", targetItem.get().getLabel()); //TODO:
insert text '('!
assertEquals(CompletionItemKind.Interface,
targetItem.get().getKind());
}
@@ -1654,7 +1670,7 @@ public class ServerTest extends NbTestCase {
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), new Position(2, 8 +
"ArrayL".length()))).get();
assertTrue(completion.isRight());
- Optional<CompletionItem> arrayListItem =
completion.getRight().getItems().stream().filter(ci -> "ArrayList
(java.util)".equals(ci.getLabel())).findAny();
+ Optional<CompletionItem> arrayListItem =
completion.getRight().getItems().stream().filter(ci ->
"ArrayList".equals(ci.getLabel())).findAny();
assertTrue(arrayListItem.isPresent());
assertNull(arrayListItem.get().getAdditionalTextEdits());
CompletableFuture<CompletionItem> resolvedItem =
server.getTextDocumentService().resolveCompletionItem(arrayListItem.get());
@@ -1671,7 +1687,7 @@ public class ServerTest extends NbTestCase {
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), new Position(3, 8 +
"ArrayL".length()))).get();
assertTrue(completion.isRight());
- Optional<CompletionItem> arrayListItem =
completion.getRight().getItems().stream().filter(ci -> "ArrayList
(java.util)".equals(ci.getLabel())).findAny();
+ Optional<CompletionItem> arrayListItem =
completion.getRight().getItems().stream().filter(ci ->
"ArrayList".equals(ci.getLabel())).findAny();
assertTrue(arrayListItem.isPresent());
assertNull(arrayListItem.get().getAdditionalTextEdits());
CompletableFuture<CompletionItem> resolvedItem =
server.getTextDocumentService().resolveCompletionItem(arrayListItem.get());
@@ -5016,8 +5032,8 @@ public class ServerTest extends NbTestCase {
server.getTextDocumentService().didOpen(new
DidOpenTextDocumentParams(new TextDocumentItem(toURI(src), "java", 0, code)));
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), new Position(0, 15))).get();
assertTrue(completion.isRight());
- List<String> actualItems =
completion.getRight().getItems().stream().map(ci -> ci.getKind() + ":" +
ci.getLabel()).collect(Collectors.toList());
- assertEquals(Arrays.asList("Interface:SuppressWarnings (java.lang)"),
actualItems);
+ List<String> actualItems =
completion.getRight().getItems().stream().map(completionItemToString).collect(Collectors.toList());
+ assertEquals(Arrays.asList("Interface:SuppressWarnings : java.lang"),
actualItems);
VersionedTextDocumentIdentifier id = new
VersionedTextDocumentIdentifier(1);
id.setUri(toURI(src));
server.getTextDocumentService().didChange(new
DidChangeTextDocumentParams(id, Arrays.asList(new
TextDocumentContentChangeEvent(new Range(new Position(0, 1), new Position(0,
15)), 14, "SuppressWarnings(v"))));
@@ -5662,7 +5678,7 @@ public class ServerTest extends NbTestCase {
server.getTextDocumentService().didChange(new
DidChangeTextDocumentParams(id, Arrays.asList(new
TextDocumentContentChangeEvent(new Range(new Position(0, 11), new Position(0,
11)), 0, " :: $1 instanceof java.lang.String"))));
Either<List<CompletionItem>, CompletionList> completion =
server.getTextDocumentService().completion(new CompletionParams(new
TextDocumentIdentifier(toURI(src)), new Position(0, 5))).get();
assertTrue(completion.isRight());
- List<String> actualItems =
completion.getRight().getItems().stream().map(ci -> ci.getKind() + ":" +
ci.getLabel()).collect(Collectors.toList());
+ List<String> actualItems =
completion.getRight().getItems().stream().map(completionItemToString).collect(Collectors.toList());
assertEquals(Arrays.asList("Method:length() : int"), actualItems);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists