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