Skip to content

Add semantic token support#114

Draft
trustytrojan wants to merge 7 commits into
GroovyLanguageServer:masterfrom
trustytrojan:semantic-tokens
Draft

Add semantic token support#114
trustytrojan wants to merge 7 commits into
GroovyLanguageServer:masterfrom
trustytrojan:semantic-tokens

Conversation

@trustytrojan
Copy link
Copy Markdown
Contributor

Before

20260518_15h02m10s_grim

After

20260518_15h03m22s_grim

Copilot AI review requested due to automatic review settings May 18, 2026 21:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds LSP semantic tokens (full) support to the Groovy language server, with a new provider that walks the AST to emit tokens for declarations, method calls, and property accesses.

Changes:

  • New SemanticTokensProvider that emits LSP delta-encoded tokens by inspecting MethodCallExpression, PropertyExpression, and declaration nodes from the ASTNodeVisitor.
  • Wires semanticTokensFull into GroovyServices, caching a provider instance.
  • Advertises semantic tokens capability with a token-type legend in GroovyLanguageServer.initialize.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 14 comments.

File Description
src/main/java/net/prominic/groovyls/providers/SemanticTokensProvider.java New provider that converts AST nodes into LSP semantic tokens.
src/main/java/net/prominic/groovyls/GroovyServices.java Implements semanticTokensFull and lazily creates the provider.
src/main/java/net/prominic/groovyls/GroovyLanguageServer.java Registers semantic tokens capability and legend in server initialization.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +371 to +377
// Ensure semantic tokens provider is initialized
if (semanticTokensProvider == null) {
semanticTokensProvider = new SemanticTokensProvider(fileContentsTracker, astVisitor);
}

// Provide semantic tokens - GDSL symbols are injected before LSP transmission
return CompletableFuture.completedFuture(semanticTokensProvider.provideFull(textDocument));
Comment on lines +162 to +163
int startOffset = lineColToOffset(text, range.getStart().getLine(), range.getStart().getCharacter());
int endOffset = lineColToOffset(text, range.getEnd().getLine(), range.getEnd().getCharacter());
int found = findExactTokenOffset(text, name, startOffset, endOffset);
if (found == -1) return;

Position pos = toLineCol(text, found);
int endOffset = lineColToOffset(text, range.getEnd().getLine(), range.getEnd().getCharacter());
if (startOffset < 0 || endOffset <= startOffset) return;

int found = findExactTokenOffset(text, name, startOffset, endOffset);
Comment on lines +183 to +184
int endOffsetCtor = lineColToOffset(text, range.getEnd().getLine(), range.getEnd().getCharacter());

Comment on lines +222 to +229
private SemanticTokens encodeDeltaTokens(List<Token> tokens) {
List<Integer> data = new ArrayList<>();
int prevLine = 0;
int prevChar = 0;
boolean first = true;
for (Token t : tokens) {
int deltaLine = first ? t.line : t.line - prevLine;
int deltaStart = first ? t.startChar : (deltaLine == 0 ? t.startChar - prevChar : t.startChar);
Comment on lines +101 to +105
SemanticTokensWithRegistrationOptions semanticTokensOptions = new SemanticTokensWithRegistrationOptions();
semanticTokensOptions.setLegend(new SemanticTokensLegend(
SemanticTokensProvider.TOKEN_TYPES,
Collections.emptyList()));
semanticTokensOptions.setFull(true);
* or comments. Tokens are encoded using the LSP delta format.
*/
public class SemanticTokensProvider {
private final FileContentsTracker fileContentsTracker;
"macro","keyword","modifier","comment","string","number","regexp","operator"
));

private final ASTNodeVisitor astVisitor;
Comment on lines +243 to +253
private int lineColToOffset(String text, int line, int col) {
if (line < 0) return -1;
int curLine = 0;
int offset = 0;
int len = text.length();
while (offset < len && curLine < line) {
if (text.charAt(offset) == '\n') {
curLine++;
}
offset++;
}
@trustytrojan trustytrojan marked this pull request as draft May 18, 2026 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants