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

neilcsmith pushed a commit to branch delivery
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/delivery by this push:
     new 82a0ab7  Fixes to LSP client/server related to semantic highlighting.
     new 8387f9f  Merge pull request #3492 from 
jlahoda/LSP-client-semantic-fixes
82a0ab7 is described below

commit 82a0ab7d7bc5e4211710bcf754a5c751b3c6e22c
Author: Jan Lahoda <jlah...@netbeans.org>
AuthorDate: Sat Jan 22 17:52:56 2022 +0100

    Fixes to LSP client/server related to semantic highlighting.
---
 .../netbeans/modules/lsp/client/LSPBindings.java   | 13 +++
 .../client/bindings/CompletionProviderImpl.java    |  6 +-
 .../lsp/client/bindings/SemanticHighlight.java     | 73 ++++++----------
 .../textmate/lexer/resources/fontsColors.xml       |  2 +
 .../netbeans/modules/java/lsp/server/Utils.java    |  4 +
 .../server/protocol/TextDocumentServiceImpl.java   |  7 +-
 .../java/lsp/server/protocol/ServerTest.java       | 99 +++++++++++++++++++++-
 7 files changed, 150 insertions(+), 54 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 b2f180d..2fcb1cd 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
@@ -37,6 +37,7 @@ import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -56,6 +57,8 @@ import org.eclipse.lsp4j.InitializeParams;
 import org.eclipse.lsp4j.InitializeResult;
 import org.eclipse.lsp4j.ResourceOperationKind;
 import org.eclipse.lsp4j.SemanticTokens;
+import org.eclipse.lsp4j.SemanticTokensCapabilities;
+import org.eclipse.lsp4j.SemanticTokensClientCapabilitiesRequests;
 import org.eclipse.lsp4j.SemanticTokensLegend;
 import org.eclipse.lsp4j.ServerCapabilities;
 import org.eclipse.lsp4j.SymbolCapabilities;
@@ -367,6 +370,7 @@ public class LSPBindings {
        dsc.setHierarchicalDocumentSymbolSupport(true);
        dsc.setSymbolKind(new 
SymbolKindCapabilities(Arrays.asList(SymbolKind.values())));
        tdcc.setDocumentSymbol(dsc);
+       tdcc.setSemanticTokens(new SemanticTokensCapabilities(new 
SemanticTokensClientCapabilitiesRequests(true), KNOWN_TOKEN_TYPES, 
KNOWN_TOKEN_MODIFIERS, Arrays.asList()));
        WorkspaceClientCapabilities wcc = new WorkspaceClientCapabilities();
        wcc.setWorkspaceEdit(new WorkspaceEditCapabilities());
        wcc.getWorkspaceEdit().setDocumentChanges(true);
@@ -387,6 +391,15 @@ public class LSPBindings {
            }
        }
     }
