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/incubator-netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new c95b336  Various improvements to the Language Server Protocol client.
c95b336 is described below

commit c95b336f711c12413d69598b252c1b3cb8ab431f
Author: Jan Lahoda <lah...@gmail.com>
AuthorDate: Sun Jan 27 20:19:24 2019 +0100

    Various improvements to the Language Server Protocol client.
    
    * Creating and using a utility to convert FileObjects to URI strings.
    
    * Track the language server process.
    
    * Sending events asynchronously.
    
    * Improving LSP code completion.
    
    * Improvements to the LSP client: code completion tooltip, stopping all 
server on shutdown, handling workspace/configuration request.
    
    * Some more improvements: sending client capabilities (empty now); don't 
try to read fixes for errors when the server does not support codeActions.
---
 .../netbeans/modules/lsp/client/LSPBindings.java   |  52 +++++++--
 .../modules/lsp/client/{bindings => }/Utils.java   |   7 +-
 .../modules/lsp/client/bindings/CodeActions.java   |   6 +-
 .../client/bindings/CompletionProviderImpl.java    | 129 +++++++++++++++++++--
 .../lsp/client/bindings/HyperlinkProviderImpl.java |   5 +-
 .../lsp/client/bindings/LanguageClientImpl.java    |  31 ++++-
 .../lsp/client/bindings/NavigatorPanelImpl.java    |   4 +-
 .../TextDocumentSyncServerCapabilityHandler.java   |  54 ++++++---
 8 files changed, 244 insertions(+), 44 deletions(-)

diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/LSPBindings.java 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/LSPBindings.java
index b6af96d..f68c1db 100644
--- a/ide/lsp.client/src/org/netbeans/modules/lsp/client/LSPBindings.java
+++ b/ide/lsp.client/src/org/netbeans/modules/lsp/client/LSPBindings.java
@@ -23,12 +23,10 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.Socket;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.WeakHashMap;
@@ -36,8 +34,11 @@ import java.util.concurrent.ExecutionException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
+import org.eclipse.lsp4j.ClientCapabilities;
 import org.eclipse.lsp4j.InitializeParams;
 import org.eclipse.lsp4j.InitializeResult;
+import org.eclipse.lsp4j.TextDocumentClientCapabilities;
+import org.eclipse.lsp4j.WorkspaceClientCapabilities;
 import org.eclipse.lsp4j.jsonrpc.Launcher;
 import org.eclipse.lsp4j.launch.LSPLauncher;
 import org.eclipse.lsp4j.services.LanguageServer;
@@ -52,6 +53,7 @@ import 
org.netbeans.modules.lsp.client.spi.LanguageServerProvider;
 import 
org.netbeans.modules.lsp.client.spi.LanguageServerProvider.LanguageServerDescription;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
+import org.openide.modules.OnStop;
 import org.openide.util.Exceptions;
 import org.openide.util.NbBundle.Messages;
 import org.openide.util.RequestProcessor;
