Skip to content

Commit 4f3848a

Browse files
committed
Resolve plugin definitions from registry
1 parent f15d57c commit 4f3848a

14 files changed

+531
-45
lines changed

src/main/java/nextflow/lsp/NextflowLanguageServer.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ public static void main(String[] args) {
121121
private LanguageClient client = null;
122122

123123
private Map<String, String> workspaceRoots = new HashMap<>();
124-
private Map<String, LanguageService> scriptServices = new HashMap<>();
125-
private Map<String, LanguageService> configServices = new HashMap<>();
124+
private Map<String, ConfigService> configServices = new HashMap<>();
125+
private Map<String, ScriptService> scriptServices = new HashMap<>();
126126

127127
private LanguageServerConfiguration configuration = LanguageServerConfiguration.defaults();
128128

@@ -461,6 +461,7 @@ public void didChangeConfiguration(DidChangeConfigurationParams params) {
461461
withDefault(JsonUtils.getBoolean(settings, "nextflow.formatting.harshilAlignment"), configuration.harshilAlignment()),
462462
withDefault(JsonUtils.getBoolean(settings, "nextflow.formatting.maheshForm"), configuration.maheshForm()),
463463
withDefault(JsonUtils.getInteger(settings, "nextflow.completion.maxItems"), configuration.maxCompletionItems()),
464+
withDefault(JsonUtils.getString(settings, "nextflow.pluginRegistryUrl"), configuration.pluginRegistryUrl()),
464465
withDefault(JsonUtils.getBoolean(settings, "nextflow.formatting.sortDeclarations"), configuration.sortDeclarations()),
465466
withDefault(JsonUtils.getBoolean(settings, "nextflow.typeChecking"), configuration.typeChecking())
466467
);
@@ -500,8 +501,8 @@ private void initializeWorkspaces() {
500501
progress.update(progressMessage, count * 100 / total);
501502
count++;
502503

503-
scriptServices.get(name).initialize(configuration);
504504
configServices.get(name).initialize(configuration);
505+
scriptServices.get(name).initialize(configuration, configServices.get(name).getPluginSpecCache());
505506
}
506507

507508
progress.end();
@@ -519,16 +520,16 @@ public void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) {
519520
var name = workspaceFolder.getName();
520521
log.debug("workspace/didChangeWorkspaceFolders remove " + name);
521522
workspaceRoots.remove(name);
522-
scriptServices.remove(name).clearDiagnostics();
523523
configServices.remove(name).clearDiagnostics();
524+
scriptServices.remove(name).clearDiagnostics();
524525
}
525526
for( var workspaceFolder : event.getAdded() ) {
526527
var name = workspaceFolder.getName();
527528
var uri = workspaceFolder.getUri();
528529
log.debug("workspace/didChangeWorkspaceFolders add " + name + " " + uri);
529530
addWorkspaceFolder(name, uri);
530-
scriptServices.get(name).initialize(configuration);
531531
configServices.get(name).initialize(configuration);
532+
scriptServices.get(name).initialize(configuration, configServices.get(name).getPluginSpecCache());
532533
}
533534
}
534535

@@ -620,13 +621,13 @@ public CompletableFuture<Either<List<? extends SymbolInformation>, List<? extend
620621
private void addWorkspaceFolder(String name, String uri) {
621622
workspaceRoots.put(name, uri);
622623

623-
var scriptService = new ScriptService(uri);
624-
scriptService.connect(client);
625-
scriptServices.put(name, scriptService);
626-
627624
var configService = new ConfigService(uri);
628625
configService.connect(client);
629626
configServices.put(name, configService);
627+
628+
var scriptService = new ScriptService(uri);
629+
scriptService.connect(client);
630+
scriptServices.put(name, scriptService);
630631
}
631632