+    private static final List<String> KNOWN_TOKEN_TYPES = 
Collections.unmodifiableList(Arrays.asList(
+            "namespace", "package", "function", "method", "macro", "parameter",
+            "variable", "struct", "enum", "class", "typeAlias", 
"typeParameter",
+            "field", "enumMember", "keyword"
+    ));
+
+    private static final List<String> KNOWN_TOKEN_MODIFIERS = 
Collections.unmodifiableList(Arrays.asList(
+            "static", "definition", "declaration"
+    ));
 
     public static synchronized Set<LSPBindings> getAllBindings() {
         Set<LSPBindings> allBindings = Collections.newSetFromMap(new 
IdentityHashMap<>());
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 0fba1fc..0869a66 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
@@ -42,6 +42,7 @@ import org.eclipse.lsp4j.CompletionList;
 import org.eclipse.lsp4j.CompletionOptions;
 import org.eclipse.lsp4j.CompletionParams;
 import org.eclipse.lsp4j.InitializeResult;
+import org.eclipse.lsp4j.InsertReplaceEdit;
 import org.eclipse.lsp4j.MarkupContent;
 import org.eclipse.lsp4j.ParameterInformation;
 import org.eclipse.lsp4j.ServerCapabilities;
@@ -189,13 +190,14 @@ public class CompletionProviderImpl implements 
CompletionProvider {
                                 commit("");
                             }
                             private void commit(String appendText) {
-                                if (i.getTextEdit().isRight()) {
+                                Either<TextEdit, InsertReplaceEdit> edit = 
i.getTextEdit();
+                                if (edit != null && edit.isRight()) {
                                     //TODO: the NetBeans client does not 
current support InsertReplaceEdits, should not happen
                                     Completion.get().hideDocumentation();
                                     Completion.get().hideCompletion();
                                     return ;
                                 }
-                                TextEdit te = i.getTextEdit().getLeft();
+                                TextEdit te = edit != null ? edit.getLeft() : 
null;
                                 NbDocument.runAtomic((StyledDocument) doc, () 
-> {
                                     try {
                                         int endPos;
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/SemanticHighlight.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/SemanticHighlight.java
index e40323a..d63113f 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/SemanticHighlight.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/SemanticHighlight.java
@@ -18,12 +18,12 @@
  */
 package org.netbeans.modules.lsp.client.bindings;
 
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
+import java.util.Collection;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import javax.swing.text.AttributeSet;
 import javax.swing.text.Document;
@@ -32,11 +32,9 @@ import org.eclipse.lsp4j.Position;
 import org.eclipse.lsp4j.SemanticTokens;
 import org.eclipse.lsp4j.SemanticTokensLegend;
 import org.eclipse.lsp4j.SemanticTokensParams;
+import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
-import org.eclipse.lsp4j.generator.JsonRpcData;
-import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
 import org.netbeans.api.editor.mimelookup.MimeLookup;
-import org.netbeans.api.editor.mimelookup.MimePath;
 import org.netbeans.api.editor.mimelookup.MimeRegistration;
 import org.netbeans.api.editor.settings.AttributesUtilities;
 import org.netbeans.api.editor.settings.FontColorSettings;
@@ -65,6 +63,10 @@ public class SemanticHighlight implements BackgroundTask {
     @Override
     public void run(LSPBindings bindings, FileObject file) {
         try {
+            SemanticTokensWithRegistrationOptions options = 
bindings.getInitResult().getCapabilities().getSemanticTokensProvider();
+            if (options == null) {
+                return ;
+            }
             OffsetsBag target = new OffsetsBag(doc);
             SemanticTokensParams params = new SemanticTokensParams(new 
TextDocumentIdentifier(Utils.toURI(file)));
             SemanticTokens tokens = 
bindings.getTextDocumentService().semanticTokensFull(params).get();
@@ -130,7 +132,7 @@ public class SemanticHighlight implements BackgroundTask {
             AttributeSet statik = isStatic ? 
fcs.getTokenFontColors("mod-static") : null;
 
             if (colors != null && statik != null) {
-                return AttributesUtilities.createComposite(colors, statik);
+                return 
AttributesUtilities.createComposite(adjustAttributes(colors), 
adjustAttributes(statik));
             } else if (colors != null) {
                 return colors;
             } else if (statik != null) {
@@ -153,6 +155,22 @@ public class SemanticHighlight implements BackgroundTask {
         return bag;
     }
 
+    private static AttributeSet adjustAttributes(AttributeSet as) {
+        Collection<Object> attrs = new LinkedList<Object>();
+
+        for (Enumeration<?> e = as.getAttributeNames(); e.hasMoreElements(); ) 
{
+            Object key = e.nextElement();
+            Object value = as.getAttribute(key);
+
+            if (value != Boolean.FALSE) {
+                attrs.add(key);
+                attrs.add(value);
+            }
+        }
+
+        return AttributesUtilities.createImmutable(attrs.toArray());
+    }
+
     @MimeRegistration(mimeType="", service=HighlightsLayerFactory.class)
     public static final class HighlightsLayerFactoryImpl implements 
HighlightsLayerFactory {
 
@@ -164,44 +182,5 @@ public class SemanticHighlight implements BackgroundTask {
         }
         
     }
-    
-//    @JsonRpcData
-//    public static class SemanticTokensParams {
-//
-//        private TextDocumentIdentifier textDocument;
-//
-//        public SemanticTokensParams() {
-//        }
-//
-//        public SemanticTokensParams(TextDocumentIdentifier textDocument) {
-//            this.textDocument = textDocument;
-//        }
-//
-//        public TextDocumentIdentifier getTextDocument() {
-//            return textDocument;
-//        }
-//
-//        public void setTextDocument(TextDocumentIdentifier textDocument) {
-//            this.textDocument = textDocument;
-//        }
-// 
-//    }
-//
-//    @JsonRpcData
-//    public static class SemanticTokens {
-//        private List<Number> data;
-//
-//        public List<Number> getData() {
-//            return data;
-//        }
-//
-//        public void setData(List<Number> data) {
-//            this.data = data;
-//        }
-//
-//    }
-//    public interface SemanticService {
-//        @JsonRequest("textDocument/semanticTokens/full")
-//        public CompletableFuture<SemanticTokens> 
semanticTokensFull(SemanticTokensParams params);
-//    }
+
 }
diff --git 
a/ide/textmate.lexer/src/org/netbeans/modules/textmate/lexer/resources/fontsColors.xml
 
b/ide/textmate.lexer/src/org/netbeans/modules/textmate/lexer/resources/fontsColors.xml
index 27acc9b..2c1fcbb 100644
--- 
a/ide/textmate.lexer/src/org/netbeans/modules/textmate/lexer/resources/fontsColors.xml
+++ 
b/ide/textmate.lexer/src/org/netbeans/modules/textmate/lexer/resources/fontsColors.xml
@@ -67,6 +67,7 @@
     <fontcolor name="mod-typeParameter" default="identifier"/>
     <fontcolor name="mod-field" default="field"/>
     <fontcolor name="mod-enumMember" default="field"/>
+    <fontcolor name="mod-keyword" default="keyword"/>
 
     <fontcolor name="mod-namespace-declaration" default="identifier"/>
     <fontcolor name="mod-package-declaration" default="identifier"/>
@@ -82,6 +83,7 @@
     <fontcolor name="mod-typeParameter-declaration" default="identifier"/>
     <fontcolor name="mod-field-declaration" default="field"/>
     <fontcolor name="mod-enumMember-declaration" default="field"/>
+    <fontcolor name="mod-keyword-declaration" default="keyword"/>
 
     <fontcolor name="mod-static" >
         <font style="italic" />
diff --git 
a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java 
b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java
index 46ec105..3bb6bcb 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java
@@ -68,12 +68,14 @@ public class Utils {
             case ENUM:
                 return SymbolKind.Enum;
             case CLASS:
+            case RECORD:
                 return SymbolKind.Class;
             case ANNOTATION_TYPE:
                 return SymbolKind.Interface;
             case INTERFACE:
                 return SymbolKind.Interface;
             case ENUM_CONSTANT:
+            case RECORD_COMPONENT:
                 return SymbolKind.EnumMember;
             case FIELD:
                 return SymbolKind.Field; //TODO: constant
@@ -110,6 +112,7 @@ public class Utils {
             case INTERFACE:
             case ENUM:
             case ANNOTATION_TYPE:
+            case RECORD:
                 TypeElement te = (TypeElement) e;
                 StringBuilder sb = new StringBuilder();
                 sb.append(fqn ? te.getQualifiedName() : te.getSimpleName());
@@ -140,6 +143,7 @@ public class Utils {
                 return sb.toString();
             case FIELD:
             case ENUM_CONSTANT:
+            case RECORD_COMPONENT:
                 return e.getSimpleName().toString();
             case CONSTRUCTOR:
             case METHOD:
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 8a52631..0f62d46 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
@@ -1947,8 +1947,8 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
     static BiConsumer<String, Object> HOOK_NOTIFICATION = null;
 
     private static final Map<ColoringAttributes, List<String>> 
COLORING_TO_TOKEN_TYPE_CANDIDATES = new HashMap<ColoringAttributes, 
List<String>>() {{
-        put(ColoringAttributes.FIELD, Arrays.asList("member"));
-        put(ColoringAttributes.RECORD_COMPONENT, Arrays.asList("member"));
+        put(ColoringAttributes.FIELD, Arrays.asList("field", "member"));
+        put(ColoringAttributes.RECORD_COMPONENT, Arrays.asList("field", 
"member"));
         put(ColoringAttributes.LOCAL_VARIABLE, Arrays.asList("variable"));
         put(ColoringAttributes.PARAMETER, Arrays.asList("parameter"));
         put(ColoringAttributes.METHOD, Arrays.asList("method", "function"));
@@ -1959,6 +1959,7 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
         put(ColoringAttributes.ANNOTATION_TYPE, Arrays.asList("interface"));
         put(ColoringAttributes.ENUM, Arrays.asList("enum"));
         put(ColoringAttributes.TYPE_PARAMETER_DECLARATION, 
Arrays.asList("typeParameter"));
+        put(ColoringAttributes.KEYWORD, Arrays.asList("keyword"));
     }};
 
     private static final Map<ColoringAttributes, List<String>> 
COLORING_TO_TOKEN_MODIFIERS_CANDIDATES = new HashMap<ColoringAttributes, 
List<String>>() {{
@@ -2011,7 +2012,7 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                                                 modifiers |= mod;
                                             }
                                         }
-                                        if (tokenType.isPresent()) {
+                                        if (tokenType.isPresent() && 
tokenType.get() >= 0) {
                                             result.add(line - lastLine);
                                             result.add((int) (currentOffset - 
currentLineStart - column));
                                             result.add(e.getKey().length());
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 ad652e7..49c5fb9 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
@@ -159,11 +159,13 @@ import 
org.netbeans.modules.java.lsp.server.refactoring.ChangeMethodParameterUI;
 import org.netbeans.modules.java.lsp.server.refactoring.ParameterUI;
 import org.netbeans.modules.java.lsp.server.ui.MockHtmlViewer;
 import org.netbeans.modules.java.source.BootClassPathUtil;
+import org.netbeans.modules.java.source.parsing.JavacParser;
 import org.netbeans.modules.parsing.api.ResultIterator;
 import org.netbeans.modules.parsing.impl.indexing.implspi.CacheFolderProvider;
 import org.netbeans.spi.java.classpath.ClassPathProvider;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.netbeans.spi.java.queries.AnnotationProcessingQueryImplementation;
+import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
 import org.netbeans.spi.lsp.ErrorProvider;
 import org.netbeans.spi.project.ProjectFactory;
 import org.netbeans.spi.project.ProjectState;
@@ -710,10 +712,12 @@ public class ServerTest extends NbTestCase {
                       "        public void innerMethod() {\n" +
                       "        }\n" +
                       "    }\n" +
+                      "    record R(int i) {}\n" +
                       "}\n";
         try (Writer w = new FileWriter(src)) {
             w.write(code);
         }
+        file2SourceLevel.put(FileUtil.toFileObject(src.getParentFile()), "17");
         FileUtil.refreshFor(getWorkDir());
         Launcher<LanguageServer> serverLauncher = 
LSPLauncher.createClientLauncher(new LspClient() {
             @Override
@@ -758,7 +762,7 @@ public class ServerTest extends NbTestCase {
                           "    character = 0\n" +
                           "  ]\n" +
                           "  end = Position [\n" +
-                          "    line = 8\n" +
+                          "    line = 9\n" +
                           "    character = 1\n" +
                           "  ]\n" +
                           "]:(Class:Inner:Range [\n" +
@@ -779,6 +783,24 @@ public class ServerTest extends NbTestCase {
                           "    line = 6\n" +
                           "    character = 9\n" +
                           "  ]\n" +
+                          "]:()), Class:R:Range [\n" +
+                          "  start = Position [\n" +
+                          "    line = 8\n" +
+                          "    character = 4\n" +
+                          "  ]\n" +
+                          "  end = Position [\n" +
+                          "    line = 8\n" +
+                          "    character = 22\n" +
+                          "  ]\n" +
+                          "]:(Field:i:Range [\n" +
+                          "  start = Position [\n" +
+                          "    line = 8\n" +
+                          "    character = 13\n" +
+                          "  ]\n" +
+                          "  end = Position [\n" +
+                          "    line = 8\n" +
+                          "    character = 18\n" +
+                          "  ]\n" +
                           "]:()), Field:field:Range [\n" +
                           "  start = Position [\n" +
                           "    line = 1\n" +
@@ -4713,6 +4735,66 @@ public class ServerTest extends NbTestCase {
                        "3:20-26:method:[]");
     }
 
+    public void testSemanticHighlighting2() throws Exception {
+        File src = new File(getWorkDir(), "Test.java");
+        src.getParentFile().mkdirs();
+        String code = "public class Test {\n" +
+                      "    private static final int C = 0;\n" +
+                      "    public int method(int p) {\n" +
+                      "        int l = p + method(0);\n" +
+                      "    }\n" +
+                      "}\n";
+        try (Writer w = new FileWriter(src)) {
+            w.write(code);
+        }
+        FileUtil.refreshFor(getWorkDir());
+        Launcher<LanguageServer> serverLauncher = 
LSPLauncher.createClientLauncher(new LanguageClient() {
+            @Override
+            public void telemetryEvent(Object arg0) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @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();
+        ClientCapabilities clientCaps = new ClientCapabilities();
+        TextDocumentClientCapabilities textCaps = new 
TextDocumentClientCapabilities();
+        clientCaps.setTextDocument(textCaps);
+        SemanticTokensCapabilities sematicTokensCapabilities = new 
SemanticTokensCapabilities(true);
+        sematicTokensCapabilities.setTokenTypes(Arrays.asList("field", 
"method", "function", "class", "interface", "enum", "typeParameter"));
+        
sematicTokensCapabilities.setTokenModifiers(Arrays.asList("declaration", 
"static"));
+        textCaps.setSemanticTokens(sematicTokensCapabilities);
+        InitializeParams initParams = new InitializeParams();
+        initParams.setCapabilities(clientCaps);
+        InitializeResult result = server.initialize(initParams).get();
+        assertNotNull(result.getCapabilities().getSemanticTokensProvider());
+        SemanticTokensLegend legend = 
result.getCapabilities().getSemanticTokensProvider().getLegend();
+        server.getTextDocumentService().didOpen(new 
DidOpenTextDocumentParams(new TextDocumentItem(toURI(src), "java", 0, code)));
+        assertColoring(legend,
+                       server.getTextDocumentService().semanticTokensFull(new 
SemanticTokensParams(new TextDocumentIdentifier(toURI(src)))).get(),
+                       "0:13-17:class:[declaration]",
+                       "1:29-30:field:[declaration, static]",
+                       "2:15-21:method:[declaration]",
+                       "3:20-26:method:[]");
+    }
+
     private void assertColoring(SemanticTokensLegend legend, SemanticTokens 
tokens, String... expected) {
         List<String> coloring = new ArrayList<>();
         int line = 0;
@@ -4943,7 +5025,19 @@ public class ServerTest extends NbTestCase {
         public void saveProject(Project project) throws IOException, 
ClassCastException {
         }
     }
-    
+
+    private static final Map<FileObject, String> file2SourceLevel = new 
HashMap<>();
+
+    @ServiceProvider(service=SourceLevelQueryImplementation.class)
+    public static final class SourceLevelImpl implements 
SourceLevelQueryImplementation {
+
+        @Override
+        public String getSourceLevel(FileObject javaFile) {
+            return file2SourceLevel.getOrDefault(javaFile, "1.8");
+        }
+
+    }
+
     private static volatile ProgressCommand progressCommandInstance;
     
     @ServiceProvider(service = CodeActionsProvider.class)
@@ -5183,5 +5277,6 @@ public class ServerTest extends NbTestCase {
 
     static {
         System.setProperty("SourcePath.no.source.filter", "true");
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
     }
 }

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