@@ -70,7 +72,7 @@ public class LSPBindings {
     private static final Map<FileObject, Map<String, LSPBindings>> 
workspace2Extension2Server = new HashMap<>();
     private final Map<FileObject, Map<BackgroundTask, RequestProcessor.Task>> 
backgroundTasks = new WeakHashMap<>();
 
-    public static LSPBindings getBindings(FileObject file) {
+    public static synchronized LSPBindings getBindings(FileObject file) {
         for (Entry<FileObject, Map<String, LSPBindings>> e : 
workspace2Extension2Server.entrySet()) {
             if (FileUtil.isParentOf(e.getKey(), file)) {
                 LSPBindings bindings = e.getValue().get(file.getExt());
@@ -108,21 +110,26 @@ public class LSPBindings {
                                                        
launcher.startListening();
                                                        LanguageServer server = 
launcher.getRemoteProxy();
                                                        InitializeParams 
initParams = new InitializeParams();
-                                                       
initParams.setRootUri(prj.getProjectDirectory().toURI().toString()); //XXX: 
what if a different root is expected????
+                                                       
initParams.setRootUri(Utils.toURI(prj.getProjectDirectory())); //XXX: what if a 
different root is expected????
                                                        
initParams.setRootPath(FileUtil.toFile(prj.getProjectDirectory()).getAbsolutePath());
 //some servers still expect root path
                                                        
initParams.setProcessId(0);
+                                                       
initParams.setCapabilities(new ClientCapabilities(new 
WorkspaceClientCapabilities(), new TextDocumentClientCapabilities(), null));
                                                        InitializeResult result 
= server.initialize(initParams).get();
-                                                       LSPBindings b = new 
LSPBindings(server, result);
+                                                       LSPBindings b = new 
LSPBindings(server, result, 
LanguageServerProviderAccessor.getINSTANCE().getProcess(desc));
                                                        lci.setBindings(b);
                                                        return b;
                                                    } catch 
(InterruptedException | ExecutionException ex) {
-                                                       LOG.log(Level.FINE, 
null, ex);
+                                                       LOG.log(Level.WARNING, 
null, ex);
                                                    }
                                                }
                                            }
-                                           return new LSPBindings(null, null);
+                                           return new LSPBindings(null, null, 
null);
                                        });
 
+        if (bindings.process != null && !bindings.process.isAlive()) {
+            //XXX: what now
+            return null;
+        }
         return bindings.server != null ? bindings : null;
     }
     private static final Logger LOG = 
