This is an automated email from the ASF dual-hosted git repository.

jlahoda 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 aa742a6  Improving code completion appearance for both LSP client and 
Java LSP server.
aa742a6 is described below

commit aa742a673a21c13de008f5f30621a936997e478f
Author: Jan Lahoda <jlah...@netbeans.org>
AuthorDate: Mon Sep 16 07:17:33 2019 +0200

    Improving code completion appearance for both LSP client and Java LSP 
server.
---
 .../client/bindings/CompletionProviderImpl.java    | 121 ++++++++++++++-------
 .../lsp/server/text/TextDocumentServiceImpl.java   |  36 +++---
 .../modules/java/lsp/server/ServerTest.java        |   4 +-
 3 files changed, 99 insertions(+), 62 deletions(-)

diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CompletionProviderImpl.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CompletionProviderImpl.java
index 75a017f..8c873b4 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CompletionProviderImpl.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CompletionProviderImpl.java
@@ -37,8 +37,11 @@ import javax.swing.text.StyledDocument;
 import org.eclipse.lsp4j.CompletionItem;
 import org.eclipse.lsp4j.CompletionItemKind;
 import org.eclipse.lsp4j.CompletionList;
+import org.eclipse.lsp4j.CompletionOptions;
 import org.eclipse.lsp4j.CompletionParams;
+import org.eclipse.lsp4j.MarkupContent;
 import org.eclipse.lsp4j.ParameterInformation;
+import org.eclipse.lsp4j.ServerCapabilities;
 import org.eclipse.lsp4j.SignatureHelp;
 import org.eclipse.lsp4j.SignatureInformation;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
@@ -62,6 +65,7 @@ import org.openide.filesystems.FileObject;
 import org.openide.text.NbDocument;
 import org.openide.util.Exceptions;
 import org.openide.util.ImageUtilities;
