Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
01fa185
Keep track of opened files with unknown extension.
toinehartman Oct 1, 2025
ec1363b
Check for valid state before getting files.
toinehartman Oct 1, 2025
2d7b93c
Use dummy parser instead of separate open file bookkeeping.
toinehartman Oct 2, 2025
ce5aee8
Reset parser.
toinehartman Oct 2, 2025
ab6e7c6
Simplify updating open files.
toinehartman Oct 6, 2025
1a0da53
Re-use newly introduced language helpers.
toinehartman Oct 6, 2025
8d8b675
Merge remote-tracking branch 'origin/main' into fix/795-open-register…
toinehartman Oct 6, 2025
65bd32f
Replace state instead of updating parser.
toinehartman Oct 6, 2025
e9f791a
Exception instead of incomplete future.
toinehartman Oct 9, 2025
bee0669
Merge remote-tracking branch 'origin/main' into fix/795-open-register…
toinehartman Oct 9, 2025
37c816c
Prevent 'no such file' errors using dummy contribution.
toinehartman Oct 13, 2025
da179cf
Clean up declarations & imports.
toinehartman Oct 13, 2025
eaa412f
Prevent 'no such file' errors on analysis.
toinehartman Oct 13, 2025
80b9fd3
Register extension after contibution registration is done.
toinehartman Oct 13, 2025
efaa03c
Merge remote-tracking branch 'origin/main' into fix/795-open-register…
toinehartman Oct 13, 2025
261bf55
Extract updating file state to functions.
toinehartman Oct 13, 2025
cfebe65
Properly log analyzer triggers.
toinehartman Oct 13, 2025
b6380dd
Reset language ID to re-trigger contributions.
toinehartman Oct 14, 2025
eb973f0
Rewrite optional mapping.
toinehartman Oct 14, 2025
74b8451
Merge remote-tracking branch 'origin/main' into fix/795-open-register…
toinehartman Oct 14, 2025
252608f
Log port number when server fails.
toinehartman Oct 14, 2025
edb3302
Use precise replace to prevent races.
toinehartman Oct 14, 2025
82b5b98
Bump log level.
toinehartman Oct 14, 2025
73a479e
Document NoContributions.
toinehartman Oct 14, 2025
6485415
Fix SQ issues.
toinehartman Oct 14, 2025
c050228
Handle case where didClose or registerLanguage races with parser update.
toinehartman Oct 15, 2025
f9b8582
Fixes from review by @DavyLandman.
toinehartman Oct 15, 2025
4781d0c
Associate empty contributions with extension.
toinehartman Oct 15, 2025
27a6410
Throw exceptions on methods that are not intended to be called.
toinehartman Oct 15, 2025
756bb02
Merge remote-tracking branch 'origin/main' into fix/795-open-register…
toinehartman Oct 15, 2025
e20ddde
Refactor and fix SQ warnings.
toinehartman Oct 15, 2025
0e1ac0d
Revert "Throw exceptions on methods that are not intended to be called."
toinehartman Oct 15, 2025
6e9be85
Do not wrap exceptions in futures.
toinehartman Oct 15, 2025
61108eb
Merge remote-tracking branch 'origin/main' into fix/795-open-register…
toinehartman Oct 20, 2025
eb1f73b
Make sure to always complete tree future.
toinehartman Oct 20, 2025
93bd8ad
Revert changes to state computation.
toinehartman Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
import org.rascalmpl.library.lang.json.internal.JsonValueReader;
import org.rascalmpl.library.lang.json.internal.JsonValueWriter;
import org.rascalmpl.library.util.PathConfig;
import org.rascalmpl.uri.URIResolverRegistry;
import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.vscode.lsp.log.LogRedirectConfiguration;
import org.rascalmpl.vscode.lsp.terminal.ITerminalIDEServer.LanguageParameter;
Expand Down Expand Up @@ -219,7 +218,6 @@ private static void startLSP(Launcher<IBaseLanguageClient> server) {
}
private static class ActualLanguageServer implements IBaseLanguageServerExtensions, LanguageClientAware {
static final Logger logger = LogManager.getLogger(ActualLanguageServer.class);
private static final URIResolverRegistry reg = URIResolverRegistry.getInstance();
private final IBaseTextDocumentService lspDocumentService;
private final BaseWorkspaceService lspWorkspaceService;
private final Runnable onExit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import java.util.function.Function;

import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.nullness.qual.PolyNull;
import org.eclipse.lsp4j.ProgressParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.rascalmpl.library.util.ParseErrorRecovery;
import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.values.parsetrees.ITree;
import org.rascalmpl.vscode.lsp.parametric.NoContributions;
import org.rascalmpl.vscode.lsp.util.Diagnostics;
import org.rascalmpl.vscode.lsp.util.Versioned;
import io.usethesource.vallang.ISourceLocation;
Expand Down Expand Up @@ -197,6 +198,12 @@ public CompletableFuture<Versioned<List<Diagnostics.Template>>> getDiagnosticsAs
private void parse() {
parser.apply(location, content)
.whenComplete((t, e) -> {
if (e != null && e instanceof CompletionException && e.getCause() != null) {
e = e.getCause();
}
if (e != null && e instanceof NoContributions.NoContributionException) {
return;
}
var diagnosticsList = toDiagnosticsList(t, e); // `t` and `e` are nullable

// Complete future to get the tree
Expand Down Expand Up @@ -241,4 +248,9 @@ private List<Diagnostics.Template> toDiagnosticsList(@Nullable ITree tree, @Null
public long getLastModified() {
return unpackCurrent().getTimestamp();
}

public TextDocumentState changeParser(BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parsing) {
var c = getCurrentContent();
return new TextDocumentState(parsing, this.location, c.version(), c.get(), getLastModified());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2018-2025, NWO-I CWI and Swat.engineering
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.rascalmpl.vscode.lsp.parametric;

import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.rascalmpl.values.parsetrees.ITree;
import org.rascalmpl.vscode.lsp.util.concurrent.InterruptibleFuture;

import io.usethesource.vallang.IConstructor;
import io.usethesource.vallang.IList;
import io.usethesource.vallang.ISet;
import io.usethesource.vallang.ISourceLocation;
import io.usethesource.vallang.ITuple;
import io.usethesource.vallang.IValue;

public class NoContributions implements ILanguageContributions {

private static final Logger logger = LogManager.getLogger(NoContributions.class);

private final Duration delay = Duration.ofSeconds(10);
private final CompletableFuture<Boolean> falseFut = CompletableFuture.completedFuture(false);
private Executor exec;

public class NoContributionException extends NotImplementedException {
private NoContributionException(String message) {
super(message);
}
}

public NoContributions(Executor exec) {
this.exec = exec;
}

private <T extends IValue> CompletableFuture<T> delayed(T t) {
var delayedExec = CompletableFuture.delayedExecutor(delay.toMillis(), TimeUnit.MILLISECONDS, exec);
return CompletableFuture.supplyAsync(() -> t, delayedExec);
}

private <T> InterruptibleFuture<T> delayedInterruptibleFailure(String contribution) {
return new InterruptibleFuture<>(delayedFailure(contribution), () -> {});
}

private <T> CompletableFuture<T> delayedFailure(String contribution) {
var delayedExec = CompletableFuture.delayedExecutor(delay.toMillis(), TimeUnit.MILLISECONDS, exec);
return CompletableFuture.supplyAsync(() -> { throw new NoContributionException("Ignoring missing contribution " + contribution); }, delayedExec);
}

@Override
public String getName() {
return "Silent contributions";
}

@Override
public CompletableFuture<ITree> parsing(ISourceLocation loc, String input) {
logger.debug("No contrib: parse");
return delayedFailure("parsing");
}

@Override
public InterruptibleFuture<IConstructor> analysis(ISourceLocation loc, ITree input) {
return delayedInterruptibleFailure("analysis");
}

@Override
public InterruptibleFuture<IConstructor> build(ISourceLocation loc, ITree input) {
return delayedInterruptibleFailure("build");
}

@Override
public InterruptibleFuture<IList> documentSymbol(ITree input) {
return delayedInterruptibleFailure("documentSymbol");
}

@Override
public InterruptibleFuture<IList> codeLens(ITree input) {
return delayedInterruptibleFailure("codeLens");
}

@Override
public InterruptibleFuture<IList> inlayHint(ITree input) {
return delayedInterruptibleFailure("inlayHint");
}

@Override
public InterruptibleFuture<IValue> execution(String command) {
return delayedInterruptibleFailure("execution");
}

@Override
public InterruptibleFuture<ISet> hover(IList focus) {
return delayedInterruptibleFailure("hover");
}

@Override
public InterruptibleFuture<ISet> definition(IList focus) {
return delayedInterruptibleFailure("definition");
}

@Override
public InterruptibleFuture<ISet> references(IList focus) {
return delayedInterruptibleFailure("references");
}

@Override
public InterruptibleFuture<ISet> implementation(IList focus) {
return delayedInterruptibleFailure("implementation");
}

@Override
public InterruptibleFuture<IList> codeAction(IList focus) {
return delayedInterruptibleFailure("codeLens");
}

@Override
public InterruptibleFuture<IList> selectionRange(IList focus) {
return delayedInterruptibleFailure("selectionRange");
}

@Override
public InterruptibleFuture<ISourceLocation> prepareRename(IList focus) {
return delayedInterruptibleFailure("prepareRename");
}

@Override
public InterruptibleFuture<ITuple> rename(IList focus, String name) {
return delayedInterruptibleFailure("rename");
}

@Override
public InterruptibleFuture<ITuple> didRenameFiles(IList fileRenames) {
return delayedInterruptibleFailure("didRenameFiles");
}

@Override
public CompletableFuture<IList> parseCodeActions(String command) {
return delayedFailure("parseCodeActions");
}

@Override
public CompletableFuture<Boolean> hasAnalysis() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasBuild() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasDocumentSymbol() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasCodeLens() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasInlayHint() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasRename() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasExecution() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasHover() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasDefinition() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasReferences() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasImplementation() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasCodeAction() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasDidRenameFiles() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> hasSelectionRange() {
return falseFut;
}

@Override
public CompletableFuture<Boolean> specialCaseHighlighting() {
return falseFut;
}

@Override
public CompletableFuture<SummaryConfig> getAnalyzerSummaryConfig() {
return delayedFailure("getAnalyzerSummaryConfig");
}

@Override
public CompletableFuture<SummaryConfig> getBuilderSummaryConfig() {
return delayedFailure("getBuilderSummaryConfig");
}

@Override
public CompletableFuture<SummaryConfig> getOndemandSummaryConfig() {
return delayedFailure("getOndemandSummaryConfig");
}

@Override
public void cancelProgress(String progressId) {
logger.trace("Cancelling progress " + progressId + " not supported on dummy contributions.");
}
}
Loading
Loading