Logger.getLogger(LSPBindings.class.getName());
@@ -147,10 +154,10 @@ public class LSPBindings {
                 LanguageServer server = launcher.getRemoteProxy();
 
                 InitializeParams initParams = new InitializeParams();
-                initParams.setRootUri(root.toURI().toString());
+                initParams.setRootUri(Utils.toURI(root));
                 initParams.setProcessId(0);
                 InitializeResult result = server.initialize(initParams).get();
-                LSPBindings bindings = new LSPBindings(server, result);
+                LSPBindings bindings = new LSPBindings(server, result, null);
 
                 lc.setBindings(bindings);
 
@@ -163,10 +170,12 @@ public class LSPBindings {
 
     private final LanguageServer server;
     private final InitializeResult initResult;
+    private final Process process;
 
-    private LSPBindings(LanguageServer server, InitializeResult initResult) {
+    private LSPBindings(LanguageServer server, InitializeResult initResult, 
Process process) {
         this.server = server;
         this.initResult = initResult;
+        this.process = process;
     }
 
     public TextDocumentService getTextDocumentService() {
@@ -222,4 +231,27 @@ public class LSPBindings {
     public interface BackgroundTask {
         public void run(LSPBindings bindings, FileObject file);
     }
+
+    @OnStop
+    public static class Cleanup implements Runnable {
+
+        @Override
+        public void run() {
+            for (Map<String, LSPBindings> mime2Bindings : 
project2MimeType2Server.values()) {
+                for (LSPBindings b : mime2Bindings.values()) {
+                    if (b != null) {
+                        b.process.destroy();
+                    }
+                }
+            }
+            for (Map<String, LSPBindings> mime2Bindings : 
workspace2Extension2Server.values()) {
+                for (LSPBindings b : mime2Bindings.values()) {
+                    if (b != null) {
+                        b.process.destroy();
+                    }
+                }
+            }
+        }
+
+    }
 }
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/Utils.java 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
similarity index 88%
rename from 
ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/Utils.java
rename to ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
index ca0c7d9..f972bc5 100644
--- a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/Utils.java
+++ b/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
@@ -16,13 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.netbeans.modules.lsp.client.bindings;
+package org.netbeans.modules.lsp.client;
 
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import org.eclipse.lsp4j.Position;
 import org.netbeans.api.editor.document.LineDocument;
 import org.netbeans.api.editor.document.LineDocumentUtils;
+import org.openide.filesystems.FileObject;
 
 /**
  *
@@ -30,6 +31,10 @@ import org.netbeans.api.editor.document.LineDocumentUtils;
  */
 public class Utils {
 
+    public static String toURI(FileObject file) {
+        return file.toURI().toString().replace("file:/", "file:///");
+    }
+
     public static Position createPosition(Document doc, int offset) throws 
BadLocationException {
          return new Position(LineDocumentUtils.getLineIndex((LineDocument) 
doc, offset),
                              offset - 
LineDocumentUtils.getLineStart((LineDocument) doc, offset));
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CodeActions.java 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CodeActions.java
index 8e7e071..982da88 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CodeActions.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/CodeActions.java
@@ -18,7 +18,6 @@
  */
 package org.netbeans.modules.lsp.client.bindings;
 
-import java.net.URI;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -34,6 +33,7 @@ import org.eclipse.lsp4j.TextDocumentIdentifier;
 import org.netbeans.api.editor.mimelookup.MimeRegistration;
 import org.netbeans.modules.editor.NbEditorUtilities;
 import org.netbeans.modules.lsp.client.LSPBindings;
+import org.netbeans.modules.lsp.client.Utils;
 import org.netbeans.spi.editor.codegen.CodeGenerator;
 import org.openide.filesystems.FileObject;
 import org.openide.util.Exceptions;
@@ -60,10 +60,10 @@ public class CodeActions implements CodeGenerator.Factory {
         if (server == null) {
             return Collections.emptyList();
         }
-        URI uri = file.toURI();
+        String uri = Utils.toURI(file);
         try {
             List<? extends Command> commands = 
-                    server.getTextDocumentService().codeAction(new 
CodeActionParams(new TextDocumentIdentifier(uri.toString()),
+                    server.getTextDocumentService().codeAction(new 
CodeActionParams(new TextDocumentIdentifier(uri),
                     new Range(Utils.createPosition(component.getDocument(), 
component.getSelectionStart()),
                             Utils.createPosition(component.getDocument(), 
component.getSelectionEnd())),
                     new CodeActionContext(Collections.emptyList()))).get();
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 61d016f..75a017f 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
@@ -22,12 +22,14 @@ import java.awt.Color;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.event.KeyEvent;
-import java.net.URI;
+import java.net.URL;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
+import javax.swing.Action;
 import javax.swing.Icon;
 import javax.swing.ImageIcon;
+import javax.swing.JToolTip;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.JTextComponent;
@@ -36,7 +38,11 @@ import org.eclipse.lsp4j.CompletionItem;
 import org.eclipse.lsp4j.CompletionItemKind;
 import org.eclipse.lsp4j.CompletionList;
 import org.eclipse.lsp4j.CompletionParams;
+import org.eclipse.lsp4j.ParameterInformation;
+import org.eclipse.lsp4j.SignatureHelp;
+import org.eclipse.lsp4j.SignatureInformation;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.lsp4j.TextDocumentPositionParams;
 import org.eclipse.lsp4j.TextEdit;
 import org.eclipse.lsp4j.jsonrpc.messages.Either;
 import org.netbeans.api.editor.mimelookup.MimeRegistration;
@@ -44,6 +50,8 @@ import org.netbeans.editor.BaseDocument;
 import org.netbeans.editor.Utilities;
 import org.netbeans.modules.editor.NbEditorUtilities;
 import org.netbeans.modules.lsp.client.LSPBindings;
+import org.netbeans.modules.lsp.client.Utils;
+import org.netbeans.spi.editor.completion.CompletionDocumentation;
 import org.netbeans.spi.editor.completion.CompletionProvider;
 import org.netbeans.spi.editor.completion.CompletionResultSet;
 import org.netbeans.spi.editor.completion.CompletionTask;
@@ -64,6 +72,64 @@ public class CompletionProviderImpl implements 
CompletionProvider {
 
     @Override
     public CompletionTask createTask(int queryType, JTextComponent component) {
+        if ((queryType & TOOLTIP_QUERY_TYPE) != 0) {
+            return new AsyncCompletionTask(new AsyncCompletionQuery() {
+                @Override
+                protected void query(CompletionResultSet resultSet, Document 
doc, int caretOffset) {
+                    try {
+                        FileObject file = NbEditorUtilities.getFileObject(doc);
+                        if (file == null) {
+                            //TODO: beep
+                            return ;
+                        }
+                        LSPBindings server = LSPBindings.getBindings(file);
+                        if (server == null) {
+                            return ;
+                        }
+                        String uri = Utils.toURI(file);
+                        TextDocumentPositionParams params;
+                        params = new TextDocumentPositionParams(new 
TextDocumentIdentifier(uri),
+                                Utils.createPosition(doc, caretOffset));
+                        SignatureHelp help = 
server.getTextDocumentService().signatureHelp(params).get();
+                        if (help == null || help.getSignatures().isEmpty()) {
+                            return ;
+                        }
+                        //TODO: active signature?
+                        StringBuilder signatures = new StringBuilder();
+                        signatures.append("<html>");
+                        for (SignatureInformation info : help.getSignatures()) 
{
+                            if (info.getParameters().isEmpty()) {
+                                signatures.append("No parameter.");
+                                continue;
+                            }
+                            String sigSep = "";
+                            int idx = 0;
+                            for (ParameterInformation pi : 
info.getParameters()) {
+                                if (idx == help.getActiveParameter()) {
+                                    signatures.append("<b>");
+                                }
+                                signatures.append(sigSep);
+                                signatures.append(pi.getLabel());
+                                if (idx == help.getActiveParameter()) {
+                                    signatures.append("</b>");
+                                }
+                                sigSep = ", ";
+                                idx++;
+                            }
+                        }
+                        JToolTip tip = new JToolTip();
+                        tip.setTipText(signatures.toString());
+                        resultSet.setToolTip(tip);
+                    } catch (BadLocationException | InterruptedException ex) {
+                        Exceptions.printStackTrace(ex);
+                    } catch (ExecutionException ex) {
+                        Exceptions.printStackTrace(ex);
+                    } finally {
+                        resultSet.finish();
+                    }
+                }
+            }, component);
+        }
         return new AsyncCompletionTask(new AsyncCompletionQuery() {
             @Override
             protected void query(CompletionResultSet resultSet, Document doc, 
int caretOffset) {
@@ -77,9 +143,9 @@ public class CompletionProviderImpl implements 
CompletionProvider {
                     if (server == null) {
                         return ;
                     }
-                    URI uri = file.toURI();
+                    String uri = Utils.toURI(file);
                     CompletionParams params;
-                    params = new CompletionParams(new 
TextDocumentIdentifier(uri.toString()),
+                    params = new CompletionParams(new 
TextDocumentIdentifier(uri),
                             Utils.createPosition(doc, caretOffset));
                     CountDownLatch l = new CountDownLatch(1);
                     //TODO: Location or Location[]
@@ -95,6 +161,21 @@ 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!
+                            }
+                        } else {
+                            documentation = header;
+                        }
                         CompletionItemKind kind = i.getKind();
                         Icon ic = Icons.getCompletionIcon(kind);
                         ImageIcon icon = new 
ImageIcon(ImageUtilities.icon2Image(ic));
@@ -135,17 +216,46 @@ public class CompletionProviderImpl implements 
CompletionProvider {
 
                             @Override
                             public int getPreferredWidth(Graphics grphcs, Font 
font) {
-                                return 
CompletionUtilities.getPreferredWidth(insert, null, grphcs, font);
+                                return 
CompletionUtilities.getPreferredWidth(leftLabel, rightLabel, grphcs, font);
                             }
 
                             @Override
                             public void render(Graphics grphcs, Font font, 
Color color, Color color1, int i, int i1, boolean bln) {
-                                CompletionUtilities.renderHtml(icon, insert, 
null, grphcs, font, color, i, i1, bln);
+                                CompletionUtilities.renderHtml(icon, 
leftLabel, rightLabel, grphcs, font, color, i, i1, bln);
                             }
 
                             @Override
                             public CompletionTask createDocumentationTask() {
-                                return null;
+                                return new CompletionTask() {
+                                    @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;
+                                            }
+                                            @Override
+                                            public Action 
getGotoSourceAction() {
+                                                return null;
+                                            }
+                                        });
+                                        resultSet.finish();
+                                    }
+
+                                    @Override
+                                    public void refresh(CompletionResultSet 
resultSet) {}
+
+                                    @Override
+                                    public void cancel() {}
+                                };
                             }
 
                             @Override
@@ -165,7 +275,7 @@ public class CompletionProviderImpl implements 
CompletionProvider {
 
                             @Override
                             public CharSequence getSortText() {
-                                return i.getSortText();
+                                return sortText;
                             }
 
                             @Override
@@ -184,6 +294,11 @@ public class CompletionProviderImpl implements 
CompletionProvider {
             }
         }, component);
     }
+    
+    private String encode(String str) {
+        return str.replace("&", "&amp;")
+                  .replace("<", "&lt;");
+    }
 
     @Override
     public int getAutoQueryTypes(JTextComponent component, String typedText) {
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/HyperlinkProviderImpl.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/HyperlinkProviderImpl.java
index 4c79aa1..4f1cb70 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/HyperlinkProviderImpl.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/HyperlinkProviderImpl.java
@@ -38,6 +38,7 @@ import 
org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt;
 import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
 import org.netbeans.modules.editor.NbEditorUtilities;
 import org.netbeans.modules.lsp.client.LSPBindings;
+import org.netbeans.modules.lsp.client.Utils;
 import org.openide.cookies.LineCookie;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.URLMapper;
@@ -84,10 +85,10 @@ public class HyperlinkProviderImpl implements 
HyperlinkProviderExt {
         if (server == null) {
             return ;
         }
-        URI uri = file.toURI();
+        String uri = Utils.toURI(file);
         try {
             TextDocumentPositionParams params;
-            params = new TextDocumentPositionParams(new 
TextDocumentIdentifier(uri.toString()),
+            params = new TextDocumentPositionParams(new 
TextDocumentIdentifier(uri),
                                                     Utils.createPosition(doc, 
offset));
             //TODO: Location or Location[]
             CompletableFuture<List<? extends Location>> def = 
server.getTextDocumentService().definition(params);
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/LanguageClientImpl.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/LanguageClientImpl.java
index 4ed1fd5..fe2ebdd 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/LanguageClientImpl.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/LanguageClientImpl.java
@@ -24,6 +24,7 @@ import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.List;
@@ -42,18 +43,22 @@ import org.eclipse.lsp4j.ApplyWorkspaceEditResponse;
 import org.eclipse.lsp4j.CodeActionContext;
 import org.eclipse.lsp4j.CodeActionParams;
 import org.eclipse.lsp4j.Command;
+import org.eclipse.lsp4j.ConfigurationItem;
+import org.eclipse.lsp4j.ConfigurationParams;
 import org.eclipse.lsp4j.Diagnostic;
 import org.eclipse.lsp4j.DiagnosticSeverity;
 import org.eclipse.lsp4j.ExecuteCommandParams;
 import org.eclipse.lsp4j.MessageActionItem;
 import org.eclipse.lsp4j.MessageParams;
 import org.eclipse.lsp4j.PublishDiagnosticsParams;
+import org.eclipse.lsp4j.ServerCapabilities;
 import org.eclipse.lsp4j.ShowMessageRequestParams;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
 import org.eclipse.lsp4j.TextEdit;
 import org.eclipse.lsp4j.WorkspaceEdit;
 import org.eclipse.lsp4j.services.LanguageClient;
 import org.netbeans.modules.lsp.client.LSPBindings;
+import org.netbeans.modules.lsp.client.Utils;
 import org.netbeans.spi.editor.hints.ChangeInfo;
 import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
@@ -66,6 +71,7 @@ import org.openide.filesystems.FileObject;
 import org.openide.filesystems.URLMapper;
 import org.openide.text.NbDocument;
 import org.openide.util.Exceptions;
+import org.openide.util.RequestProcessor;
 
 /**
  *
@@ -74,11 +80,16 @@ import org.openide.util.Exceptions;
 public class LanguageClientImpl implements LanguageClient {
 
     private static final Logger LOG = 
Logger.getLogger(LanguageClientImpl.class.getName());
+    private static final RequestProcessor WORKER = new 
RequestProcessor(LanguageClientImpl.class.getName(), 1, false, false);
 
     private LSPBindings bindings;
+    private boolean allowCodeActions;
 
     public void setBindings(LSPBindings bindings) {
         this.bindings = bindings;
+        ServerCapabilities serverCapabilities = 
bindings.getInitResult().getCapabilities();
+        Boolean codeActions = serverCapabilities.getCodeActionProvider();
+        allowCodeActions = codeActions != null && codeActions;
     }
 
     @Override
@@ -94,9 +105,10 @@ public class LanguageClientImpl implements LanguageClient {
             Document doc = ec != null ? ec.getDocument() : null;
             if (doc == null)
                 return ; //ignore...
-            List<ErrorDescription> diags = pdp.getDiagnostics().stream().map(d 
-> 
-                    
ErrorDescriptionFactory.createErrorDescription(severityMap.get(d.getSeverity()),
 d.getMessage(), new DiagnosticFixList(pdp.getUri(), d), file, 
Utils.getOffset(doc, d.getRange().getStart()), Utils.getOffset(doc, 
d.getRange().getEnd()))
-            ).collect(Collectors.toList());
+            List<ErrorDescription> diags = pdp.getDiagnostics().stream().map(d 
-> {
+                LazyFixList fixList = allowCodeActions ? new 
DiagnosticFixList(pdp.getUri(), d) : 
ErrorDescriptionFactory.lazyListForFixes(Collections.emptyList());
+                return 
ErrorDescriptionFactory.createErrorDescription(severityMap.get(d.getSeverity()),
 d.getMessage(), fixList, file, Utils.getOffset(doc, d.getRange().getStart()), 
Utils.getOffset(doc, d.getRange().getEnd()));
+            }).collect(Collectors.toList());
             HintsController.setErrors(doc, LanguageClientImpl.class.getName(), 
diags);
         } catch (URISyntaxException | MalformedURLException ex) {
             LOG.log(Level.FINE, null, ex);
@@ -161,6 +173,19 @@ public class LanguageClientImpl implements LanguageClient {
         System.err.println("logMessage: " + arg0);
     }
 
+    @Override
+    public CompletableFuture<List<Object>> configuration(ConfigurationParams 
configurationParams) {
+        CompletableFuture<List<Object>> result = new CompletableFuture<>();
+        WORKER.post(() -> {
+            List<Object> outcome = new ArrayList<>();
+            for (ConfigurationItem ci : configurationParams.getItems()) {
+                outcome.add(null);
+            }
+            result.complete(outcome);
+        });
+        return result;
+    }
+
     private final class DiagnosticFixList implements LazyFixList {
 
         private final PropertyChangeSupport pcs = new 
PropertyChangeSupport(this);
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/NavigatorPanelImpl.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/NavigatorPanelImpl.java
index bbc12f3..def4911 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/NavigatorPanelImpl.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/NavigatorPanelImpl.java
@@ -32,6 +32,7 @@ import org.eclipse.lsp4j.SymbolInformation;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
 import org.netbeans.modules.lsp.client.LSPBindings;
 import org.netbeans.modules.lsp.client.LSPBindings.BackgroundTask;
+import org.netbeans.modules.lsp.client.Utils;
 import org.netbeans.spi.navigator.NavigatorPanel;
 import org.openide.explorer.ExplorerManager;
 import org.openide.explorer.view.BeanTreeView;
@@ -135,7 +136,8 @@ public class NavigatorPanelImpl extends 
Children.Keys<SymbolInformation> impleme
     public void run(LSPBindings bindings, FileObject file) {
         if (file.equals(this.file)) {
             try {
-                List<? extends SymbolInformation> symbols = 
bindings.getTextDocumentService().documentSymbol(new DocumentSymbolParams(new 
TextDocumentIdentifier(file.toURI().toString()))).get();
+                String uri = Utils.toURI(file);
+                List<? extends SymbolInformation> symbols = 
bindings.getTextDocumentService().documentSymbol(new DocumentSymbolParams(new 
TextDocumentIdentifier(uri))).get();
 
                 setKeys(symbols);
             } catch (InterruptedException | ExecutionException ex) {
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/TextDocumentSyncServerCapabilityHandler.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/TextDocumentSyncServerCapabilityHandler.java
index c08a3b9..9ac2f60 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/TextDocumentSyncServerCapabilityHandler.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/TextDocumentSyncServerCapabilityHandler.java
@@ -39,19 +39,21 @@ import org.netbeans.api.editor.EditorRegistry;
 import org.netbeans.editor.BaseDocumentEvent;
 import org.netbeans.modules.editor.*;
 import org.netbeans.modules.lsp.client.LSPBindings;
+import org.netbeans.modules.lsp.client.Utils;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
 import org.openide.modules.OnStart;
 import org.openide.util.Exceptions;
+import org.openide.util.RequestProcessor;
 
-/** TODO: asynchronous
- *  TODO: follow the synchronization options
+/** TODO: follow the synchronization options
  *  TODO: close
  *
  * @author lahvac
  */
 public class TextDocumentSyncServerCapabilityHandler {
 
+    private final RequestProcessor WORKER = new 
RequestProcessor(TextDocumentSyncServerCapabilityHandler.class.getName(), 1, 
false, false);
     private final Set<JTextComponent> lastOpened = 
Collections.newSetFromMap(new IdentityHashMap<>());
 
     private void handleChange() {
@@ -73,25 +75,34 @@ public class TextDocumentSyncServerCapabilityHandler {
             if (file == null)
                 continue; //ignore
 
-            LSPBindings server = LSPBindings.getBindings(file);
+            Document doc = opened.getDocument();
 
-            if (server == null)
-                continue; //ignore
+            WORKER.post(() -> {
+                LSPBindings server = LSPBindings.getBindings(file);
+
+                if (server == null)
+                    return ; //ignore
+
+                String uri = Utils.toURI(file);
+                String[] text = new String[1];
 
-            try {
-                //XXX: should construct events outside of AWT
-                TextDocumentItem textDocumentItem = new 
TextDocumentItem(file.toURI().toString(),
+                doc.render(() -> {
+                    try {
+                        text[0] = doc.getText(0, doc.getLength());
+                    } catch (BadLocationException ex) {
+                        Exceptions.printStackTrace(ex);
+                        text[0] = "";
+                    }
+                });
+
+                TextDocumentItem textDocumentItem = new TextDocumentItem(uri,
                                                                          
FileUtil.getMIMEType(file),
                                                                          0,
-                                                                         
opened.getDocument().getText(0, opened.getDocument().getLength())); //XXX: 
should do in render!
+                                                                         
text[0]);
 
                 server.getTextDocumentService().didOpen(new 
DidOpenTextDocumentParams(textDocumentItem));
                 server.scheduleBackgroundTasks(file);
-            } catch (BadLocationException ex) {
-                Exceptions.printStackTrace(ex);
-            }
-
-            Document doc = opened.getDocument();
+            });
 
             doc.addDocumentListener(new DocumentListener() { //XXX: listener
                 int version; //XXX: proper versioning!
@@ -128,9 +139,18 @@ public class TextDocumentSyncServerCapabilityHandler {
                                                                    
oldText.length(),
                                                                    newText);
                         VersionedTextDocumentIdentifier di = new 
VersionedTextDocumentIdentifier(++version);
-                        di.setUri(file.toURI().toString());
-                        server.getTextDocumentService().didChange(new 
DidChangeTextDocumentParams(di, Arrays.asList(event)));
-                        server.scheduleBackgroundTasks(file);
+                        
di.setUri(org.netbeans.modules.lsp.client.Utils.toURI(file));
+                        DidChangeTextDocumentParams params = new 
DidChangeTextDocumentParams(di, Arrays.asList(event));
+
+                        WORKER.post(() -> {
+                            LSPBindings server = LSPBindings.getBindings(file);
+
+                            if (server == null)
+                                return ; //ignore
+
+                            server.getTextDocumentService().didChange(params);
+                            server.scheduleBackgroundTasks(file);
+                        });
                     } catch (BadLocationException ex) {
                         Exceptions.printStackTrace(ex);
                     }


---------------------------------------------------------------------
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