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 aadbec9  LSP: Go to Type Definition added. (#2939)
aadbec9 is described below

commit aadbec9ceb27459767a785845aa82677e4a372ca
Author: Dusan Balek <dusan.ba...@oracle.com>
AuthorDate: Fri May 7 15:00:25 2021 +0200

    LSP: Go to Type Definition added. (#2939)
---
 ide/api.lsp/apichanges.xml                         | 96 ++++++++++++++++++++++
 ide/api.lsp/manifest.mf                            |  2 +-
 ide/api.lsp/nbproject/project.properties           |  1 +
 .../org/netbeans/api/lsp/HyperlinkLocation.java    | 28 +++++++
 .../spi/lsp/HyperlinkTypeDefLocationProvider.java  | 56 +++++++++++++
 java/java.editor/nbproject/project.xml             |  2 +-
 .../netbeans/modules/editor/java/GoToSupport.java  |  4 +-
 .../editor/hyperlink/JavaHyperlinkProvider.java    | 12 ++-
 java/java.lsp.server/nbproject/project.xml         |  2 +-
 .../modules/java/lsp/server/protocol/Server.java   |  1 +
 .../server/protocol/TextDocumentServiceImpl.java   | 26 +++++-
 .../java/lsp/server/protocol/ServerTest.java       | 69 ++++++++++++++++
 12 files changed, 292 insertions(+), 7 deletions(-)

diff --git a/ide/api.lsp/apichanges.xml b/ide/api.lsp/apichanges.xml
new file mode 100644
index 0000000..e533835
--- /dev/null
+++ b/ide/api.lsp/apichanges.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+
+<?xml-stylesheet href="../../nbbuild/javadoctools/apichanges.xsl" 
type="text/xsl"?>
+<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" 
"../../nbbuild/javadoctools/apichanges.dtd">
+
+<!-- INFO FOR PEOPLE ADDING CHANGES:
+[most of contents snipped - see openide's apichanges for how-to instructions]
+<change>
+    <api name="compiler"/>
+    <summary>Some brief description here, can use <b>XHTML</b></summary>
+    <version major="1" minor="99"/>
+    <date day="13" month="6" year="2001"/>
+    <author login="jrhacker"/>
+    <compatibility addition="yes"/>
+    <description>
+        The main description of the change here.
+        Again can use full <b>XHTML</b> as needed.
+    </description>
+    <class package="org.openide.compiler" name="DoWhatIWantCompiler"/>
+    <issue number="14309"/>
+</change>
+-->
+
+<apichanges>
+
+<!-- First, a list of API names you may use: -->
+<apidefs>
+        <apidef name="LSP_API">LSP APIs</apidef>
+</apidefs>
+
+<!-- ACTUAL CHANGES BEGIN HERE: -->
+
+<changes>
+    <change id="HyperlinkTypeDefLocationProvider">
+        <api name="LSP_API"/>
+        <summary>Adding HyperlinkTypeDefLocationProvider</summary>
+        <version major="1" minor="1"/>
+        <date day="5" month="5" year="2021"/>
+        <author login="dbalek"/>
+        <compatibility binary="compatible" source="compatible" addition="yes" 
deletion="no"/>
+        <description>
+            A <code>HyperlinkTypeDefLocationProvider</code> interface 
introduced that allows to
+            compute hyperlinks to type definition locations.
+        </description>
+        <class package="org.netbeans.spi.lsp" 
name="HyperlinkTypeDefLocationProvider"/>
+    </change>
+</changes>
+
+  <!-- Now the surrounding HTML text and document structure: -->
+
+  <htmlcontents>
+<!--
+                            NO NO NO NO NO!
+         ==============>    DO NOT EDIT ME!  <======================
+          AUTOMATICALLY GENERATED FROM APICHANGES.XML, DO NOT EDIT
+                SEE xml/api/doc/changes/apichanges.xml
+-->
+    <head>
+      <title>LSP API changes by date</title>
+      <link rel="stylesheet" href="prose.css" type="text/css"/>
+    </head>
+    <body>
+
+<p class="overviewlink"><a href="overview-summary.html">Overview</a></p>
+
+<h1>Introduction</h1>
+
+<p>This document lists changes made to the LSP APIs. Please ask on the
+    <code>d...@netbeans.apache.org</code>
+    mailing list if you have any questions about the details of a
+    change, or are wondering how to convert existing code to be compatible.
+</p>
+
+      <hr/><standard-changelists module-code-name="org.netbeans.api.lsp/1"/>
+
+      <hr/><p>@FOOTER@</p>
+
+    </body>
+  </htmlcontents>
+</apichanges>
diff --git a/ide/api.lsp/manifest.mf b/ide/api.lsp/manifest.mf
index 2a6458d..087bc50 100644
--- a/ide/api.lsp/manifest.mf
+++ b/ide/api.lsp/manifest.mf
@@ -1,6 +1,6 @@
 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.0
+OpenIDE-Module-Specification-Version: 1.1
 AutoUpdate-Show-In-Client: false
 
diff --git a/ide/api.lsp/nbproject/project.properties 
b/ide/api.lsp/nbproject/project.properties
index 0f73a11..445f2ff 100644
--- a/ide/api.lsp/nbproject/project.properties
+++ b/ide/api.lsp/nbproject/project.properties
@@ -17,3 +17,4 @@
 is.autoload=true
 javac.source=1.8
 javac.compilerargs=-Xlint -Xlint:-serial
+javadoc.apichanges=${basedir}/apichanges.xml
\ No newline at end of file
diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java 
b/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java
index 1c449a5..4ded8d2 100644
--- a/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java
@@ -29,6 +29,7 @@ import org.netbeans.api.editor.mimelookup.MimePath;
 import org.netbeans.lib.editor.util.swing.DocumentUtilities;
 import org.netbeans.modules.lsp.HyperlinkLocationAccessor;
 import org.netbeans.spi.lsp.HyperlinkLocationProvider;
+import org.netbeans.spi.lsp.HyperlinkTypeDefLocationProvider;
 import org.openide.filesystems.FileObject;
 
 /**
@@ -157,4 +158,31 @@ public final class HyperlinkLocation {
             return locations;
         });
     }
+
+    /**
+     * Resolves a hyperlink at the given document offset and returns its target
+     * type definition location(s).
+     *
+     * @param doc document on which to operate.
+     * @param offset offset within document
+     * @return target type definition location(s)
+     *
+     * @since 1.1
+     */
+    @NonNull
+    public static CompletableFuture<List<HyperlinkLocation>> 
resolveTypeDefinition(@NonNull final Document doc, final int offset) {
+        MimePath mimePath = MimePath.parse(DocumentUtilities.getMimeType(doc));
+        CompletableFuture<HyperlinkLocation>[] futures = 
MimeLookup.getLookup(mimePath).lookupAll(HyperlinkTypeDefLocationProvider.class).stream()
+                .map(provider -> provider.getHyperlinkTypeDefLocation(doc, 
offset)).toArray(CompletableFuture[]::new);
+        return CompletableFuture.allOf(futures).thenApply(value -> {
+            List<HyperlinkLocation> locations = new 
ArrayList<>(futures.length);
+            for (CompletableFuture<HyperlinkLocation> future : futures) {
+                HyperlinkLocation location = future.getNow(null);
+                if (location != null) {
+                    locations.add(location);
+                }
+            }
+            return locations;
+        });
+    }
 }
diff --git 
a/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkTypeDefLocationProvider.java 
b/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkTypeDefLocationProvider.java
new file mode 100644
index 0000000..86e8196
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkTypeDefLocationProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.netbeans.api.lsp.HyperlinkLocation;
+import java.util.concurrent.CompletableFuture;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.spi.editor.mimelookup.MimeLocation;
+
+/**
+ * Interface for resolving hyperlinks to type definition locations. 
Implementations of the interface
+ * should be registered in MimeLookup.
+ * <pre>
+ *
+ *  {@code @MimeRegistration(mimeType = "text/foo", service = 
HyperlinkTypeDefLocationProvider.class)
+ *   public class FooHyperlinkTypeDefLocationProvider implements 
HyperlinkTypeDefLocationProvider {
+ *     ...
+ *   }
+ *  }
+ * </pre>
+ *
+ * @author Dusan Balek
+ * @since 1.1
+ */
+@MimeLocation(subfolderName = "HyperlinkTypeDefLocationProviders")
+public interface HyperlinkTypeDefLocationProvider {
+
+    /**
+     * Resolves a hyperlink at the given document offset and returns its
+     * target type definition location.
+     *
+     * @param doc document on which to operate.
+     * @param offset offset within document
+     * @return target location
+     *
+     * @since 1.1
+     */
+    CompletableFuture<HyperlinkLocation> getHyperlinkTypeDefLocation(@NonNull 
Document doc, int offset);
+}
diff --git a/java/java.editor/nbproject/project.xml 
b/java/java.editor/nbproject/project.xml
index eaa3a89..460fd94 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.0</specification-version>
+                        <specification-version>1.1</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git 
a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java 
b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
index 287c926..4e081dd 100644
--- a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
+++ b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
@@ -166,7 +166,7 @@ public class GoToSupport {
         }
     }
 
-    public static CompletableFuture<HyperlinkLocation> getGoToLocation(final 
Document doc, final int offset) {
+    public static CompletableFuture<HyperlinkLocation> getGoToLocation(final 
Document doc, final int offset, final boolean goToSource) {
         try {
             final FileObject fo = getFileObject(doc);
             if (fo != null) {
@@ -182,7 +182,7 @@ public class GoToSupport {
                             return;
                         }
 
-                        Context resolved = resolveContext(controller, doc, 
offset, false, false);
+                        Context resolved = resolveContext(controller, doc, 
offset, goToSource, false);
 
                         if (resolved == null) {
                             target[0] = new GoToTarget(-1, -1, null, null, 
null, null, null, false);
diff --git 
a/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
 
b/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
index 74030ee..6fbb1ef 100644
--- 
a/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
+++ 
b/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
@@ -32,6 +32,7 @@ import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
 import org.netbeans.modules.editor.java.GoToSupport;
 import org.netbeans.modules.java.editor.overridden.GoToImplementation;
 import org.netbeans.spi.lsp.HyperlinkLocationProvider;
+import org.netbeans.spi.lsp.HyperlinkTypeDefLocationProvider;
 
 /**
  * Implementation of the hyperlink provider for java language.
@@ -88,7 +89,16 @@ public final class JavaHyperlinkProvider implements 
HyperlinkProviderExt {
 
         @Override
         public CompletableFuture<HyperlinkLocation> 
getHyperlinkLocation(Document doc, int offset) {
-            return GoToSupport.getGoToLocation(doc, offset);
+            return GoToSupport.getGoToLocation(doc, offset, false);
+        }
+    }
+
+    @MimeRegistration(mimeType = "text/x-java", service = 
HyperlinkTypeDefLocationProvider.class)
+    public static class TypeDefLocationProvider implements 
HyperlinkTypeDefLocationProvider {
+
+        @Override
+        public CompletableFuture<HyperlinkLocation> 
getHyperlinkTypeDefLocation(Document doc, int offset) {
+            return GoToSupport.getGoToLocation(doc, offset, true);
         }
     }
 }
diff --git a/java/java.lsp.server/nbproject/project.xml 
b/java/java.lsp.server/nbproject/project.xml
index f1992a9..901e384 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -92,7 +92,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.0</specification-version>
+                        <specification-version>1.1</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
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 d539e83..bda32ff 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
@@ -603,6 +603,7 @@ public final class Server {
                 capabilities.setCodeActionProvider(new 
CodeActionOptions(Arrays.asList(CodeActionKind.QuickFix, 
CodeActionKind.Source)));
                 capabilities.setDocumentSymbolProvider(true);
                 capabilities.setDefinitionProvider(true);
+                capabilities.setTypeDefinitionProvider(true);
                 capabilities.setImplementationProvider(true);
                 capabilities.setDocumentHighlightProvider(true);
                 capabilities.setReferencesProvider(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 b106aec..42ae0ad 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.SymbolInformation;
 import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
 import org.eclipse.lsp4j.TextDocumentEdit;
 import org.eclipse.lsp4j.TextEdit;
+import org.eclipse.lsp4j.TypeDefinitionParams;
 import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
 import org.eclipse.lsp4j.WorkspaceEdit;
 import org.eclipse.lsp4j.jsonrpc.messages.Either;
@@ -526,6 +527,29 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
     }
 
     @Override
+    public CompletableFuture<Either<List<? extends Location>, List<? extends 
LocationLink>>> typeDefinition(TypeDefinitionParams params) {
+        try {
+            String uri = params.getTextDocument().getUri();
+            Document doc = openedDocuments.get(uri);
+            if (doc != null) {
+                FileObject file = Utils.fromUri(uri);
+                if (file != null) {
+                    int offset = Utils.getOffset(doc, params.getPosition());
+                    return HyperlinkLocation.resolveTypeDefinition(doc, 
offset).thenApply(locs -> {
+                        return Either.forLeft(locs.stream().map(location -> {
+                            FileObject fo = location.getFileObject();
+                            return new Location(Utils.toUri(fo), new 
Range(Utils.createPosition(fo, location.getStartOffset()), 
Utils.createPosition(fo, location.getEndOffset())));
+                        }).collect(Collectors.toList()));
+                    });
+                }
+            }
+        } catch (MalformedURLException ex) {
+            client.logMessage(new MessageParams(MessageType.Error, 
ex.getMessage()));
+        }
+        return 
CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
+    }
+
+    @Override
     public CompletableFuture<Either<List<? extends Location>, List<? extends 
LocationLink>>> implementation(ImplementationParams params) {
         // shortcut: if the projects are not yet initialized, return empty:
         if (server.openedProjects().getNow(null) == null) {
@@ -682,7 +706,7 @@ public class TextDocumentServiceImpl implements 
TextDocumentService, LanguageCli
                     }
                 }
                 if (!sourceRoots.isEmpty()) {
-                    
query[0].getContext().add(org.netbeans.modules.refactoring.api.Scope.create(sourceRoots,
 null, null));
+                    
query[0].getContext().add(org.netbeans.modules.refactoring.api.Scope.create(sourceRoots,
 null, null, true));
                 }
                 cancelCallback[0] = () -> query[0].cancelRequest();
                 RefactoringSession refactoring = 
RefactoringSession.create("FindUsages");
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 f8f5e82..d3d6076 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
@@ -109,6 +109,7 @@ import org.eclipse.lsp4j.TextDocumentEdit;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
 import org.eclipse.lsp4j.TextDocumentItem;
 import org.eclipse.lsp4j.TextEdit;
+import org.eclipse.lsp4j.TypeDefinitionParams;
 import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
 import org.eclipse.lsp4j.WorkDoneProgressCancelParams;
 import org.eclipse.lsp4j.WorkDoneProgressCreateParams;
@@ -882,6 +883,74 @@ public class ServerTest extends NbTestCase {
         assertEquals(20, definition.get(0).getRange().getEnd().getCharacter());
     }
 
+    public void testGoToTypeDefinition() throws Exception {
+        File src = new File(getWorkDir(), "Test.java");
+        src.getParentFile().mkdirs();
+        try (Writer w = new FileWriter(new File(src.getParentFile(), 
".test-project"))) {}
+        String code = "public class Test {\n" +
+                      "    private Other field;\n" +
+                      "    public void test() {\n" +
+                      "        System.err.println(field);\n" +
+                      "    }\n" +
+                      "}\n";
+        try (Writer w = new FileWriter(src)) {
+            w.write(code);
+        }
+        File otherSrc = new File(getWorkDir(), "Other.java");
+        try (Writer w = new FileWriter(otherSrc)) {
+            w.write("/**Some source*/\n" +
+                    "public class Other {\n" +
+                    "    public void test() { }\n" +
+                    "}");
+        }
+        FileUtil.refreshFor(getWorkDir());
+        CountDownLatch indexingComplete = new CountDownLatch(1);
+        Launcher<LanguageServer> serverLauncher = 
LSPLauncher.createClientLauncher(new LspClient() {
+            @Override
+            public void telemetryEvent(Object arg0) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+
+            @Override
+            public void publishDiagnostics(PublishDiagnosticsParams params) {
+            }
+
+            @Override
+            public void showMessage(MessageParams params) {
+                if (Server.INDEXING_COMPLETED.equals(params.getMessage())) {
+                    indexingComplete.countDown();
+                } else {
+                    throw new UnsupportedOperationException("Unexpected 
message.");
+                }
+            }
+
+            @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();
+        InitializeParams initParams = new InitializeParams();
+        initParams.setRootUri(getWorkDir().toURI().toString());
+        server.initialize(initParams).get();
+        indexingComplete.await();
+        server.getTextDocumentService().didOpen(new 
DidOpenTextDocumentParams(new TextDocumentItem(toURI(src), "java", 0, code)));
+        Position pos = new Position(3, 30);
+        List<? extends Location> typeDefinition = 
server.getTextDocumentService().typeDefinition(new TypeDefinitionParams(new 
TextDocumentIdentifier(toURI(src)), pos)).get().getLeft();
+        assertEquals(1, typeDefinition.size());
+        assertEquals(toURI(otherSrc), typeDefinition.get(0).getUri());
+        assertEquals(1, typeDefinition.get(0).getRange().getStart().getLine());
+        assertEquals(13, 
typeDefinition.get(0).getRange().getStart().getCharacter());
+        assertEquals(1, typeDefinition.get(0).getRange().getEnd().getLine());
+        assertEquals(18, 
typeDefinition.get(0).getRange().getEnd().getCharacter());
+    }
+
     public void testGoToImplementations() throws Exception {
         File src = new File(getWorkDir(), "Test.java");
         src.getParentFile().mkdirs();

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