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 68222f2649 LPS: SignatureHelp implemented.
new e71774364f Merge pull request #6476 from
dbalek/dbalek/lsp-signature-help
68222f2649 is described below
commit 68222f26491c6b9ea886f18605e4f9443b45fc34
Author: Dusan Balek <[email protected]>
AuthorDate: Thu Sep 21 16:01:46 2023 +0200
LPS: SignatureHelp implemented.
---
ide/api.lsp/apichanges.xml | 15 ++
ide/api.lsp/manifest.mf | 2 +-
.../org/netbeans/api/lsp/SignatureInformation.java | 248 +++++++++++++++++++++
.../modules/lsp/SignatureInformationAccessor.java | 57 +++++
.../spi/lsp/SignatureInformationCollector.java | 132 +++++++++++
.../netbeans/api/lsp/SignatureInformationTest.java | 128 +++++++++++
java/java.completion/nbproject/project.properties | 2 +-
.../modules/java/completion/JavaTooltipTask.java | 78 +++++--
java/java.editor/nbproject/project.xml | 4 +-
.../java/JavaSignatureInformationCollector.java | 66 ++++++
.../editor/java/MethodParamsTipPaintComponent.java | 7 +
.../modules/java/lsp/server/protocol/Server.java | 5 +
.../server/protocol/TextDocumentServiceImpl.java | 48 +++-
.../java/lsp/server/protocol/ServerTest.java | 64 +++++-
14 files changed, 826 insertions(+), 30 deletions(-)
diff --git a/ide/api.lsp/apichanges.xml b/ide/api.lsp/apichanges.xml
index b14de6dd7b..3cbeb75231 100644
--- a/ide/api.lsp/apichanges.xml
+++ b/ide/api.lsp/apichanges.xml
@@ -51,6 +51,21 @@
<!-- ACTUAL CHANGES BEGIN HERE: -->
<changes>
+ <change id="SignatureInformation">
+ <api name="LSP_API"/>
+ <summary>Added SignatureInformation and
SignatureInformationCollector</summary>
+ <version major="1" minor="20"/>
+ <date day="21" month="9" year="2023"/>
+ <author login="dbalek"/>
+ <compatibility binary="compatible" source="compatible" addition="yes"
deletion="no"/>
+ <description>
+ A <a
href="@TOP@/org/netbeans/api/lsp/SignatureInformation.html">SignatureInformation</a>
class
+ and <a
href="@TOP@/org/netbeans/api/lsp/SignatureInformationCollecto.html">SignatureInformationCollector</a>
interface
+ introduced that allows to compute and collect signature
information.
+ </description>
+ <class package="org.netbeans.api.lsp" name="SignatureInformation"/>
+ <class package="org.netbeans.spi.lsp"
name="SignatureInformationCollector"/>
+ </change>
<change id="LazyCodeAction">
<api name="LSP_API"/>
<summary>Added CodeAction with lazy edit computation</summary>
diff --git a/ide/api.lsp/manifest.mf b/ide/api.lsp/manifest.mf
index dccfadd348..3bfd176abc 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.19
+OpenIDE-Module-Specification-Version: 1.20
AutoUpdate-Show-In-Client: false
diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/SignatureInformation.java
b/ide/api.lsp/src/org/netbeans/api/lsp/SignatureInformation.java
new file mode 100644
index 0000000000..a5e384da01
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/SignatureInformation.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.lsp;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.lib.editor.util.swing.DocumentUtilities;
+import org.netbeans.modules.lsp.SignatureInformationAccessor;
+import org.netbeans.spi.lsp.SignatureInformationCollector;
+
+/**
+ * Represents the signature of something callable. A signature can have a
label,
+ * like a function-name, a doc-comment, and a set of parameters.
+ *
+ * @author Dusan Balek
+ * @since 1.20
+ */
+public final class SignatureInformation {
+
+ static {
+ SignatureInformationAccessor.setDefault(new
SignatureInformationAccessor() {
+ @Override
+ public SignatureInformation createSignatureInformation(String
label, List<ParameterInformation> params, boolean isActive, String
documentation) {
+ return new SignatureInformation(label, params, isActive,
documentation);
+ }
+
+ @Override
+ public ParameterInformation createParameterInformation(String
label, boolean isActive, String documentation) {
+ return new ParameterInformation(label, isActive,
documentation);
+ }
+ });
+ }
+
+ private final String label;
+ private final List<ParameterInformation> params;
+ private final boolean isActive;
+ private final String documentation;
+
+ private SignatureInformation(String label, List<ParameterInformation>
params, boolean isActive, String documentation) {
+ this.label = label;
+ this.params = params;
+ this.isActive = isActive;
+ this.documentation = documentation;
+ }
+
+ /**
+ * The label of this signature information.
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * The parameters of this signature.
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public List<ParameterInformation> getParameters() {
+ return Collections.unmodifiableList(params);
+ }
+
+ /**
+ * Returns true if the signature is active.
+ *
+ * @since 1.20
+ */
+ public boolean isActive() {
+ return isActive;
+ }
+
+ /**
+ * A human-readable string that represents a doc-comment. An HTML format is
+ * supported.
+ *
+ * @since 1.20
+ */
+ @CheckForNull
+ public String getDocumentation() {
+ return documentation;
+ }
+
+ /**
+ * Computes and collects signature information for a document at a given
offset. Example
+ * usage can be illustrated by:
+ * {@snippet file="org/netbeans/api/lsp/SignatureInformationTest.java"
region="testSignatureInformationCollect"}
+ *
+ * @param doc a text document
+ * @param offset an offset inside the text document
+ * @param context an optional signature help context
+ * @param consumer an operation accepting collected signature information
+ *
+ * @since 1.20
+ */
+ public static void collect(@NonNull Document doc, int offset, @NullAllowed
Context context, @NonNull Consumer<SignatureInformation> consumer) {
+ MimePath mimePath = MimePath.parse(DocumentUtilities.getMimeType(doc));
+ for (SignatureInformationCollector collector :
MimeLookup.getLookup(mimePath).lookupAll(SignatureInformationCollector.class)) {
+ collector.collectSignatureInformation(doc, offset, context,
consumer);
+ }
+ }
+
+ /**
+ * Represents a parameter of a callable-signature. A parameter can
+ * have a label and a doc-comment.
+ *
+ * @since 1.20
+ */
+ public static final class ParameterInformation {
+
+ private final String label;
+ private final boolean isActive;
+ private final String documentation;
+
+ private ParameterInformation(String label, boolean isActive, String
documentation) {
+ this.label = label;
+ this.isActive = isActive;
+ this.documentation = documentation;
+ }
+
+ /**
+ * The label of this parameter information.
+ * <p>
+ * <i>Note</i>: a label should be a substring of its containing
+ * signature label. Its intended use case is to highlight the parameter
+ * label part in the {@code SignatureInformation.label}.
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Returns true if the parameter is active.
+ *
+ * @since 1.20
+ */
+ public boolean isActive() {
+ return isActive;
+ }
+
+ /**
+ * A human-readable string that represents a doc-comment. An HTML
format is
+ * supported.
+ *
+ * @since 1.20
+ */
+ @CheckForNull
+ public String getDocumentation() {
+ return documentation;
+ }
+ }
+
+ /**
+ * Additional information about the context in which a signature help
request
+ * was triggered.
+ *
+ * @since 1.20
+ */
+ public static final class Context {
+
+ private final TriggerKind triggerKind;
+ private final Character triggerCharacter;
+
+ public Context(@NonNull TriggerKind triggerKind, @NullAllowed
Character triggerCharacter) {
+ this.triggerKind = triggerKind;
+ this.triggerCharacter = triggerCharacter;
+ }
+
+ /**
+ * Action that caused signature help to be triggered.
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public TriggerKind getTriggerKind() {
+ return triggerKind;
+ }
+
+ /**
+ * Character that caused signature help to be triggered.
+ * Is undefined if {@code triggerKind != TriggerKind.TriggerCharacter}.
+ *
+ * @since 1.20
+ */
+ @CheckForNull
+ public Character getTriggerCharacter() {
+ return triggerCharacter;
+ }
+ }
+
+ /**
+ * Specifies how a signature help was triggered.
+ *
+ * @since 1.20
+ */
+ public enum TriggerKind {
+
+ /**
+ * Signature help was invoked manually by the user or by a command.
+ *
+ * @since 1.20
+ */
+ Invoked,
+
+ /**
+ * Signature help was triggered by a trigger character.
+ *
+ * @since 1.20
+ */
+ TriggerCharacter,
+
+ /**
+ * Signature help was triggered by the cursor moving or by the document
+ * content changing.
+ *
+ * @since 1.20
+ */
+ ContentChange
+ }
+}
diff --git
a/ide/api.lsp/src/org/netbeans/modules/lsp/SignatureInformationAccessor.java
b/ide/api.lsp/src/org/netbeans/modules/lsp/SignatureInformationAccessor.java
new file mode 100644
index 0000000000..be0e9f87c9
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/modules/lsp/SignatureInformationAccessor.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.lsp;
+
+import java.util.List;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.lsp.SignatureInformation;
+import org.openide.util.Exceptions;
+import org.openide.util.Parameters;
+
+
+public abstract class SignatureInformationAccessor {
+
+ private static volatile SignatureInformationAccessor DEFAULT;
+
+ public static synchronized SignatureInformationAccessor getDefault() {
+ SignatureInformationAccessor instance = DEFAULT;
+ if (instance == null) {
+ Class<?> c = SignatureInformation.class;
+ try {
+ Class.forName(c.getName(), true, c.getClassLoader());
+ instance = DEFAULT;
+ assert instance != null;
+ } catch (Exception ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return instance;
+ }
+
+ public static void setDefault(@NonNull final SignatureInformationAccessor
accessor) {
+ Parameters.notNull("accessor", accessor); //NOI18N
+ if (DEFAULT != null) {
+ throw new IllegalStateException("Accessor already initialized");
+ }
+ DEFAULT = accessor;
+ }
+
+ public abstract SignatureInformation createSignatureInformation(String
label, List<SignatureInformation.ParameterInformation> params, boolean
isActive, String documentation);
+ public abstract SignatureInformation.ParameterInformation
createParameterInformation(String label, boolean isActive, String
documentation);
+}
diff --git
a/ide/api.lsp/src/org/netbeans/spi/lsp/SignatureInformationCollector.java
b/ide/api.lsp/src/org/netbeans/spi/lsp/SignatureInformationCollector.java
new file mode 100644
index 0000000000..3205202425
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/spi/lsp/SignatureInformationCollector.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.spi.lsp;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
+import org.netbeans.api.lsp.SignatureInformation;
+import org.netbeans.modules.lsp.SignatureInformationAccessor;
+import org.netbeans.spi.editor.mimelookup.MimeLocation;
+
+/**
+ * Interface for computing and collecting signature information. Clients can
use
+ * this interface to collect signature information and send them for
presentation
+ * outside of NetBeans using the Language Server Protocol. Implementations of
the
+ * interface should be registered in MimeLookup.
+ * {@snippet :
+ *
+ * {@code @}MimeRegistration(mimeType = "text/foo", service =
SignatureInformationCollector.class)
+ * public class FooSignatureInformationCollector implements
SignatureInformationCollector {
+ * ...
+ * }
+ * }
+ *
+ * @author Dusan Balek
+ * @since 1.20
+ */
+@MimeLocation(subfolderName = "SignatureHelpProviders")
+public interface SignatureInformationCollector {
+
+ /**
+ * Computes and collects signature information for a document at a given
offset.
+ *
+ * @param doc a text document
+ * @param offset an offset inside the text document
+ * @param context an optional signature help context
+ * @param consumer an operation accepting collected signature information
+ *
+ *
+ * @since 1.0
+ */
+ public void collectSignatureInformation(@NonNull Document doc, int offset,
@NullAllowed SignatureInformation.Context context, @NonNull
Consumer<SignatureInformation> consumer);
+
+ /**
+ * Creates a builder for {@link SignatureInformation} instances.
+ *
+ * @param label the label of the signature information
+ * @param isActive true if the signature is active
+ * @return newly created builder
+ *
+ * @since 1.20
+ */
+ public static Builder newBuilder(@NonNull String label, boolean isActive) {
+ return new Builder(label, isActive);
+ }
+
+ /**
+ * Builder for {@link SignatureInformation} instances. Its usage can be
illustrated by:
+ * {@snippet file="org/netbeans/api/lsp/SignatureInformationTest.java"
region="builder"}
+ *
+ * @since 1.20
+ */
+ public static final class Builder {
+
+ private final String label;
+ private final List<SignatureInformation.ParameterInformation> params;
+ private final boolean isActive;
+ private String documentation;
+
+ private Builder(@NonNull String label, boolean isActive) {
+ this.label = label;
+ this.isActive = isActive;
+ this.params = new ArrayList<>();
+ }
+
+ /**
+ * A human-readable string that represents a doc-comment. An HTML
format
+ * is supported.
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public Builder documentation(@NonNull String documentation) {
+ this.documentation = documentation;
+ return this;
+ }
+
+ /**
+ * Adds parameter information to this signature.
+ *
+ * @param label label of the parameter information
+ * @param isActive true if the the parameter is active
+ * @param documentation an optional doc-comment of the parameter
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public Builder addParameter(@NonNull String label, boolean isActive,
@NullAllowed String documentation) {
+
this.params.add(SignatureInformationAccessor.getDefault().createParameterInformation(label,
isActive, documentation));
+ return this;
+ }
+
+ /**
+ * Builds signature information.
+ *
+ * @since 1.20
+ */
+ @NonNull
+ public SignatureInformation build() {
+ return
SignatureInformationAccessor.getDefault().createSignatureInformation(label,
params, isActive, documentation);
+ }
+ }
+}
diff --git
a/ide/api.lsp/test/unit/src/org/netbeans/api/lsp/SignatureInformationTest.java
b/ide/api.lsp/test/unit/src/org/netbeans/api/lsp/SignatureInformationTest.java
new file mode 100644
index 0000000000..21ebf4fe4e
--- /dev/null
+++
b/ide/api.lsp/test/unit/src/org/netbeans/api/lsp/SignatureInformationTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.lsp;
+
+import java.util.List;
+import java.util.function.Consumer;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.spi.lsp.SignatureInformationCollector;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class SignatureInformationTest extends NbTestCase {
+
+ public SignatureInformationTest(String name) {
+ super(name);
+ }
+
+ @Override
+ public void setUp () throws Exception {
+ super.setUp();
+ clearWorkDir();
+ MockMimeLookup.setInstances (MimePath.get ("text/foo"), new
FooSignatureInformationCollector());
+ }
+
+ public void testSignatureInformationCollect() {
+ Document doc = createDocument("text/foo", "");
+ int offset = 0;
+ // @start region="testSignatureInformationCollect"
+
+ // Compute and collect signature information for a document at a given
offset
+ SignatureInformation.collect(doc, offset, null, signature -> {
+
+ // signature should never be 'null'
+ assertNotNull(signature);
+
+ // getting signature 'label'
+ String label = signature.getLabel();
+ assertEquals("label", label);
+
+ // check if the signature is active
+ assertTrue(signature.isActive());
+
+ // getting signature 'parameters'
+ List<SignatureInformation.ParameterInformation> params =
signature.getParameters();
+ // check number of parameters
+ assertEquals(2, params.size());
+ for (int i = 0; i < params.size(); i++) {
+ SignatureInformation.ParameterInformation param =
params.get(i);
+ // getting parameter 'label'
+ String paramLabel = param.getLabel();
+ assertEquals("param" + i, paramLabel);
+ // check if the parameter is active
+ if (i == 1) {
+ assertTrue(param.isActive());
+ } else {
+ assertFalse(param.isActive());
+ }
+ // getting optional parameter 'documentation'
+ String paramDocumentation = param.getDocumentation();
+ assertEquals("param" + i + " documentation",
paramDocumentation);
+ }
+
+ // getting optional signature 'documentation'
+ String documentation = signature.getDocumentation();
+ assertEquals("documentation", documentation);
+ });
+
+ // @end region="testSignatureInformationCollect"
+ }
+
+ private Document createDocument(String mimeType, String contents) {
+ Document doc = new DefaultStyledDocument();
+ doc.putProperty("mimeType", mimeType);
+ try {
+ doc.insertString(0, contents, null);
+ return doc;
+ } catch (BadLocationException ble) {
+ throw new IllegalStateException(ble);
+ }
+ }
+
+ private static class FooSignatureInformationCollector implements
SignatureInformationCollector {
+
+ @Override
+ public void collectSignatureInformation(Document doc, int offset,
SignatureInformation.Context context, Consumer<SignatureInformation> consumer) {
+ // @start region="builder"
+
+ // Create a builder for creating 'SignatureInformation' instance
providing its 'label' and 'isActive' flag
+ SignatureInformation si =
SignatureInformationCollector.newBuilder("label", true)
+
+ // add signature parameters
+ .addParameter("param0", false, "param0 documentation")
+ .addParameter("param1", true, "param1 documentation")
+
+ // set signature documentation
+ .documentation("documentation")
+
+ // create a new 'SignatureInformation' instance
+ .build();
+
+ // @end region="builder"
+ consumer.accept(si);
+ }
+ }
+}
diff --git a/java/java.completion/nbproject/project.properties
b/java/java.completion/nbproject/project.properties
index a59952644c..4540e613f7 100644
--- a/java/java.completion/nbproject/project.properties
+++ b/java/java.completion/nbproject/project.properties
@@ -17,7 +17,7 @@
is.autoload=true
javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
-spec.version.base=2.7.0
+spec.version.base=2.8.0
#test configs
test.config.jet-main.includes=\
diff --git
a/java/java.completion/src/org/netbeans/modules/java/completion/JavaTooltipTask.java
b/java/java.completion/src/org/netbeans/modules/java/completion/JavaTooltipTask.java
index 10149c3d09..0ee74aa066 100644
---
a/java/java.completion/src/org/netbeans/modules/java/completion/JavaTooltipTask.java
+++
b/java/java.completion/src/org/netbeans/modules/java/completion/JavaTooltipTask.java
@@ -21,7 +21,6 @@ package org.netbeans.modules.java.completion;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
@@ -42,7 +41,6 @@ import com.sun.source.util.Trees;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.java.source.*;
-import org.openide.util.NbBundle;
/**
*
@@ -60,7 +58,9 @@ public final class JavaTooltipTask extends BaseTask {
private int anchorOffset;
private List<List<String>> toolTipData;
+ private List<String> toolTipSignatures;
private int toolTipIndex;
+ private int activeSignatureIndex;
private int toolTipOffset;
private JavaTooltipTask(final int caretOffset, final Callable<Boolean>
cancel) {
@@ -71,10 +71,18 @@ public final class JavaTooltipTask extends BaseTask {
return toolTipData;
}
+ public List<String> getTooltipSignatures() {
+ return toolTipSignatures;
+ }
+
public int getTooltipIndex() {
return toolTipIndex;
}
+ public int getActiveSignatureIndex() {
+ return activeSignatureIndex;
+ }
+
public int getAnchorOffset() {
return anchorOffset;
}
@@ -85,7 +93,7 @@ public final class JavaTooltipTask extends BaseTask {
@Override
protected void resolve(CompilationController controller) throws
IOException {
- Env env = getCompletionEnvironment(controller, true);
+ Env env = getCompletionEnvironment(controller, false);
if (env == null) {
return;
}
@@ -102,18 +110,19 @@ public final class JavaTooltipTask extends BaseTask {
List<Tree> argTypes = getArgumentsUpToPos(env,
mi.getArguments(), (int) sourcePositions.getEndPosition(root,
mi.getMethodSelect()), startPos, false);
if (argTypes != null) {
controller.toPhase(JavaSource.Phase.RESOLVED);
+ final Trees trees = controller.getTrees();
TypeMirror[] types = new TypeMirror[argTypes.size()];
int j = 0;
for (Tree t : argTypes) {
- types[j++] = controller.getTrees().getTypeMirror(new
TreePath(path, t));
+ types[j++] = trees.getTypeMirror(new TreePath(path,
t));
}
- Tree mid = mi.getMethodSelect();
+ final Tree mid = mi.getMethodSelect();
+ final Element activeElement = trees.getElement(path);
path = new TreePath(path, mid);
switch (mid.getKind()) {
case MEMBER_SELECT: {
ExpressionTree exp = ((MemberSelectTree)
mid).getExpression();
path = new TreePath(path, exp);
- final Trees trees = controller.getTrees();
final TypeMirror type = trees.getTypeMirror(path);
final Element element = trees.getElement(path);
final boolean isStatic = element != null &&
(element.getKind().isClass() || element.getKind().isInterface() ||
element.getKind() == TYPE_PARAMETER);
@@ -127,13 +136,12 @@ public final class JavaTooltipTask extends BaseTask {
return (!isStatic ||
e.getModifiers().contains(STATIC) || e.getKind() == CONSTRUCTOR) &&
(t.getKind() != TypeKind.DECLARED || trees.isAccessible(scope, e,
(DeclaredType) (isSuperCall && enclType != null ? enclType : t)));
}
};
- toolTipData = getMatchingParams(controller, type,
controller.getElementUtilities().getMembers(type, acceptor),
((MemberSelectTree) mid).getIdentifier().toString(), types,
controller.getTypes());
+ handleMatchingParams(controller, type,
activeElement, controller.getElementUtilities().getMembers(type, acceptor),
((MemberSelectTree) mid).getIdentifier().toString(), types);
break;
}
case IDENTIFIER: {
final Scope scope = env.getScope();
final TreeUtilities tu =
controller.getTreeUtilities();
- final Trees trees = controller.getTrees();
final TypeElement enclClass =
scope.getEnclosingClass();
final boolean isStatic = enclClass != null ?
(tu.isStaticContext(scope) || (env.getPath().getLeaf().getKind() ==
Tree.Kind.BLOCK && ((BlockTree) env.getPath().getLeaf()).isStatic())) : false;
ElementUtilities.ElementAcceptor acceptor = new
ElementUtilities.ElementAcceptor() {
@@ -152,12 +160,12 @@ public final class JavaTooltipTask extends BaseTask {
String name = ((IdentifierTree)
mid).getName().toString();
if (SUPER_KEYWORD.equals(name) && enclClass !=
null) {
TypeMirror superclass =
enclClass.getSuperclass();
- toolTipData = getMatchingParams(controller,
superclass, controller.getElementUtilities().getMembers(superclass, acceptor),
INIT, types, controller.getTypes());
+ handleMatchingParams(controller, superclass,
activeElement, controller.getElementUtilities().getMembers(superclass,
acceptor), INIT, types);
} else if (THIS_KEYWORD.equals(name) && enclClass
!= null) {
TypeMirror thisclass = enclClass.asType();
- toolTipData = getMatchingParams(controller,
thisclass, controller.getElementUtilities().getMembers(thisclass, acceptor),
INIT, types, controller.getTypes());
+ handleMatchingParams(controller, thisclass,
activeElement, controller.getElementUtilities().getMembers(thisclass,
acceptor), INIT, types);
} else {
- toolTipData = getMatchingParams(controller,
enclClass != null ? enclClass.asType() : null,
controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), name,
types, controller.getTypes());
+ handleMatchingParams(controller, enclClass !=
null ? enclClass.asType() : null, activeElement,
controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), name,
types);
}
break;
}
@@ -183,13 +191,14 @@ public final class JavaTooltipTask extends BaseTask {
List<Tree> argTypes = getArgumentsUpToPos(env,
nc.getArguments(), pos, startPos, false);
if (argTypes != null) {
controller.toPhase(JavaSource.Phase.RESOLVED);
+ final Trees trees = controller.getTrees();
TypeMirror[] types = new TypeMirror[argTypes.size()];
int j = 0;
for (Tree t : argTypes) {
- types[j++] = controller.getTrees().getTypeMirror(new
TreePath(path, t));
+ types[j++] = trees.getTypeMirror(new TreePath(path,
t));
}
+ final Element activeElement = trees.getElement(path);
path = new TreePath(path, nc.getIdentifier());
- final Trees trees = controller.getTrees();
TypeMirror type = trees.getTypeMirror(path);
if (type != null && type.getKind() == TypeKind.ERROR &&
path.getLeaf().getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
path = new TreePath(path, ((ParameterizedTypeTree)
path.getLeaf()).getType());
@@ -204,7 +213,7 @@ public final class JavaTooltipTask extends BaseTask {
return e.getKind() == CONSTRUCTOR &&
(trees.isAccessible(scope, e, (DeclaredType) t) || isAnonymous &&
e.getModifiers().contains(PROTECTED));
}
};
- toolTipData = getMatchingParams(controller, type,
controller.getElementUtilities().getMembers(type, acceptor), INIT, types,
controller.getTypes());
+ handleMatchingParams(controller, type, activeElement,
controller.getElementUtilities().getMembers(type, acceptor), INIT, types);
toolTipIndex = types.length;
if (pos < 0) {
path = path.getParentPath();
@@ -226,9 +235,12 @@ public final class JavaTooltipTask extends BaseTask {
}
}
- private List<List<String>> getMatchingParams(CompilationInfo info,
TypeMirror type, Iterable<? extends Element> elements, String name,
TypeMirror[] argTypes, Types types) {
- List<List<String>> ret = new ArrayList<>();
+ private void handleMatchingParams(CompilationInfo info, TypeMirror type,
Element activeElement, Iterable<? extends Element> elements, String name,
TypeMirror[] argTypes) {
+ List<List<String>> data = new ArrayList<>();
+ List<String> signatures = new ArrayList<>();
+ Types types = info.getTypes();
TypeUtilities tu = info.getTypeUtilities();
+ activeSignatureIndex = 0;
for (Element e : elements) {
if ((e.getKind() == CONSTRUCTOR || e.getKind() == METHOD) &&
name.contentEquals(e.getSimpleName())) {
List<? extends VariableElement> params = ((ExecutableElement)
e).getParameters();
@@ -237,10 +249,19 @@ public final class JavaTooltipTask extends BaseTask {
if (!varArgs && (parSize < argTypes.length)) {
continue;
}
+ if (e == activeElement) {
+ activeSignatureIndex = signatures.size();
+ }
+ ExecutableType eType = (ExecutableType) asMemberOf(e, type,
types);
+ StringBuilder sig = new StringBuilder(INIT.equals(name) &&
type != null && type.getKind() == TypeKind.DECLARED ? ((DeclaredType)
type).asElement().getSimpleName() : name).append('(');
if (parSize == 0) {
-
ret.add(Collections.<String>singletonList(NbBundle.getMessage(JavaCompletionTask.class,
"JCP-no-parameters")));
+ data.add(new ArrayList<>());
+ sig.append(')');
+ if (e.getKind() == METHOD) {
+ sig.append(" :
").append(tu.getTypeName(eType.getReturnType()));
+ }
+ signatures.add(sig.toString());
} else {
- ExecutableType eType = (ExecutableType) asMemberOf(e,
type, types);
Iterator<? extends TypeMirror> parIt =
eType.getParameterTypes().iterator();
TypeMirror param = null;
for (int i = 0; i <= argTypes.length; i++) {
@@ -258,21 +279,29 @@ public final class JavaTooltipTask extends BaseTask {
for (Iterator<? extends VariableElement> it =
params.iterator(); it.hasNext();) {
VariableElement ve = it.next();
StringBuilder sb = new StringBuilder();
- sb.append(tu.getTypeName(tIt.next()));
+ CharSequence typeName =
tu.getTypeName(tIt.next());
+ sb.append(typeName);
+ sig.append(typeName);
if (varArgs && !tIt.hasNext()) {
sb.delete(sb.length() - 2,
sb.length()).append("..."); //NOI18N
+ sig.delete(sig.length() - 2,
sig.length()).append("..."); //NOI18N
}
CharSequence veName = ve.getSimpleName();
if (veName != null && veName.length() > 0) {
- sb.append(" "); // NOI18N
- sb.append(veName);
+ sb.append(" ").append(veName); // NOI18N
+ sig.append(" ").append(veName); // NOI18N
}
if (it.hasNext()) {
- sb.append(", "); // NOI18N
+ sig.append(", "); // NOI18N
}
paramStrings.add(sb.toString());
}
- ret.add(paramStrings);
+ data.add(paramStrings);
+ sig.append(')');
+ if (e.getKind() == METHOD) {
+ sig.append(" :
").append(tu.getTypeName(eType.getReturnType()));
+ }
+ signatures.add(sig.toString());
break;
}
if (argTypes[i] == null || argTypes[i].getKind() !=
TypeKind.ERROR && !isAssignable(types, argTypes[i], param)) {
@@ -282,7 +311,8 @@ public final class JavaTooltipTask extends BaseTask {
}
}
}
- return ret.isEmpty() ? null : ret;
+ toolTipData = data.isEmpty() ? null : data;
+ toolTipSignatures = signatures.isEmpty() ? null : signatures;
}
private static boolean isAssignable(Types types, TypeMirror arg,
TypeMirror parameter) {
diff --git a/java/java.editor/nbproject/project.xml
b/java/java.editor/nbproject/project.xml
index 132d3c9ffe..e3b37e4895 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.17</specification-version>
+ <specification-version>1.20</specification-version>
</run-dependency>
</dependency>
<dependency>
@@ -207,7 +207,7 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
- <specification-version>1.8</specification-version>
+ <specification-version>2.8</specification-version>
</run-dependency>
</dependency>
<dependency>
diff --git
a/java/java.editor/src/org/netbeans/modules/editor/java/JavaSignatureInformationCollector.java
b/java/java.editor/src/org/netbeans/modules/editor/java/JavaSignatureInformationCollector.java
new file mode 100644
index 0000000000..943b14f0eb
--- /dev/null
+++
b/java/java.editor/src/org/netbeans/modules/editor/java/JavaSignatureInformationCollector.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.editor.java;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.lsp.SignatureInformation;
+import org.netbeans.modules.java.completion.JavaTooltipTask;
+import org.netbeans.modules.parsing.api.ParserManager;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.spi.ParseException;
+import org.netbeans.spi.lsp.SignatureInformationCollector;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-java", service =
SignatureInformationCollector.class)
+public final class JavaSignatureInformationCollector implements
SignatureInformationCollector {
+
+ @Override
+ public void collectSignatureInformation(Document doc, int offset,
SignatureInformation.Context context, Consumer<SignatureInformation> consumer) {
+ if (context == null || context.getTriggerKind() !=
SignatureInformation.TriggerKind.TriggerCharacter ||
context.getTriggerCharacter() == '(') {
+ try {
+ JavaTooltipTask task = JavaTooltipTask.create(offset, () ->
false);
+
ParserManager.parse(Collections.singletonList(Source.create(doc)), task);
+ if (task.getTooltipData() != null &&
task.getTooltipSignatures() != null) {
+ Iterator<List<String>> it =
task.getTooltipData().iterator();
+ for (int i = 0; i < task.getTooltipSignatures().size() &&
it.hasNext(); i++) {
+ List<String> params = it.next();
+ String signature = task.getTooltipSignatures().get(i);
+ Builder builder =
SignatureInformationCollector.newBuilder(signature, i ==
task.getActiveSignatureIndex());
+ for (int j = 0; j < params.size(); j++) {
+ String param = params.get(j);
+ builder.addParameter(param, j ==
task.getTooltipIndex(), null);
+ }
+ consumer.accept(builder.build());
+ }
+ }
+ } catch (ParseException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ }
+}
diff --git
a/java/java.editor/src/org/netbeans/modules/editor/java/MethodParamsTipPaintComponent.java
b/java/java.editor/src/org/netbeans/modules/editor/java/MethodParamsTipPaintComponent.java
index 565375de5d..2db9c3338c 100644
---
a/java/java.editor/src/org/netbeans/modules/editor/java/MethodParamsTipPaintComponent.java
+++
b/java/java.editor/src/org/netbeans/modules/editor/java/MethodParamsTipPaintComponent.java
@@ -24,6 +24,7 @@ import java.util.List;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import org.openide.awt.GraphicsUtils;
+import org.openide.util.NbBundle;
/**
*
@@ -91,8 +92,14 @@ public class MethodParamsTipPaintComponent extends JToolTip {
if (params != null) {
for (List<String> p : params) {
int i = 0;
+ if (p.isEmpty()) {
+
p.add(NbBundle.getMessage(MethodParamsTipPaintComponent.class,
"JCP-no-parameters"));
+ }
int plen = p.size() - 1;
for (String s : p) {
+ if (i < plen) {
+ s += ", "; //NOI18N
+ }
if (getWidth(s, i == idx || i == plen && idx > plen ?
getDrawFont().deriveFont(Font.BOLD) : getDrawFont()) + drawX > screenWidth) {
drawY += fontHeight;
drawX = startX + getWidth(" ", drawFont);
//NOI18N
diff --git
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
index ba01d4f530..f846fdb952 100644
---
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
+++
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java
@@ -71,6 +71,7 @@ import org.eclipse.lsp4j.SemanticTokensParams;
import org.eclipse.lsp4j.ServerCapabilities;
import org.eclipse.lsp4j.SetTraceParams;
import org.eclipse.lsp4j.ShowMessageRequestParams;
+import org.eclipse.lsp4j.SignatureHelpOptions;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.TextDocumentSyncKind;
import org.eclipse.lsp4j.TextDocumentSyncOptions;
@@ -783,6 +784,10 @@ public final class Server {
completionOptions.setResolveProvider(true);
completionOptions.setTriggerCharacters(Arrays.asList(".", "#",
"@", "*"));
capabilities.setCompletionProvider(completionOptions);
+ SignatureHelpOptions signatureHelpOptions = new
SignatureHelpOptions();
+ signatureHelpOptions.setTriggerCharacters(Arrays.asList("("));
+
signatureHelpOptions.setRetriggerCharacters(Arrays.asList(","));
+ capabilities.setSignatureHelpProvider(signatureHelpOptions);
capabilities.setHoverProvider(true);
CodeActionOptions codeActionOptions = new
CodeActionOptions(Arrays.asList(CodeActionKind.QuickFix, CodeActionKind.Source,
CodeActionKind.SourceOrganizeImports, CodeActionKind.Refactor));
codeActionOptions.setResolveProvider(true);
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 7401da39a2..b6c4a4b9f2 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
@@ -126,6 +126,7 @@ import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.MarkupContent;
import org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
+import org.eclipse.lsp4j.ParameterInformation;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.PrepareRenameParams;
import org.eclipse.lsp4j.PrepareRenameResult;
@@ -144,6 +145,7 @@ import
org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
import org.eclipse.lsp4j.ServerCapabilities;
import org.eclipse.lsp4j.SignatureHelp;
import org.eclipse.lsp4j.SignatureHelpParams;
+import org.eclipse.lsp4j.SignatureInformation;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
import org.eclipse.lsp4j.TextDocumentEdit;
@@ -580,7 +582,51 @@ public class TextDocumentServiceImpl implements
TextDocumentService, LanguageCli
@Override
public CompletableFuture<SignatureHelp> signatureHelp(SignatureHelpParams
params) {
- throw new UnsupportedOperationException("Not supported yet.");
+ // shortcut: if the projects are not yet initialized, return empty:
+ if (server.openedProjects().getNow(null) == null) {
+ return CompletableFuture.completedFuture(null);
+ }
+ String uri = params.getTextDocument().getUri();
+ FileObject file = fromURI(uri);
+ Document rawDoc = server.getOpenedDocuments().getDocument(uri);
+ if (file == null || !(rawDoc instanceof StyledDocument)) {
+ return CompletableFuture.completedFuture(null);
+ }
+ StyledDocument doc = (StyledDocument) rawDoc;
+ List<SignatureInformation> signatures = new ArrayList<>();
+ AtomicInteger activeSignature = new AtomicInteger(-1);
+ AtomicInteger activeParameter = new AtomicInteger(-1);
+ org.netbeans.api.lsp.SignatureInformation.collect(doc,
Utils.getOffset(doc, params.getPosition()), null, signature -> {
+ SignatureInformation signatureInformation = new
SignatureInformation(signature.getLabel());
+ List<ParameterInformation> parameters = new
ArrayList<>(signature.getParameters().size());
+ for (int i = 0; i < signature.getParameters().size(); i++) {
+ org.netbeans.api.lsp.SignatureInformation.ParameterInformation
parameter = signature.getParameters().get(i);
+ ParameterInformation parameterInformation = new
ParameterInformation(parameter.getLabel());
+ if (parameter.getDocumentation() != null) {
+ MarkupContent markup = new MarkupContent();
+ markup.setKind("markdown");
+ markup.setValue(html2MD(parameter.getDocumentation()));
+ parameterInformation.setDocumentation(markup);
+ }
+ parameters.add(parameterInformation);
+ if (signatureInformation.getActiveParameter() == null &&
parameter.isActive()) {
+ signatureInformation.setActiveParameter(i);
+ }
+ }
+ if (signature.getDocumentation() != null) {
+ MarkupContent markup = new MarkupContent();
+ markup.setKind("markdown");
+ markup.setValue(html2MD(signature.getDocumentation()));
+ signatureInformation.setDocumentation(markup);
+ }
+ signatureInformation.setParameters(parameters);
+ if (activeSignature.get() < 0 && signature.isActive()) {
+ activeSignature.set(signatures.size());
+ activeParameter.set(signatureInformation.getActiveParameter());
+ }
+ signatures.add(signatureInformation);
+ });
+ return CompletableFuture.completedFuture(signatures.isEmpty() ? null :
new SignatureHelp(signatures, activeSignature.get(), activeParameter.get()));
}
@Override
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 84867cfa97..8f657a9b2b 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
@@ -53,7 +53,6 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -109,6 +108,7 @@ import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.MarkupContent;
import org.eclipse.lsp4j.MessageActionItem;
import org.eclipse.lsp4j.MessageParams;
+import org.eclipse.lsp4j.ParameterInformation;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.ProgressParams;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
@@ -126,6 +126,9 @@ import org.eclipse.lsp4j.ResourceOperationKind;
import org.eclipse.lsp4j.ShowDocumentParams;
import org.eclipse.lsp4j.ShowDocumentResult;
import org.eclipse.lsp4j.ShowMessageRequestParams;
+import org.eclipse.lsp4j.SignatureHelp;
+import org.eclipse.lsp4j.SignatureHelpParams;
+import org.eclipse.lsp4j.SignatureInformation;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.TextDocumentClientCapabilities;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
@@ -1391,6 +1394,65 @@ public class ServerTest extends NbTestCase {
"\n");
}
+ public void testSignatureHelp() throws Exception {
+ File src = new File(getWorkDir(), "Test.java");
+ src.getParentFile().mkdirs();
+ String code = "/**\n" +
+ " * This is a test class with Javadoc.\n" +
+ " */\n" +
+ "public class Test {\n" +
+ " public static void main(String[] args) {\n" +
+ " System.out.println(\"len: \" + args.length);\n"
+
+ " }\n" +
+ "}\n";
+ try (Writer w = new FileWriter(src)) {
+ w.write(code);
+ }
+ FileUtil.refreshFor(getWorkDir());
+ Launcher<LanguageServer> serverLauncher =
createClientLauncherWithLogging(new LspClient() {
+ @Override
+ public void telemetryEvent(Object arg0) {
+ }
+
+ @Override
+ public void publishDiagnostics(PublishDiagnosticsParams params) {
+ }
+
+ @Override
+ public void showMessage(MessageParams arg0) {
+ }
+
+ @Override
+ public CompletableFuture<MessageActionItem>
showMessageRequest(ShowMessageRequestParams arg0) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public void logMessage(MessageParams arg0) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }, client.getInputStream(), client.getOutputStream());
+ serverLauncher.startListening();
+ LanguageServer server = serverLauncher.getRemoteProxy();
+ InitializeResult result = server.initialize(new
InitializeParams()).get();
+ assertNotNull(result.getCapabilities().getSignatureHelpProvider());
+ server.getTextDocumentService().didOpen(new
DidOpenTextDocumentParams(new TextDocumentItem(toURI(src), "java", 0, code)));
+ SignatureHelp help = server.getTextDocumentService().signatureHelp(new
SignatureHelpParams(new TextDocumentIdentifier(toURI(src)), new Position(5,
30))).get();
+ assertNotNull(help);
+ List<SignatureInformation> signatures = help.getSignatures();
+ assertNotNull(signatures);
+ SignatureInformation sInfo = signatures.stream().filter(si ->
"println(String x) : void".equals(si.getLabel())).findFirst().get();
+ assertNotNull(sInfo);
+ assertEquals(signatures.indexOf(sInfo),
help.getActiveSignature().intValue());
+ assertEquals(0, help.getActiveParameter().intValue());
+ List<ParameterInformation> params = sInfo.getParameters();
+ assertNotNull(params);
+ assertEquals(1, params.size());
+ assertTrue(params.get(0).getLabel().isLeft());
+ assertEquals("String x", params.get(0).getLabel().getLeft());
+ assertEquals(0, sInfo.getActiveParameter().intValue());
+ }
+
public void testAdvancedCompletion1() throws Exception {
String javaVersion = System.getProperty("java.specification.version");
File src = new File(getWorkDir(), "Test.java");
---------------------------------------------------------------------
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