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 836fea4927 Enable Micronaut HyperlinkProviders - deadlocks fixed. 
(#5991)
836fea4927 is described below

commit 836fea49272478fe787afa85f0ecf13a76dadde4
Author: Dusan Balek <dusan.ba...@oracle.com>
AuthorDate: Mon May 29 13:29:13 2023 +0200

    Enable Micronaut HyperlinkProviders - deadlocks fixed. (#5991)
---
 .../micronaut/MicronautConfigUtilities.java        |  94 +++++++++++++-----
 .../MicronautConfigCompletionCollector.java        |   4 +-
 .../MicronautConfigCompletionProvider.java         |   4 +-
 .../completion/MicronautConfigCompletionTask.java  |   3 +-
 .../completion/MicronautHoverProvider.java         |   4 +-
 .../MicronautConfigHyperlinkProvider.java          | 110 ++++++++++++++++++---
 6 files changed, 179 insertions(+), 40 deletions(-)

diff --git 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java
 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java
index 1d5c8c701d..75887a4645 100644
--- 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java
+++ 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java
@@ -23,7 +23,9 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Stack;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import javax.swing.text.Document;
@@ -58,6 +60,9 @@ public class MicronautConfigUtilities {
 
     private static final Pattern REGEXP = 
Pattern.compile("^(application|bootstrap)(-\\w*)*\\.(yml|properties)$", 
Pattern.CASE_INSENSITIVE);
 
+    public static final String YAML_MIME = "text/x-yaml";
+    public static final String PROPERTIES_MIME = "text/x-properties";
+
     public static boolean isMicronautConfigFile(FileObject fo) {
         return fo != null && REGEXP.matcher(fo.getNameExt()).matches();
     }
@@ -73,7 +78,7 @@ public class MicronautConfigUtilities {
                         try {
                             int lineStart = 
LineDocumentUtils.getLineStart(lineDocument, offset);
                             String mimeType = 
DocumentUtilities.getMimeType(doc);
-                            if ("text/x-yaml".equals(mimeType)) {
+                            if (YAML_MIME.equals(mimeType)) {
                                 String text = lineDocument.getText(lineStart, 
offset - lineStart);
                                 if (!text.startsWith("#")) {
                                     int idx = text.indexOf(':');
@@ -98,26 +103,7 @@ public class MicronautConfigUtilities {
                                                                     span[1] = 
end;
                                                                 }
                                                                 if (start <= 
offset && offset <= end && item.getName().equals(lineDocument.getText(start, 
end - start))) {
-                                                                    String 
propertyName = getPropertyName(context);
-                                                                    for 
(Map.Entry<String, ConfigurationMetadataGroup> groupEntry : 
MicronautConfigProperties.getGroups(project).entrySet()) {
-                                                                        String 
groupKey = groupEntry.getKey();
-                                                                        if 
(groupKey.endsWith(".*")) {
-                                                                            
groupKey = groupKey.substring(0, groupKey.length() - 2);
-                                                                        }
-                                                                        if 
(Pattern.matches(groupKey.replaceAll("\\.", "\\\\.").replaceAll("\\*", 
"\\\\w*") + ".*", propertyName)) {
-                                                                            
ConfigurationMetadataGroup group = groupEntry.getValue();
-                                                                            if 
(sources != null) {
-                                                                               
 sources.addAll(group.getSources().values());
-                                                                            }
-                                                                            
for (Map.Entry<String, ConfigurationMetadataProperty> propertyEntry : 
group.getProperties().entrySet()) {
-                                                                               
 String propertyKey = propertyEntry.getKey();
-                                                                               
 if (Pattern.matches(propertyKey.replaceAll("\\.", "\\\\.").replaceAll("\\*", 
"\\\\w*"), propertyName)) {
-                                                                               
     property[0] = propertyEntry.getValue();
-                                                                               
     return;
-                                                                               
 }
-                                                                            }
-                                                                        }
-                                                                    }
+                                                                    
property[0] = getProperty(MicronautConfigProperties.getGroups(project), 
getPropertyName(context), sources);
                                                                 }
                                                             }
                                                         }
@@ -180,7 +166,7 @@ public class MicronautConfigUtilities {
     public static void collectUsages(FileObject fo, String propertyName, 
Consumer<Usage> consumer) {
         try {
             String mimeType = fo.getMIMEType();
-            if ("text/x-yaml".equals(mimeType)) {
+            if (YAML_MIME.equals(mimeType)) {
                 ParserManager.parse(Collections.singleton(Source.create(fo)), 
new UserTask() {
                     public @Override void run(ResultIterator resultIterator) 
throws Exception {
                         Parser.Result r = resultIterator.getParserResult();
@@ -211,6 +197,70 @@ public class MicronautConfigUtilities {
             Exceptions.printStackTrace(ex);
         }
     }
+    
+    public static List<int[]> getPropertySpans(Project project, Parser.Result 
r) {
+        List<int[]> spans = new ArrayList<>();
+        if (r instanceof ParserResult) {
+            Language language = 
LanguageRegistry.getInstance().getLanguageByMimeType(r.getSnapshot().getMimeType());
+            if (language != null) {
+                StructureScanner scanner = language.getStructure();
+                if (scanner != null) {
+                    Map<String, ConfigurationMetadataGroup> groups = 
MicronautConfigProperties.getGroups(project);
+                    scan(scanner.scan((ParserResult) r), new Stack<>(), 
context -> {
+                        if (!context.empty()) {
+                            String propertyName = getPropertyName(context);
+                            List<ConfigurationMetadataSource> sources = new 
ArrayList<>();
+                            ConfigurationMetadataProperty property = 
getProperty(groups, propertyName, sources);
+                            if (property != null || !sources.isEmpty()) {
+                                StructureItem item = context.peek();
+                                spans.add(new int[] {(int) item.getPosition(), 
(int) item.getPosition() + item.getName().length()});
+                            }
+                        }
+                        return true;
+                    });
+                }
+            }
+        }
+        return spans;
+    }
+    
+    private static ConfigurationMetadataProperty getProperty(Map<String, 
ConfigurationMetadataGroup> groups, String propertyName, 
List<ConfigurationMetadataSource> sources) {
+        for (Map.Entry<String, ConfigurationMetadataGroup> groupEntry : 
groups.entrySet()) {
+            String groupKey = groupEntry.getKey();
+            if (groupKey.endsWith(".*")) {
+                groupKey = groupKey.substring(0, groupKey.length() - 2);
+            }
+            if (Pattern.matches(groupKey.replaceAll("\\.", 
"\\\\.").replaceAll("\\*", "\\\\w*") + ".*", propertyName)) {
+                ConfigurationMetadataGroup group = groupEntry.getValue();
+                if (sources != null) {
+                    sources.addAll(group.getSources().values());
+                }
+                for (Map.Entry<String, ConfigurationMetadataProperty> 
propertyEntry : group.getProperties().entrySet()) {
+                    String propertyKey = propertyEntry.getKey();
+                    if (Pattern.matches(propertyKey.replaceAll("\\.", 
"\\\\.").replaceAll("\\*", "\\\\w*"), propertyName)) {
+                        return propertyEntry.getValue();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private static void scan(List<? extends StructureItem> structures, 
Stack<StructureItem> context, Function<Stack<StructureItem>, Boolean> visitor) {
+        for (StructureItem structure : structures) {
+            if (structure != null) {
+                try {
+                    context.push(structure);
+                    if (visitor.apply(context)) {
+                        scan(structure.getNestedItems(), context, visitor);
+                    }
+                } finally {
+                    context.pop();
+                }
+            }
+        }
+    }
+
 
     private static void find(FileObject fo, String propertyName, List<? 
extends StructureItem> structures, CharSequence content, Consumer<Usage> 
consumer) {
         int idx = propertyName.indexOf('.');
diff --git 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
index 893f858898..4a5b511a26 100644
--- 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
+++ 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
@@ -38,12 +38,12 @@ import 
org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
  */
 public class MicronautConfigCompletionCollector implements CompletionCollector 
{
 
-    @MimeRegistration(mimeType = "text/x-yaml", service = 
CompletionCollector.class)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, service = 
CompletionCollector.class)
     public static MicronautConfigCompletionCollector createYamlCollector() {
         return new MicronautConfigCompletionCollector();
     }
 
-    @MimeRegistration(mimeType = "text/x-properties", service = 
CompletionCollector.class)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.PROPERTIES_MIME, 
service = CompletionCollector.class)
     public static MicronautConfigCompletionCollector 
createPropertiesCollector() {
         return new MicronautConfigCompletionCollector();
     }
diff --git 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
index f5417bb0ea..b51e122b68 100644
--- 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
+++ 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
@@ -55,12 +55,12 @@ public class MicronautConfigCompletionProvider implements 
CompletionProvider {
 
     public static final String PROPERTY_NAME_COLOR = getHTMLColor(64, 64, 217);
 
-    @MimeRegistration(mimeType = "text/x-yaml", service = 
CompletionProvider.class)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, service = 
CompletionProvider.class)
     public static MicronautConfigCompletionProvider createYamlProvider() {
         return new MicronautConfigCompletionProvider();
     }
 
-    @MimeRegistration(mimeType = "text/x-properties", service = 
CompletionProvider.class)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.PROPERTIES_MIME, 
service = CompletionProvider.class)
     public static MicronautConfigCompletionProvider createPropertiesProvider() 
{
         return new MicronautConfigCompletionProvider();
     }
diff --git 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java
 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java
index bcd5031d42..646984d920 100644
--- 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java
+++ 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java
@@ -50,6 +50,7 @@ import org.netbeans.modules.csl.core.LanguageRegistry;
 import org.netbeans.modules.csl.spi.ParserResult;
 import org.netbeans.modules.editor.indent.api.IndentUtils;
 import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.netbeans.modules.micronaut.MicronautConfigUtilities;
 import org.netbeans.modules.parsing.api.ParserManager;
 import org.netbeans.modules.parsing.api.ResultIterator;
 import org.netbeans.modules.parsing.api.Source;
@@ -78,7 +79,7 @@ public class MicronautConfigCompletionTask {
             try {
                 String text = lineDocument.getText(lineStart, caretOffset - 
lineStart);
                 String mimeType = DocumentUtilities.getMimeType(doc);
-                if ("text/x-yaml".equals(mimeType)) {
+                if (MicronautConfigUtilities.YAML_MIME.equals(mimeType)) {
                     if (!text.startsWith("#")) {
                         int idx = text.indexOf(':');
                         if (idx < 0) {
diff --git 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautHoverProvider.java
 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautHoverProvider.java
index be2299be6f..91f7abf222 100644
--- 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautHoverProvider.java
+++ 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautHoverProvider.java
@@ -31,12 +31,12 @@ import 
org.springframework.boot.configurationmetadata.ConfigurationMetadataPrope
  */
 public class MicronautHoverProvider implements HoverProvider {
 
-    @MimeRegistration(mimeType = "text/x-yaml", service = HoverProvider.class)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, service = 
HoverProvider.class)
     public static MicronautHoverProvider createYamlProvider() {
         return new MicronautHoverProvider();
     }
 
-    @MimeRegistration(mimeType = "text/x-properties", service = 
HoverProvider.class)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.PROPERTIES_MIME, 
service = HoverProvider.class)
     public static MicronautHoverProvider createPropertiesProvider() {
         return new MicronautHoverProvider();
     }
diff --git 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java
 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java
index c10dc9d513..dc2e66ee3b 100644
--- 
a/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java
+++ 
b/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java
@@ -21,6 +21,8 @@ package org.netbeans.modules.micronaut.hyperlink;
 import java.awt.Toolkit;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
@@ -42,28 +44,41 @@ import org.netbeans.api.java.source.JavaSource;
 import org.netbeans.api.java.source.ui.ElementOpen;
 import org.netbeans.api.lsp.HyperlinkLocation;
 import org.netbeans.api.progress.BaseProgressUtils;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
 import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt;
 import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
+import org.netbeans.lib.editor.util.swing.DocumentUtilities;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
 import org.netbeans.modules.micronaut.MicronautConfigUtilities;
+import org.netbeans.modules.parsing.api.Snapshot;
+import org.netbeans.modules.parsing.spi.IndexingAwareParserResultTask;
+import org.netbeans.modules.parsing.spi.Parser;
+import org.netbeans.modules.parsing.spi.Scheduler;
+import org.netbeans.modules.parsing.spi.SchedulerEvent;
+import org.netbeans.modules.parsing.spi.SchedulerTask;
+import org.netbeans.modules.parsing.spi.TaskFactory;
+import org.netbeans.modules.parsing.spi.TaskIndexingMode;
 import org.netbeans.spi.lsp.HyperlinkLocationProvider;
+import org.openide.filesystems.FileObject;
 import org.openide.util.NbBundle;
 import 
org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
 import 
org.springframework.boot.configurationmetadata.ConfigurationMetadataSource;
 
 /**
- * CURRENTLY NOT ACTIVE - @MimeRegistration DISABLED to work around 
- * <a href="https://github.com/apache/netbeans/issues/3913";>GITHUB-3913</a>
- *
+ * 
  * @author Dusan Balek
  */
 public class MicronautConfigHyperlinkProvider implements HyperlinkProviderExt {
 
-    //@MimeRegistration(mimeType = "text/x-yaml", service = 
HyperlinkProviderExt.class, position = 1250)
+    private static final String SPANS_PROPERTY_NAME = 
"MicronautConfigHyperlinkSpans";
+
+    @MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, service = 
HyperlinkProviderExt.class, position = 1250)
     public static MicronautConfigHyperlinkProvider createYamlProvider() {
         return new MicronautConfigHyperlinkProvider();
     }
 
-    //@MimeRegistration(mimeType = "text/x-properties", service = 
HyperlinkProviderExt.class, position = 1250)
+    @MimeRegistration(mimeType = MicronautConfigUtilities.PROPERTIES_MIME, 
service = HyperlinkProviderExt.class, position = 1250)
     public static MicronautConfigHyperlinkProvider createPropertiesProvider() {
         return new MicronautConfigHyperlinkProvider();
     }
@@ -80,10 +95,26 @@ public class MicronautConfigHyperlinkProvider implements 
HyperlinkProviderExt {
 
     @Override
     public int[] getHyperlinkSpan(Document doc, int offset, HyperlinkType 
type) {
-        int[] span = new int[2];
-        List<ConfigurationMetadataSource> sources = new ArrayList<>();
-        ConfigurationMetadataProperty property = 
MicronautConfigUtilities.resolveProperty(doc, offset, span, sources);
-        return property != null || !sources.isEmpty() ? span : null;
+        String mimeType = DocumentUtilities.getMimeType(doc);
+        if (MicronautConfigUtilities.YAML_MIME.equals(mimeType)) {
+            List<int[]> spans = null;
+            synchronized (doc) {
+                spans = (List<int[]>) doc.getProperty(SPANS_PROPERTY_NAME);
+            }
+            if (spans != null) {
+                for (int[] span : spans) {
+                    if (span.length == 2 && span[0] <= offset && offset <= 
span[1]) {
+                        return span;
+                    }
+                }
+            }
+            return null;
+        } else {
+            int[] span = new int[2];
+            List<ConfigurationMetadataSource> sources = new ArrayList<>();
+            ConfigurationMetadataProperty property = 
MicronautConfigUtilities.resolveProperty(doc, offset, span, sources);
+            return property != null || !sources.isEmpty() ? span : null;
+        }
     }
 
     @Override
@@ -133,6 +164,7 @@ public class MicronautConfigHyperlinkProvider implements 
HyperlinkProviderExt {
                         if (cancel != null && cancel.get()) {
                             return;
                         }
+                        controller.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
                         TypeElement te = (TypeElement) 
handle[0].resolve(controller);
                         if (te != null) {
                             ElementHandle found = null;
@@ -169,14 +201,70 @@ public class MicronautConfigHyperlinkProvider implements 
HyperlinkProviderExt {
         return handle[0];
     }
 
+    public static final class Task extends 
IndexingAwareParserResultTask<Parser.Result> {
+    
+        private final AtomicBoolean cancel = new AtomicBoolean();
+        private final Project project;
+
+        public Task(Project project) {
+            super(TaskIndexingMode.ALLOWED_DURING_SCAN);
+            this.project = project;
+        }
+
+        @Override
+        public void run(Parser.Result result, SchedulerEvent event) {
+            if (cancel.get()) {
+                return;
+            }
+            Document doc = result.getSnapshot().getSource().getDocument(false);
+            if (doc != null) {
+                List<int[]> spans = 
MicronautConfigUtilities.getPropertySpans(project, result);
+                synchronized (doc) {
+                    doc.putProperty(SPANS_PROPERTY_NAME, spans);
+                }
+            }
+        }
+
+        @Override
+        public int getPriority() {
+            return 200;
+        }
+
+        @Override
+        public Class<? extends Scheduler> getSchedulerClass() {
+            return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
+        }
+
+        @Override
+        public void cancel() {
+            cancel.set(true);
+        }
+
+        @MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, 
service = TaskFactory.class)
+        public static final class Factory extends TaskFactory {
+
+            @Override
+            public Collection<? extends SchedulerTask> create(Snapshot 
snapshot) {
+                FileObject fo = snapshot.getSource().getFileObject();
+                if (MicronautConfigUtilities.isMicronautConfigFile(fo)) {
+                    Project project = FileOwnerQuery.getOwner(fo);
+                    if (project != null && 
MicronautConfigProperties.hasConfigMetadata(project)) {
+                        return Collections.singleton(new Task(project));
+                    }
+                }
+                return Collections.emptySet();
+            }
+        }
+    }
+
     public static class LocationProvider implements HyperlinkLocationProvider {
 
-        //@MimeRegistration(mimeType = "text/x-yaml", service = 
HyperlinkLocationProvider.class)
+        @MimeRegistration(mimeType = MicronautConfigUtilities.YAML_MIME, 
service = HyperlinkLocationProvider.class)
         public static LocationProvider createYamlProvider() {
             return new LocationProvider();
         }
 
-        //@MimeRegistration(mimeType = "text/x-properties", service = 
HyperlinkLocationProvider.class)
+        @MimeRegistration(mimeType = MicronautConfigUtilities.PROPERTIES_MIME, 
service = HyperlinkLocationProvider.class)
         public static LocationProvider createPropertiesProvider() {
             return new LocationProvider();
         }


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