Skip to content

Commit

Permalink
fix: Support semantic token MultilineTokenSupport
Browse files Browse the repository at this point in the history
Fixes #401

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr authored and fbricon committed Jul 4, 2024
1 parent 5d5674f commit 58147b4
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public static ClientCapabilities create(Object experimental) {
"documentation",
"defaultLibrary"*/
));
semanticTokensCapabilities.setMultilineTokenSupport(Boolean.TRUE);
semanticTokensCapabilities.setServerCancelSupport(Boolean.TRUE);
var semanticTokensClientCapabilitiesRequests = new SemanticTokensClientCapabilitiesRequests(Boolean.TRUE, Boolean.FALSE);
semanticTokensCapabilities.setFormats(List.of(TokenFormat.Relative));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package com.redhat.devtools.lsp4ij.features.semanticTokens;

import com.redhat.devtools.lsp4ij.fixtures.LSPSemanticTokensFixtureTestCase;
import org.jetbrains.annotations.NotNull;

/**
* Completion tests by emulating LSP 'textDocument/semanticTokens' responses
* from the Lua language server.
*/
public class LuaSemanticTokensTest extends LSPSemanticTokensFixtureTestCase {

public LuaSemanticTokensTest() {
// Use *.luax instead of *.lua to avoid consuming the lua textmate
super("*.luax");
}


public void testSemanticTokens() {
// 1. Test completion items result
assertSemanticTokens("test.luax",
"""
--[[
** {==================================================================
** Testing memory limits
** ===================================================================
--]]
print("memory-allocation errors")
""",
"""
{
"data": [
0,
2,
4,
17,
0,
6,
0,
5,
12,
512
]
}
""",
"""
--<LSP_COMMENT>[[
</LSP_COMMENT> ** {==================================================================
** Testing memory limits
** ===================================================================
--]]
<LSP_FUNCTION>print</LSP_FUNCTION>("memory-allocation errors")
"""
);
}

private void assertSemanticTokens(@NotNull String fileName,
@NotNull String editorContentText,
@NotNull String jsonSemanticTokens,
@NotNull String expected) {
String semanticProvider = """
{
"legend": {
"tokenTypes": [
"namespace",
"type",
"class",
"enum",
"interface",
"struct",
"typeParameter",
"parameter",
"variable",
"property",
"enumMember",
"event",
"function",
"method",
"macro",
"keyword",
"modifier",
"comment",
"string",
"number",
"regexp",
"operator",
"decorator"
],
"tokenModifiers": [
"declaration",
"definition",
"readonly",
"static",
"deprecated",
"abstract",
"async",
"modification",
"documentation",
"defaultLibrary",
"global"
]
},
"range": true,
"full": true
}""";
assertSemanticTokens(fileName, editorContentText, semanticProvider, jsonSemanticTokens, expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package com.redhat.devtools.lsp4ij.fixtures;

import com.redhat.devtools.lsp4ij.JSONUtils;
import com.redhat.devtools.lsp4ij.features.semanticTokens.inspector.SemanticTokensInspectorData;
import com.redhat.devtools.lsp4ij.features.semanticTokens.inspector.SemanticTokensInspectorListener;
import com.redhat.devtools.lsp4ij.features.semanticTokens.inspector.SemanticTokensInspectorManager;
import com.redhat.devtools.lsp4ij.mock.MockLanguageServer;
import org.eclipse.lsp4j.SemanticTokens;
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.atomic.AtomicReference;

/**
* Base class test case to test LSP 'textDocument/semanticTokens' feature.
*/
public abstract class LSPSemanticTokensFixtureTestCase extends LSPCodeInsightFixtureTestCase {

public LSPSemanticTokensFixtureTestCase(String... fileNamePatterns) {
super(fileNamePatterns);
}

/**
* Test LSP semanticTokens.
*
* @param fileName the file name used to match registered language servers.
* @param editorContentText the editor content text.
* @param jsonSemanticProvider the LSP SemanticTokensWithRegistrationOptions as JSON string.
* @param jsonSemanticTokens the LSP SemanticTokens as JSON string.
* @param expected the expected IJ SemanticTokens inspector data.
*/
public void assertSemanticTokens(@NotNull String fileName,
@NotNull String editorContentText,
@NotNull String jsonSemanticProvider,
@NotNull String jsonSemanticTokens,
@NotNull String expected) {
var semanticProvider = JSONUtils.getLsp4jGson().fromJson(jsonSemanticProvider, SemanticTokensWithRegistrationOptions.class);
var semanticTokens = JSONUtils.getLsp4jGson().fromJson(jsonSemanticTokens, SemanticTokens.class);
assertSemanticTokens(fileName, editorContentText, semanticProvider, semanticTokens, expected);
}

/**
* Test LSP semanticTokens.
*
* @param fileName the file name used to match registered language servers.
* @param editorContentText the editor content text.
* @param semanticProvider the LSP SemanticTokensWithRegistrationOptions.
* @param semanticTokens the LSP SemanticTokens.
* @param expected the expected IJ SemanticTokens inspector data.
*/
public void assertSemanticTokens(@NotNull String fileName,
@NotNull String editorContentText,
@NotNull SemanticTokensWithRegistrationOptions semanticProvider,
@NotNull SemanticTokens semanticTokens,
@NotNull String expected) {

var project = myFixture.getProject();
var refData = new AtomicReference<SemanticTokensInspectorData>();
SemanticTokensInspectorListener listener = data -> refData.set(data);
SemanticTokensInspectorManager.getInstance(project).addSemanticTokensInspectorListener(listener);
try {

MockLanguageServer.INSTANCE.setTimeToProceedQueries(200);

var serverCapabilities = MockLanguageServer.INSTANCE.defaultServerCapabilities();
serverCapabilities.setSemanticTokensProvider(semanticProvider);
MockLanguageServer.reset(() -> serverCapabilities);
MockLanguageServer.INSTANCE.setSemanticTokens(semanticTokens);

// Open editor for a given file name and content (which declares <caret> to know where the completion is triggered).
myFixture.configureByText(fileName, editorContentText);
myFixture.doHighlighting();

assertNotNull(refData.get());
String actual = SemanticTokensInspectorManager.format(refData.get(), true, false, false, project);
assertEquals(expected, actual);

}
finally {
SemanticTokensInspectorManager.getInstance(project).removeSemanticTokensInspectorListener(listener);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ public void setCompletionList(CompletionList completionList) {
this.textDocumentService.setMockCompletionList(completionList);
}

public void setSemanticTokens(SemanticTokens semanticTokens) {
this.textDocumentService.setSemanticTokens(semanticTokens);
}

public void setHover(Hover hover) {
this.textDocumentService.setMockHover(hover);
}
Expand Down Expand Up @@ -320,4 +324,5 @@ public String toString() {
return "MockLanguageServer [started=" + started + ", delay=" + delay + ", remoteProxies=" + remoteProxies.size()
+ ", inFlight=" + inFlight.size() + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public CompletableFuture<List<? extends CodeLens>> codeLens(CodeLensParams param
File file = new File(URI.create(params.getTextDocument().getUri()));
if (file.exists() && file.length() > 100) {
return CompletableFuture.completedFuture(Collections.singletonList(new CodeLens(
new Range(new Position(1, 0), new Position(1, 1)), new Command("Hi, I'm a CodeLens", null), null)));
new Range(new Position(1, 0), new Position(1, 1)), new Command("Hi, I'm a CodeLens", "mock.command"), null)));
}
return CompletableFuture.completedFuture(Collections.emptyList());
}
Expand Down Expand Up @@ -410,4 +410,5 @@ public void setFoldingRanges(List<FoldingRange> foldingRanges) {
public CompletableFuture<List<FoldingRange>> foldingRange(FoldingRangeRequestParams params) {
return CompletableFuture.completedFuture(this.foldingRanges);
}

}

0 comments on commit 58147b4

Please sign in to comment.