632633
private String relativePath(String uri) {
@@ -654,12 +655,12 @@ private LanguageService getLanguageService(String uri) {
654655
return service;
655656
}
656657

657-
private LanguageService getLanguageService0(String uri, Map<String, LanguageService> services) {
658+
private LanguageService getLanguageService0(String uri, Map<String, ? extends LanguageService> services) {
658659
var service = workspaceRoots.entrySet().stream()
659660
.filter((entry) -> entry.getValue() != null && uri.startsWith(entry.getValue()))
660661
.findFirst()
661-
.map((entry) -> services.get(entry.getKey()))
662-
.orElse(services.get(DEFAULT_WORKSPACE_FOLDER_NAME));
662+
.map((entry) -> (LanguageService) services.get(entry.getKey()))
663+
.orElse((LanguageService) services.get(DEFAULT_WORKSPACE_FOLDER_NAME));
663664
if( service == null || !service.matchesFile(uri) )
664665
return null;
665666
return service;

src/main/java/nextflow/lsp/services/LanguageServerConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public record LanguageServerConfiguration(
2727
boolean harshilAlignment,
2828
boolean maheshForm,
2929
int maxCompletionItems,
30+
String pluginRegistryUrl,
3031
boolean sortDeclarations,
3132
boolean typeChecking
3233
) {
@@ -41,6 +42,7 @@ public static LanguageServerConfiguration defaults() {
4142
false,
4243
false,
4344
100,
45+
"https://registry.nextflow.io/api/",
4446
false,
4547
false
4648
);

src/main/java/nextflow/lsp/services/config/ConfigAstCache.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Set;
2222

2323
import groovy.lang.GroovyClassLoader;
24+
import nextflow.config.ast.ConfigNode;
2425
import nextflow.config.control.ConfigResolveVisitor;
2526
import nextflow.config.control.ResolveIncludeVisitor;
2627
import nextflow.config.parser.ConfigParserPluginFactory;
@@ -30,6 +31,7 @@
3031
import nextflow.lsp.compiler.LanguageServerErrorCollector;
3132
import nextflow.lsp.file.FileCache;
3233
import nextflow.lsp.services.LanguageServerConfiguration;
34+
import nextflow.lsp.spec.PluginSpecCache;
3335
import nextflow.script.control.PhaseAware;
3436
import nextflow.script.control.Phases;
3537
import nextflow.script.types.Types;
@@ -46,7 +48,7 @@ public class ConfigAstCache extends ASTNodeCache {
4648

4749
private LanguageServerConfiguration configuration;
4850

49-
private Map<String,SpecNode> spec = ConfigSpecFactory.defaultScopes();
51+
private PluginSpecCache pluginSpecCache;
5052

5153
public ConfigAstCache() {
5254
super(createCompiler());
@@ -65,8 +67,9 @@ private static CompilerConfiguration createConfiguration() {
6567
return config;
6668
}
6769

68-
public void initialize(LanguageServerConfiguration configuration) {
70+
public void initialize(LanguageServerConfiguration configuration, PluginSpecCache pluginSpecCache) {
6971
this.configuration = configuration;
72+
this.pluginSpecCache = pluginSpecCache;
7073
}
7174

7275
@Override
@@ -92,7 +95,7 @@ protected Set<URI> analyze(Set<URI> uris, FileCache fileCache) {
9295
continue;
9396
// phase 3: name checking
9497
new ConfigResolveVisitor(sourceUnit, compiler().compilationUnit(), Types.DEFAULT_CONFIG_IMPORTS).visit();
95-
new ConfigSpecVisitor(sourceUnit, spec, configuration.typeChecking()).visit();
98+
new ConfigSpecVisitor(sourceUnit, pluginSpecCache, configuration.typeChecking()).visit();
9699
if( sourceUnit.getErrorCollector().hasErrors() )
97100
continue;
98101
// phase 4: type checking
@@ -121,4 +124,8 @@ public boolean hasSyntaxErrors(URI uri) {
121124
.isPresent();
122125
}
123126

127+
public ConfigNode getConfigNode(URI uri) {
128+
return (ConfigNode) getSourceUnit(uri).getAST();
129+
}
130+
124131
}

src/main/java/nextflow/lsp/services/config/ConfigCompletionProvider.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import nextflow.config.ast.ConfigIncompleteNode;
2626
import nextflow.config.dsl.ConfigDsl;
2727
import nextflow.config.spec.SpecNode;
28-
import nextflow.lsp.ast.ASTNodeCache;
2928
import nextflow.lsp.ast.CompletionHelper;
3029
import nextflow.lsp.services.CompletionProvider;
3130
import nextflow.lsp.util.Logger;
@@ -62,14 +61,12 @@
6261
*/
6362
public class ConfigCompletionProvider implements CompletionProvider {
6463

65-
private static final List<CompletionItem> TOPLEVEL_ITEMS = topLevelItems();
66-
6764
private static Logger log = Logger.getInstance();
6865

69-
private ASTNodeCache ast;
66+
private ConfigAstCache ast;
7067
private CompletionHelper ch;
7168

72-
public ConfigCompletionProvider(ASTNodeCache ast, int maxItems) {
69+
public ConfigCompletionProvider(ConfigAstCache ast, int maxItems) {
7370
this.ast = ast;
7471
this.ch = new CompletionHelper(maxItems);
7572
}
@@ -86,17 +83,18 @@ public Either<List<CompletionItem>, CompletionList> completion(TextDocumentIdent
8683
return Either.forLeft(Collections.emptyList());
8784

8885
var nodeStack = ast.getNodesAtPosition(uri, position);
86+
var spec = ast.getConfigNode(uri).getSpec();
8987
if( nodeStack.isEmpty() )
90-
return Either.forLeft(TOPLEVEL_ITEMS);
88+
return Either.forLeft(topLevelItems(spec));
9189

9290
if( isConfigExpression(nodeStack) ) {
9391
addCompletionItems(nodeStack);
9492
}
9593
else {
9694
var names = currentConfigScope(nodeStack);
9795
if( names.isEmpty() )
98-
return Either.forLeft(TOPLEVEL_ITEMS);
99-
addConfigOptions(names);
96+
return Either.forLeft(topLevelItems(spec));
97+
addConfigOptions(names, spec);
10098
}
10199

102100
return ch.isIncomplete()
@@ -179,8 +177,8 @@ private static List<String> currentConfigScope(List<ASTNode> nodeStack) {
179177
return names;
180178
}
181179

182-
private void addConfigOptions(List<String> names) {
183-
var scope = SpecNode.ROOT.getScope(names);
180+
private void addConfigOptions(List<String> names, SpecNode.Scope spec) {
181+
var scope = spec.getScope(names);
184182
if( scope == null )
185183
return;
186184
scope.children().forEach((name, child) -> {
@@ -191,9 +189,9 @@ private void addConfigOptions(List<String> names) {
191189
});
192190
}
193191

194-
private static List<CompletionItem> topLevelItems() {
192+
private static List<CompletionItem> topLevelItems(SpecNode.Scope spec) {
195193
var result = new ArrayList<CompletionItem>();
196-
SpecNode.ROOT.children().forEach((name, child) -> {
194+
spec.children().forEach((name, child) -> {
197195
if( child instanceof SpecNode.Option option ) {
198196
result.add(configOption(name, option.description(), option.type()));
199197
}

src/main/java/nextflow/lsp/services/config/ConfigHoverProvider.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import nextflow.config.ast.ConfigAssignNode;
2424
import nextflow.config.ast.ConfigBlockNode;
2525
import nextflow.config.spec.SpecNode;
26-
import nextflow.lsp.ast.ASTNodeCache;
2726
import nextflow.lsp.ast.ASTNodeStringUtils;
2827
import nextflow.lsp.ast.LanguageServerASTUtils;
2928
import nextflow.lsp.services.HoverProvider;
@@ -49,9 +48,9 @@ public class ConfigHoverProvider implements HoverProvider {
4948

5049
private static Logger log = Logger.getInstance();
5150

52-
private ASTNodeCache ast;
51+
private ConfigAstCache ast;
5352

54-
public ConfigHoverProvider(ASTNodeCache ast) {
53+
public ConfigHoverProvider(ConfigAstCache ast) {
5554
this.ast = ast;
5655
}
5756

@@ -69,7 +68,7 @@ public Hover hover(TextDocumentIdentifier textDocument, Position position) {
6968

7069
var builder = new StringBuilder();
7170

72-
var content = getHoverContent(nodeStack);
71+
var content = getHoverContent(nodeStack, ast.getConfigNode(uri).getSpec());
7372
if( content != null ) {
7473
builder.append(content);
7574
builder.append('\n');
@@ -94,14 +93,14 @@ public Hover hover(TextDocumentIdentifier textDocument, Position position) {
9493
return new Hover(new MarkupContent(MarkupKind.MARKDOWN, value));
9594
}
9695

97-
protected String getHoverContent(List<ASTNode> nodeStack) {
96+
protected String getHoverContent(List<ASTNode> nodeStack, SpecNode.Scope spec) {
9897
var offsetNode = nodeStack.get(0);
9998
if( offsetNode instanceof ConfigAssignNode assign ) {
10099
var names = getCurrentScope(nodeStack);
101100
names.addAll(assign.names);
102101

103102
var fqName = String.join(".", names);
104-
var option = SpecNode.ROOT.getOption(names);
103+
var option = spec.getOption(names);
105104
if( option != null ) {
106105
var description = StringGroovyMethods.stripIndent(option.description(), true).trim();
107106
var builder = new StringBuilder();
@@ -120,7 +119,7 @@ else if( Logger.isDebugEnabled() ) {
120119
if( names.isEmpty() )
121120
return null;
122121

123-
var scope = SpecNode.ROOT.getChild(names);
122+
var scope = spec.getChild(names);
124123
if( scope != null ) {
125124
return StringGroovyMethods.stripIndent(scope.description(), true).trim();
126125
}

src/main/java/nextflow/lsp/services/config/ConfigService.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import nextflow.lsp.services.LanguageService;
2424
import nextflow.lsp.services.LinkProvider;
2525
import nextflow.lsp.services.SemanticTokensProvider;
26+
import nextflow.lsp.spec.PluginSpecCache;
2627

2728
/**
2829
* Implementation of language services for Nextflow config files.
@@ -31,6 +32,8 @@
3132
*/
3233
public class ConfigService extends LanguageService {
3334

35+
private PluginSpecCache pluginSpecCache;
36+
3437
private ConfigAstCache astCache;
3538

3639
public ConfigService(String rootUri) {
@@ -46,11 +49,16 @@ public boolean matchesFile(String uri) {
4649
@Override
4750
public void initialize(LanguageServerConfiguration configuration) {
4851
synchronized (this) {
49-
astCache.initialize(configuration);
52+
pluginSpecCache = new PluginSpecCache(configuration.pluginRegistryUrl());
53+
astCache.initialize(configuration, pluginSpecCache);
5054
}
5155
super.initialize(configuration);
5256
}
5357

58+
public PluginSpecCache getPluginSpecCache() {
59+
return pluginSpecCache;
60+
}
61+
5462
@Override
5563
protected ASTNodeCache getAstCache() {
5664
return astCache;

0 commit comments

Comments
 (0)