+import org.openide.xml.XMLUtil;
 
 /**
  *
@@ -162,20 +166,13 @@ public class CompletionProviderImpl implements 
CompletionProvider {
                     for (CompletionItem i : items) {
                         String insert = i.getInsertText() != null ? 
i.getInsertText() : i.getLabel();
                         String leftLabel = encode(i.getLabel());
-                        String rightLabel = encode(""); //TODO: anything we 
could show there?
-                        String sortText = i.getSortText() != null ? 
i.getSortText() : i.getLabel();
-                        String header = "<html>" + "<b>" + (i.getDetail() != 
null ? i.getDetail() : i.getLabel()) + "</b>";
-                        String documentation;
-                        if (i.getDocumentation() != null) {
-                            header += "<br><br>";
-                            if (i.getDocumentation().isLeft()) {
-                                documentation = header + 
i.getDocumentation().getLeft();
-                            } else {
-                                documentation = header + 
i.getDocumentation().getRight().getValue(); //TODO: convert markup!
-                            }
+                        String rightLabel;
+                        if (i.getDetail() != null) {
+                            rightLabel = encode(i.getDetail());
                         } else {
-                            documentation = header;
+                            rightLabel = null;
                         }
+                        String sortText = i.getSortText() != null ? 
i.getSortText() : i.getLabel();
                         CompletionItemKind kind = i.getKind();
                         Icon ic = Icons.getCompletionIcon(kind);
                         ImageIcon icon = new 
ImageIcon(ImageUtilities.icon2Image(ic));
@@ -226,36 +223,66 @@ public class CompletionProviderImpl implements 
CompletionProvider {
 
                             @Override
                             public CompletionTask createDocumentationTask() {
-                                return new CompletionTask() {
+                                return new AsyncCompletionTask(new 
AsyncCompletionQuery() {
                                     @Override
-                                    public void query(CompletionResultSet 
resultSet) {
-                                        resultSet.setDocumentation(new 
CompletionDocumentation() {
-                                            @Override
-                                            public String getText() {
-                                                return documentation;
-                                            }
-                                            @Override
-                                            public URL getURL() {
-                                                return null;
-                                            }
-                                            @Override
-                                            public CompletionDocumentation 
resolveLink(String link) {
-                                                return null;
+                                    protected void query(CompletionResultSet 
resultSet, Document doc, int caretOffset) {
+                                        CompletionItem resolved;
+                                        if ((i.getDetail() == null || 
i.getDocumentation() == null) && hasCompletionResolve(server)) {
+                                            CompletionItem temp;
+                                            try {
+                                                temp = 
server.getTextDocumentService().resolveCompletionItem(i).get();
+                                            } catch (InterruptedException | 
ExecutionException ex) {
+                                                Exceptions.printStackTrace(ex);
+                                                temp = i;
                                             }
-                                            @Override
-                                            public Action 
getGotoSourceAction() {
-                                                return null;
-                                            }
-                                        });
+                                            resolved = temp;
+                                        } else {
+                                            resolved = i;
+                                        }
+                                        if (resolved.getDocumentation() != 
null || resolved.getDetail() != null) {
+                                            resultSet.setDocumentation(new 
CompletionDocumentation() {
+                                                @Override
+                                                public String getText() {
+                                                    StringBuilder 
documentation = new StringBuilder();
+                                                    
documentation.append("<html>\n");
+                                                    if (resolved.getDetail() 
!= null) {
+                                                        
documentation.append("<b>").append(escape(resolved.getDetail())).append("</b>");
+                                                        
documentation.append("\n<p>");
+                                                    }
+                                                    if 
(resolved.getDocumentation() != null) {
+                                                        MarkupContent content;
+                                                        if 
(resolved.getDocumentation().isLeft()) {
+                                                            content = new 
MarkupContent();
+                                                            
content.setKind("plaintext");
+                                                            
content.setValue(resolved.getDocumentation().getLeft());
+                                                        } else {
+                                                            content = 
resolved.getDocumentation().getRight();
+                                                        }
+                                                        switch 
(content.getKind()) {
+                                                            case "markdown":
+                                                            default:
+                                                            case "plaintext": 
documentation.append("<pre>\n").append(content.getValue()).append("\n</pre>"); 
break;
+                                                        }
+                                                    }
+                                                    return 
documentation.toString();
+                                                }
+                                                @Override
+                                                public URL getURL() {
+                                                    return null;
+                                                }
+                                                @Override
+                                                public CompletionDocumentation 
resolveLink(String link) {
+                                                    return null;
+                                                }
+                                                @Override
+                                                public Action 
getGotoSourceAction() {
+                                                    return null;
+                                                }
+                                            });
+                                        }
                                         resultSet.finish();
                                     }
-
-                                    @Override
-                                    public void refresh(CompletionResultSet 
resultSet) {}
-
-                                    @Override
-                                    public void cancel() {}
-                                };
+                                });
                             }
 
                             @Override
@@ -295,6 +322,24 @@ public class CompletionProviderImpl implements 
CompletionProvider {
         }, component);
     }
     
+    private boolean hasCompletionResolve(LSPBindings server) {
+        ServerCapabilities capabilities = 
server.getInitResult().getCapabilities();
+        if (capabilities == null) return false;
+        CompletionOptions completionProvider = 
capabilities.getCompletionProvider();
+        if (completionProvider == null) return false;
+        Boolean resolveProvider = completionProvider.getResolveProvider();
+        return resolveProvider != null && resolveProvider;
+    }
+
+    private static String escape(String s) {
+        if (s != null) {
+            try {
+                return XMLUtil.toAttributeValue(s);
+            } catch (Exception ex) {}
+        }
+        return s;
+    }
+
     private String encode(String str) {
         return str.replace("&", "&amp;")
                   .replace("<", "&lt;");
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/text/TextDocumentServiceImpl.java
 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/text/TextDocumentServiceImpl.java
index 3c46336..3f3ebe1 100644
--- 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/text/TextDocumentServiceImpl.java
+++ 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/text/TextDocumentServiceImpl.java
@@ -29,7 +29,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -40,8 +39,6 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.BiFunction;
-import java.util.function.Function;
 import java.util.prefs.Preferences;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
@@ -109,9 +106,6 @@ import org.netbeans.api.java.source.ElementHandle;
 import org.netbeans.api.java.source.JavaSource;
 import org.netbeans.api.java.source.ModificationResult;
 import org.netbeans.api.java.source.support.ReferencesCount;
-import org.netbeans.api.java.source.ui.ElementOpen;
-import org.netbeans.api.lexer.TokenHierarchy;
-import org.netbeans.modules.editor.NbEditorUtilities;
 import org.netbeans.modules.editor.java.GoToSupport;
 import org.netbeans.modules.editor.java.GoToSupport.Context;
 import org.netbeans.modules.editor.java.GoToSupport.GoToTarget;
@@ -136,16 +130,12 @@ import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.Fix;
 import org.netbeans.spi.editor.hints.LazyFixList;
 import org.netbeans.spi.java.hints.JavaFix;
-import org.netbeans.spi.lexer.MutableTextInput;
 import org.openide.cookies.EditorCookie;
-import org.openide.cookies.LineCookie;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
 import org.openide.filesystems.URLMapper;
 import org.openide.modules.Places;
-import org.openide.text.Line;
 import org.openide.text.NbDocument;
-import org.openide.text.PositionRef;
 import org.openide.util.Exceptions;
 import org.openide.util.RequestProcessor;
 
@@ -167,7 +157,8 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
     @Override
     public CompletableFuture<Either<List<CompletionItem>, CompletionList>> 
completion(CompletionParams params) {
         try {
-            FileObject file = fromUri(params.getTextDocument().getUri());
+            String uri = params.getTextDocument().getUri();
+            FileObject file = fromUri(uri);
             EditorCookie ec = file.getLookup().lookup(EditorCookie.class);
             Document doc = ec.openDocument();
             int caret = getOffset(doc, params.getPosition());
@@ -248,28 +239,29 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
 
         @Override
         public CompletionItem createExecutableItem(CompilationInfo info, 
ExecutableElement elem, ExecutableType type, int substitutionOffset, 
ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, 
boolean inImport, boolean addSemicolon, boolean smartType, int 
assignToVarOffset, boolean memberRef) {
-            CompletionItem item = new 
CompletionItem(elem.getSimpleName().toString());
-            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
             Iterator<? extends VariableElement> it = 
elem.getParameters().iterator();
             Iterator<? extends TypeMirror> tIt = 
type.getParameterTypes().iterator();
-            StringBuilder details = new StringBuilder();
+            StringBuilder label = new StringBuilder();
             String sep = "";
-            details.append("(");
+            label.append(elem.getSimpleName().toString());
+            label.append("(");
             while(it.hasNext() && tIt.hasNext()) {
                 TypeMirror tm = tIt.next();
                 if (tm == null) {
                     break;
                 }
-                details.append(sep);
-                details.append(Utilities.getTypeName(info, tm, false, 
elem.isVarArgs() && !tIt.hasNext()).toString());
-                details.append(' ');
-                details.append(it.next().getSimpleName().toString());
+                label.append(sep);
+                label.append(Utilities.getTypeName(info, tm, false, 
elem.isVarArgs() && !tIt.hasNext()).toString());
+                label.append(' ');
+                label.append(it.next().getSimpleName().toString());
                 sep = ", ";
             }
-            details.append(")");
+            label.append(") : ");
             TypeMirror retType = type.getReturnType();
-            details.append(Utilities.getTypeName(info, retType, 
false).toString());
-            item.setDetail(details.toString());
+            label.append(Utilities.getTypeName(info, retType, 
false).toString());
+            CompletionItem item = new CompletionItem(label.toString());
+            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
+            item.setInsertText(elem.getSimpleName().toString());
             return item;
         }
 
diff --git 
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ServerTest.java
 
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ServerTest.java
index 58151ee..b2545bd 100644
--- 
a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ServerTest.java
+++ 
b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/ServerTest.java
@@ -188,7 +188,7 @@ public class ServerTest extends NbTestCase {
         Either<List<CompletionItem>, CompletionList> completion = 
server.getTextDocumentService().completion(new CompletionParams(new 
TextDocumentIdentifier(src.toURI().toString()), 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());
-        assertEquals(Arrays.asList("Method:hashCode"), actualItems);
+        assertEquals(Arrays.asList("Method:hashCode() : int"), actualItems);
         VersionedTextDocumentIdentifier id = new 
VersionedTextDocumentIdentifier(1);
         id.setUri(src.toURI().toString());
         server.getTextDocumentService().didChange(new 
DidChangeTextDocumentParams(id, Arrays.asList(new 
TextDocumentContentChangeEvent(new Range(new Position(0, hashCodeStart), new 
Position(0, hashCodeStart + "hashCode".length())), "hashCode".length(), 
"equ"))));
@@ -196,7 +196,7 @@ public class ServerTest extends NbTestCase {
         assertDiags(diags, "Error:0:31-0:34");//hints
         completion = server.getTextDocumentService().completion(new 
CompletionParams(new TextDocumentIdentifier(src.toURI().toString()), new 
Position(0, hashCodeStart + 2))).get();
         actualItems = completion.getRight().getItems().stream().map(ci -> 
ci.getKind() + ":" + ci.getLabel()).collect(Collectors.toList());
-        assertEquals(Arrays.asList("Method:equals", 
"Method:equalsIgnoreCase"), actualItems);
+        assertEquals(Arrays.asList("Method:equals(Object anObject) : boolean", 
"Method:equalsIgnoreCase(String anotherString) : boolean"), actualItems);
         completion = server.getTextDocumentService().completion(new 
CompletionParams(new TextDocumentIdentifier(src.toURI().toString()), new 
Position(0, 0))).get();
         actualItems = completion.getRight().getItems().stream().map(ci -> 
ci.getKind() + ":" + ci.getLabel()).collect(Collectors.toList());
         assertTrue(actualItems.contains("Keyword:interface"));


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to