From dc03ddfc2a8da2475ba4c32e4f2a6e05b303e685 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Thu, 22 Jan 2026 17:51:14 +0100 Subject: [PATCH 1/2] Add workspace indexing progress notifications Implement LSP $/progress notifications during workspace file indexing to provide visual feedback in editors/clients. - Add progress callback parameter to ASTNodeCache.update() - Report per-file progress using AtomicInteger for thread-safe counting - Create ProgressNotification in LanguageService.update0() for multi-file updates - Show progress when indexing > 1 file (initial scan or batch updates) - Use workspace-specific token to support multiple workspaces Closes #148 --- .../java/nextflow/lsp/ast/ASTNodeCache.java | 10 +++++++- .../lsp/services/LanguageService.java | 23 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/java/nextflow/lsp/ast/ASTNodeCache.java b/src/main/java/nextflow/lsp/ast/ASTNodeCache.java index bfd44341..d0652a43 100644 --- a/src/main/java/nextflow/lsp/ast/ASTNodeCache.java +++ b/src/main/java/nextflow/lsp/ast/ASTNodeCache.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.stream.Collectors; import nextflow.lsp.compiler.LanguageServerCompiler; @@ -86,8 +88,9 @@ public void clear() { * * @param uris * @param fileCache + * @param progress optional callback to report progress as (current, total) */ - public Set update(Set uris, FileCache fileCache) { + public Set update(Set uris, FileCache fileCache, BiConsumer progress) { // invalidate cache for each source file for( var uri : uris ) { var nodes = nodesByURI.remove(uri); @@ -101,12 +104,17 @@ public Set update(Set uris, FileCache fileCache) { } // parse source files + var counter = new AtomicInteger(0); + var total = uris.size(); var sources = uris.parallelStream() .map(uri -> compiler.createSourceUnit(uri, fileCache)) .filter(sourceUnit -> sourceUnit != null) .map(sourceUnit -> { compiler.addSource(sourceUnit); compiler.compile(sourceUnit); + if( progress != null ) { + progress.accept(counter.incrementAndGet(), total); + } return sourceUnit; }) .sequential() diff --git a/src/main/java/nextflow/lsp/services/LanguageService.java b/src/main/java/nextflow/lsp/services/LanguageService.java index c21250e7..d2fc7dc2 100644 --- a/src/main/java/nextflow/lsp/services/LanguageService.java +++ b/src/main/java/nextflow/lsp/services/LanguageService.java @@ -38,6 +38,7 @@ import nextflow.lsp.util.DebouncingExecutor; import nextflow.lsp.util.LanguageServerUtils; import nextflow.lsp.util.Logger; +import nextflow.lsp.util.ProgressNotification; import nextflow.lsp.util.Positions; import nextflow.script.control.ParanoidWarning; import nextflow.script.control.RelatedInformationAware; @@ -363,14 +364,34 @@ private void update0() { log.debug(builder.toString()); } + // Create progress notification for multi-file updates + ProgressNotification progress = null; + if( uris.size() > 1 && client != null ) { + var token = "indexing-" + (rootUri != null ? rootUri.hashCode() : "default"); + progress = new ProgressNotification(client, token); + progress.create(); + progress.begin(String.format("Indexing %d files...", uris.size())); + } + try { - var changedUris = astCache.update(uris, fileCache); + final var progressNotification = progress; + var changedUris = astCache.update(uris, fileCache, + progressNotification != null + ? (current, total) -> progressNotification.update( + String.format("Indexing: %d / %d files", current, total), + current * 100 / total) + : null); publishDiagnostics(changedUris); } catch( Throwable e ) { System.err.println(e); e.printStackTrace(); } + finally { + if( progress != null ) { + progress.end(); + } + } } /** From dea95726d646220d81a5ceccd6d9e185801ce407 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Fri, 23 Jan 2026 00:55:12 +0100 Subject: [PATCH 2/2] Add progress notification methods to TestLanguageClient The new progress notification feature requires the LanguageClient to support createProgress() and notifyProgress() methods. Added no-op implementations to TestLanguageClient to prevent UnsupportedOperationException during tests. --- .../groovy/nextflow/lsp/TestLanguageClient.groovy | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/groovy/nextflow/lsp/TestLanguageClient.groovy b/src/test/groovy/nextflow/lsp/TestLanguageClient.groovy index 8383057d..49a736df 100644 --- a/src/test/groovy/nextflow/lsp/TestLanguageClient.groovy +++ b/src/test/groovy/nextflow/lsp/TestLanguageClient.groovy @@ -20,8 +20,10 @@ import java.util.concurrent.CompletableFuture import org.eclipse.lsp4j.MessageActionItem import org.eclipse.lsp4j.MessageParams +import org.eclipse.lsp4j.ProgressParams import org.eclipse.lsp4j.PublishDiagnosticsParams import org.eclipse.lsp4j.ShowMessageRequestParams +import org.eclipse.lsp4j.WorkDoneProgressCreateParams import org.eclipse.lsp4j.services.LanguageClient /** @@ -51,4 +53,14 @@ class TestLanguageClient implements LanguageClient { public void logMessage(MessageParams message) { System.err.println(message.getMessage()) } + + @Override + public CompletableFuture createProgress(WorkDoneProgressCreateParams params) { + return CompletableFuture.completedFuture(null) + } + + @Override + public void notifyProgress(ProgressParams params) { + // No-op for tests + } }