Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
627c6a5
Set document selectors on dynamic capabilities.
toinehartman Jun 15, 2026
d746799
Remove duplicate extensions from contributions.
toinehartman Jun 16, 2026
b1fe84a
Use orderless mock verification.
toinehartman Jun 16, 2026
a121cb7
Bump js-yaml from 4.1.1 to 4.2.0 in /rascal-vscode-extension (#1119)
dependabot[bot] Jun 16, 2026
618066f
Working on extra warnings feature
DavyLandman Jun 12, 2026
c806874
Dynamic registration of semantic token capability.
toinehartman Jun 16, 2026
7904a4e
Discover extension-less schemes from associated files.
toinehartman Jun 16, 2026
05efdb5
Merge remote-tracking branch 'origin/main' into fix/capability-docume…
toinehartman Jun 16, 2026
82a7136
Refactored debounce out of the ParametricFileFacts
DavyLandman Jun 16, 2026
81a9f66
Implement semantic token capability option merge.
toinehartman Jun 16, 2026
1dfea42
Rewrote everything to an analyzer
DavyLandman Jun 16, 2026
6ac2cf7
Improved where the the analyzer is running
DavyLandman Jun 16, 2026
fc7a89d
Improved test case
DavyLandman Jun 16, 2026
4203168
Print which errors are shown
DavyLandman Jun 17, 2026
376e24b
Only show the warnings for the cases where we can do something about …
DavyLandman Jun 17, 2026
45523bf
Fixed possible null deref
DavyLandman Jun 17, 2026
9100f66
Refresh editors using LSP instead of close+open.
toinehartman Jun 17, 2026
db04507
Simplify filter construction.
toinehartman Jun 17, 2026
a371d8d
Get client once.
toinehartman Jun 17, 2026
657e3e9
Only apply contributions to parametric language.
toinehartman Jun 17, 2026
6fd91bf
Use thread-safe set.
toinehartman Jun 17, 2026
030cf1f
Move/add comments on thread-safety of capability updates.
toinehartman Jun 17, 2026
fc8db21
Clarify selector wrapping.
toinehartman Jun 17, 2026
8586f9a
Test that open, associated editor is updated on language registration.
toinehartman Jun 17, 2026
7586697
Fix bugs in analyzer calls
DavyLandman Jun 17, 2026
9cc7a34
Skip second consecutive unregistration.
toinehartman Jun 18, 2026
91d457b
Processed review remarks
DavyLandman Jun 18, 2026
aa8ee92
LSP Open File resolvers needs to be writeable (but throw errors on wr…
DavyLandman Jun 18, 2026
9ce23fd
Fix some issues that make the IDE tests a bit more janky than we woul…
DavyLandman Jun 18, 2026
d00f8a9
Merge branch 'main' into fix/capability-document-selectors
toinehartman Jun 18, 2026
9a1ab32
Merge branch 'main' into feat/earlier-warnings
DavyLandman Jun 18, 2026
42731d9
Debug icons in Terminal view (#1124)
rodinaarssen Jun 18, 2026
a0651ea
Always add contribution-based document selectors to capability-specif…
toinehartman Jun 18, 2026
64d67fd
Merge remote-tracking branch 'origin/main' into fix/capability-docume…
toinehartman Jun 18, 2026
b4b36c4
Fixed IDE test in finding the right quickfix
DavyLandman Jun 18, 2026
91ea32e
Run the validator in more cases such that we do not get stuck notific…
DavyLandman Jun 19, 2026
d6a97c4
Merge remote-tracking branch 'origin/main' into feat/earlier-warnings
DavyLandman Jun 19, 2026
f523010
Create analyzer feature for rascal (#1122)
DavyLandman Jun 19, 2026
abe009d
Retry on diagnostic, to give them a chance to clear after resetting t…
DavyLandman Jun 19, 2026
b26db35
Always unregister before registration (#1123)
toinehartman Jun 22, 2026
8d5d03e
Merge remote-tracking branch 'origin/main' into fix/capability-docume…
toinehartman Jun 22, 2026
34e3916
Protect files, but avoid rewriting them when they have not changed (#…
DavyLandman Jun 22, 2026
aa52ffa
Merge branch 'main' into fix/capability-document-selectors
toinehartman Jun 22, 2026
03100bb
Improve the typescript & esbuild configuration (#1129)
DavyLandman Jun 22, 2026
b955cd1
Merge remote-tracking branch 'origin/main' into fix/capability-docume…
toinehartman Jun 22, 2026
8437074
Do not print expected exceptions.
toinehartman Jun 22, 2026
db8c580
Fix file rename test.
toinehartman Jun 22, 2026
573add7
Fix test script after #1129.
toinehartman Jun 22, 2026
f45f9c0
Fix license check for esbuild after #1129.
toinehartman Jun 22, 2026
1ea0248
Document selectors for capabilities (#1118)
DavyLandman Jun 22, 2026
0b511b3
Dynamic registration of DSL capabilities.
toinehartman Jun 17, 2026
f80435a
More useful logging of dynamic registrations.
toinehartman Jun 23, 2026
8a8dcae
Remove unused capability.
toinehartman Jun 23, 2026
29c8181
Document update/refresh considerations.
toinehartman Jun 24, 2026
e955988
Fix race in language registration.
toinehartman Jun 24, 2026
61c843b
Register capabilities dynamically (#1131)
toinehartman Jun 24, 2026
f9bb2c6
Merge remote-tracking branch 'origin/main' into feature/1010-pom-lead…
toinehartman Jun 25, 2026
1b43c27
Implement folding range refresh.
toinehartman Jun 24, 2026
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
15 changes: 8 additions & 7 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ jobs:
working-directory: ./rascal-vscode-extension
run: |
npm ci
npm run compile-tests
npm run normalTest
npm run compile:tests
npm run test:normal

ui-test:
strategy:
Expand Down Expand Up @@ -80,7 +80,7 @@ jobs:
working-directory: ./rascal-vscode-extension
run: |
npm ci
npm run compile-tests
npm run compile:tests

- name: Cache vscode downloads
id: cache-vscode
Expand Down Expand Up @@ -182,15 +182,16 @@ jobs:
sed -i "1i⚠️ This is pre-release build, based on [CI build $GITHUB_RUN_NUMBER](https://github.com/usethesource/rascal-language-servers/actions/runs/$GITHUB_RUN_ID). ⚠️\n\n" README.md
sed -i "s/\\(\"version\":.*\\)\\-head/\\1-head$GITHUB_RUN_NUMBER/" package.json

- name: Package & compile extension
- name: Compile extension
working-directory: ./rascal-vscode-extension
run: |
npm ci
npm run license-check
npm run esbuild
npm run license:check
npm run lint
npm run check:types
npm run compile

- name: package extension
- name: Package extension
working-directory: rascal-vscode-extension
run: |
npm run lsp4j:package
Expand Down
17 changes: 17 additions & 0 deletions rascal-lsp/src/main/checkerframework/lsp4j.astub
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,20 @@ public class SemanticTokensCapabilities extends DynamicRegistrationCapabilities
public @Nullable Boolean getServerCancelSupport() {}
public @Nullable Boolean getAugmentsSyntaxTokens() {}
}

package org.eclipse.lsp4j;

import org.checkerframework.checker.nullness.qual.*;

public class DocumentFilter {
public DocumentFilter(@Nullable String language, @Nullable String scheme, @Nullable Either<String, RelativePattern> pattern) {}
}

package org.eclipse.lsp4j;

import org.checkerframework.checker.nullness.qual.*;

public class Registration {
public Registration(String id, String method) {}
public Registration(String id, String method, @Nullable Object registerOptions) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -285,38 +285,36 @@ public CompletableFuture<Two<String, URI[]>[]> supplyPathConfig(PathConfigParame
@Override
public CompletableFuture<Void> sendRegisterLanguage(LanguageParameter lang) {
logger.debug("rascal/sendRegisterLanguage({}, {})", lang.getName(), lang.getMainFunction());
return CompletableFuture.runAsync(() -> lspDocumentService.registerLanguage(lang), executor);
lspDocumentService.registerLanguage(lang);
return CompletableFutureUtils.completedFuture(null, executor);
}
@Override
public CompletableFuture<Void> sendUnregisterLanguage(LanguageParameter lang) {
logger.debug("rascal/sendUnregisterLanguage({})", lang.getName());
return CompletableFuture.runAsync(() -> lspDocumentService.unregisterLanguage(lang), executor);
lspDocumentService.unregisterLanguage(lang);
return CompletableFutureUtils.completedFuture(null, executor);
}

@Override
public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
// Exit when our parent process exits
executor.submit(() -> ProcessHandle.of(params.getProcessId()).ifPresent(p -> p.onExit().thenAccept(ignored -> this.exit())));

return CompletableFuture.supplyAsync(() -> {
logger.info("LSP connection started (connected to {} version {})", params.getClientInfo().getName(), params.getClientInfo().getVersion());
logger.debug("LSP client capabilities: {}", params.getCapabilities());
final InitializeResult initializeResult = new InitializeResult(new ServerCapabilities());
lspDocumentService.initializeServerCapabilities(params.getCapabilities(), initializeResult.getCapabilities());
lspWorkspaceService.initialize(params.getCapabilities(), params.getWorkspaceFolders(), initializeResult.getCapabilities());
logger.debug("Initialized LSP connection with capabilities: {}", initializeResult);
return initializeResult;
}, executor);
logger.info("LSP connection started (connected to {} version {})", params.getClientInfo().getName(), params.getClientInfo().getVersion());
logger.debug("LSP client capabilities: {}", params.getCapabilities());
final InitializeResult initializeResult = new InitializeResult(new ServerCapabilities());
lspDocumentService.initializeServerCapabilities(params.getCapabilities(), initializeResult.getCapabilities());
lspWorkspaceService.initialize(params.getCapabilities(), params.getWorkspaceFolders(), initializeResult.getCapabilities());
logger.debug("Initialized LSP connection with capabilities: {}", initializeResult);
return CompletableFutureUtils.completedFuture(initializeResult, executor);
}

@Override
@SuppressWarnings("unused") // InitializedParams is an empty interface
public void initialized(InitializedParams params) {
executor.submit(() -> {
logger.debug("LSP connection initialized");
lspWorkspaceService.initialized();
lspDocumentService.initialized();
});
logger.debug("LSP connection initialized");
lspWorkspaceService.initialized();
lspDocumentService.initialized();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.rascalmpl.library.util.ParseErrorRecovery;
import org.rascalmpl.uri.FileAttributes;
import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.values.parsetrees.ITree;
import org.rascalmpl.vscode.lsp.parametric.NoContributions.NoContributionException;
Expand All @@ -64,6 +65,7 @@ public class TextDocumentState {
private final BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parser;
private final ISourceLocation location;
private final ExecutorService exec;
private final FileAttributes attributesOnDisk;

private final AtomicReference<Versioned<Update>> current;
private final AtomicReference<@Nullable Versioned<ITree>> lastWithoutErrors;
Expand All @@ -73,10 +75,11 @@ public TextDocumentState(
BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parser,
ISourceLocation location,
int initialVersion, String initialContent, long initialTimestamp,
ExecutorService exec) {
ExecutorService exec, FileAttributes attributesOnDisk) {

this.parser = parser;
this.location = location;
this.attributesOnDisk = attributesOnDisk;
this.lastWithoutErrors = new AtomicReference<>();
this.last = new AtomicReference<>();
this.exec = exec;
Expand All @@ -89,6 +92,13 @@ public ISourceLocation getLocation() {
return location;
}

/**
* The file attributes (aka stat) of the location on disk, before it was opened by VS Code
*/
public FileAttributes getAttributesOnDisk() {
return attributesOnDisk;
}

public CompletableFuture<Versioned<List<Diagnostics.Template>>> update(int version, String content, long timestamp) {
var u = new Update(version, content, timestamp);
Versioned.replaceIfNewer(current, new Versioned<>(version, u));
Expand Down Expand Up @@ -266,6 +276,6 @@ public long getLastModified() {

public TextDocumentState changeParser(BiFunction<ISourceLocation, String, CompletableFuture<ITree>> parsing) {
var c = getCurrentContent();
return new TextDocumentState(parsing, this.location, c.version(), c.get(), getLastModified(), exec);
return new TextDocumentState(parsing, this.location, c.version(), c.get(), getLastModified(), exec, getAttributesOnDisk());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException;
import org.eclipse.lsp4j.jsonrpc.messages.ResponseError;
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
import org.rascalmpl.uri.FileAttributes;
import org.rascalmpl.uri.URIResolverRegistry;
import org.rascalmpl.util.locations.ColumnMaps;
import org.rascalmpl.util.locations.LineColumnOffsetMap;
Expand All @@ -58,7 +59,6 @@
import org.rascalmpl.vscode.lsp.util.Lists;
import org.rascalmpl.vscode.lsp.util.Versioned;
import org.rascalmpl.vscode.lsp.util.locations.Locations;

import io.usethesource.vallang.ISourceLocation;

/**
Expand Down Expand Up @@ -153,9 +153,25 @@ protected TextDocumentState getFile(ISourceLocation loc) {
}
}

private FileAttributes safeStat(ISourceLocation loc, long timestamp) {
try {
return URIResolverRegistry.getInstance().stat(loc);
} catch (IOException e) {
// generate a fallback
// for example for untitled files, text document content provided,
// or other files that are not accessible to our VFS
return new FileAttributes(
true, true,
timestamp, timestamp,
true, false,
0
);
}

}

protected TextDocumentState openFile(TextDocumentItem doc, Function<ISourceLocation, BiFunction<ISourceLocation, String, CompletableFuture<ITree>>> parserGetter, long timestamp, ExecutorService exec) {
return files.computeIfAbsent(Locations.toLoc(doc),
l -> new TextDocumentState(parserGetter.apply(l), l, doc.getVersion(), doc.getText(), timestamp, exec));
return files.computeIfAbsent(Locations.toLoc(doc), l -> new TextDocumentState(parserGetter.apply(l), l, doc.getVersion(), doc.getText(), timestamp, exec, safeStat(l, timestamp)));
}

private void invalidateColumnMaps(ISourceLocation loc) {
Expand Down Expand Up @@ -191,12 +207,13 @@ protected void closeFile(ISourceLocation loc) {
return files.keySet();
}

protected void updateContents(DidChangeTextDocumentParams change, long timestamp) {
protected TextDocumentState updateContents(DidChangeTextDocumentParams change, long timestamp) {
var doc = change.getTextDocument();
logger.trace("New contents for {}", doc);
TextDocumentState file = getFile(Locations.toLoc(doc));
invalidateColumnMaps(file.getLocation());
handleParsingErrors(file, file.update(doc.getVersion(), Lists.last(change.getContentChanges()).getText(), timestamp));
return file;
}

protected void handleParsingErrors(TextDocumentState file, CompletableFuture<Versioned<List<Diagnostics.Template>>> diagnosticsAsync) {
Expand Down
Loading
Loading