implements PLN-0069
This commit is contained in:
parent
54f8c0d6d8
commit
41bcd8c52a
@ -0,0 +1,33 @@
|
||||
package p.studio.lsp.messages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record BaselineEditorPalette(
|
||||
String baseForeground,
|
||||
String selectionBackground,
|
||||
String activeHighlightBackground,
|
||||
String lineNumberForeground,
|
||||
String statusChipBackground,
|
||||
String statusChipBorder,
|
||||
String statusChipForeground) {
|
||||
|
||||
public BaselineEditorPalette {
|
||||
baseForeground = requireText(baseForeground, "baseForeground");
|
||||
selectionBackground = requireText(selectionBackground, "selectionBackground");
|
||||
activeHighlightBackground = requireText(activeHighlightBackground, "activeHighlightBackground");
|
||||
lineNumberForeground = requireText(lineNumberForeground, "lineNumberForeground");
|
||||
statusChipBackground = requireText(statusChipBackground, "statusChipBackground");
|
||||
statusChipBorder = requireText(statusChipBorder, "statusChipBorder");
|
||||
statusChipForeground = requireText(statusChipForeground, "statusChipForeground");
|
||||
}
|
||||
|
||||
private static String requireText(
|
||||
final String value,
|
||||
final String field) {
|
||||
final String candidate = Objects.requireNonNull(value, field).trim();
|
||||
if (candidate.isEmpty()) {
|
||||
throw new IllegalArgumentException(field + " must not be blank");
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
@ -7,12 +7,19 @@ public record BaselineServerDescription(
|
||||
String name,
|
||||
String version,
|
||||
boolean hoverSupported,
|
||||
List<String> semanticTokenTypes) {
|
||||
List<String> semanticTokenTypes,
|
||||
List<BaselineVisualTheme> visualThemes,
|
||||
String activeVisualThemeId) {
|
||||
|
||||
public BaselineServerDescription {
|
||||
name = requireText(name, "name");
|
||||
version = requireText(version, "version");
|
||||
semanticTokenTypes = List.copyOf(Objects.requireNonNull(semanticTokenTypes, "semanticTokenTypes"));
|
||||
visualThemes = List.copyOf(Objects.requireNonNull(visualThemes, "visualThemes"));
|
||||
activeVisualThemeId = requireText(activeVisualThemeId, "activeVisualThemeId");
|
||||
if (visualThemes.stream().map(BaselineVisualTheme::themeId).noneMatch(activeVisualThemeId::equals)) {
|
||||
throw new IllegalArgumentException("activeVisualThemeId must reference one of the declared visual themes");
|
||||
}
|
||||
}
|
||||
|
||||
private static String requireText(
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package p.studio.lsp.messages;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record BaselineTokenStyle(
|
||||
String semanticKey,
|
||||
String foreground,
|
||||
boolean italic,
|
||||
boolean bold,
|
||||
boolean underline) {
|
||||
|
||||
public BaselineTokenStyle {
|
||||
semanticKey = requireText(semanticKey, "semanticKey");
|
||||
foreground = requireText(foreground, "foreground");
|
||||
}
|
||||
|
||||
private static String requireText(
|
||||
final String value,
|
||||
final String field) {
|
||||
final String candidate = Objects.requireNonNull(value, field).trim();
|
||||
if (candidate.isEmpty()) {
|
||||
throw new IllegalArgumentException(field + " must not be blank");
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package p.studio.lsp.messages;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public record BaselineVisualTheme(
|
||||
String themeId,
|
||||
String displayName,
|
||||
BaselineEditorPalette editorPalette,
|
||||
List<BaselineTokenStyle> tokenStyles) {
|
||||
|
||||
public BaselineVisualTheme {
|
||||
themeId = requireText(themeId, "themeId");
|
||||
displayName = requireText(displayName, "displayName");
|
||||
editorPalette = Objects.requireNonNull(editorPalette, "editorPalette");
|
||||
tokenStyles = List.copyOf(Objects.requireNonNull(tokenStyles, "tokenStyles"));
|
||||
if (tokenStyles.isEmpty()) {
|
||||
throw new IllegalArgumentException("tokenStyles must not be empty");
|
||||
}
|
||||
}
|
||||
|
||||
private static String requireText(
|
||||
final String value,
|
||||
final String field) {
|
||||
final String candidate = Objects.requireNonNull(value, field).trim();
|
||||
if (candidate.isEmpty()) {
|
||||
throw new IllegalArgumentException(field + " must not be blank");
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,10 @@ import p.studio.compiler.messages.BuilderPipelineConfig;
|
||||
import p.studio.compiler.messages.BuildingIssue;
|
||||
import p.studio.compiler.models.AnalysisSnapshot;
|
||||
import p.studio.compiler.models.BuilderPipelineContext;
|
||||
import p.studio.compiler.models.FrontendEditorPaletteSpec;
|
||||
import p.studio.compiler.PBSDefinitions;
|
||||
import p.studio.compiler.models.FrontendTokenStyleSpec;
|
||||
import p.studio.compiler.models.FrontendVisualThemeSpec;
|
||||
import p.studio.compiler.pbs.PbsSemanticKind;
|
||||
import p.studio.compiler.pbs.lexer.PbsLexer;
|
||||
import p.studio.compiler.pbs.lexer.PbsToken;
|
||||
@ -34,7 +37,9 @@ public record CompilerLanguageServiceBridge() implements LanguageServiceBridge {
|
||||
"Prometeu Studio LSP",
|
||||
"0.1.0",
|
||||
true,
|
||||
PBSDefinitions.PBS.getSemanticPresentation().semanticKeys());
|
||||
PBSDefinitions.PBS.getSemanticPresentation().semanticKeys(),
|
||||
PBSDefinitions.PBS.getSemanticPresentation().themes().stream().map(this::mapVisualTheme).toList(),
|
||||
PBSDefinitions.PBS.getSemanticPresentation().defaultThemeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -190,4 +195,32 @@ public record CompilerLanguageServiceBridge() implements LanguageServiceBridge {
|
||||
return tokens.get(index - 1).kind() == p.studio.compiler.pbs.lexer.PbsTokenKind.LEFT_BRACKET
|
||||
&& tokens.get(index + 1).kind() == p.studio.compiler.pbs.lexer.PbsTokenKind.RIGHT_BRACKET;
|
||||
}
|
||||
|
||||
private BaselineVisualTheme mapVisualTheme(final FrontendVisualThemeSpec theme) {
|
||||
return new BaselineVisualTheme(
|
||||
theme.themeId(),
|
||||
theme.displayName(),
|
||||
mapEditorPalette(theme.editorPalette()),
|
||||
theme.tokenStyles().stream().map(this::mapTokenStyle).toList());
|
||||
}
|
||||
|
||||
private BaselineEditorPalette mapEditorPalette(final FrontendEditorPaletteSpec palette) {
|
||||
return new BaselineEditorPalette(
|
||||
palette.baseForeground(),
|
||||
palette.selectionBackground(),
|
||||
palette.activeHighlightBackground(),
|
||||
palette.lineNumberForeground(),
|
||||
palette.statusChipBackground(),
|
||||
palette.statusChipBorder(),
|
||||
palette.statusChipForeground());
|
||||
}
|
||||
|
||||
private BaselineTokenStyle mapTokenStyle(final FrontendTokenStyleSpec tokenStyle) {
|
||||
return new BaselineTokenStyle(
|
||||
tokenStyle.semanticKey(),
|
||||
tokenStyle.foreground(),
|
||||
tokenStyle.italic(),
|
||||
tokenStyle.bold(),
|
||||
tokenStyle.underline());
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class CompilerLanguageServiceBridgeTest {
|
||||
@ -55,6 +56,21 @@ class CompilerLanguageServiceBridgeTest {
|
||||
assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-number")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void describeServerPublishesFrontendVisualThemes() {
|
||||
final CompilerLanguageServiceBridge bridge = new CompilerLanguageServiceBridge();
|
||||
|
||||
final var description = bridge.describeServer(new LspProjectContext("main", "pbs", Path.of(".")));
|
||||
|
||||
assertEquals("pbs-default", description.activeVisualThemeId());
|
||||
assertEquals(1, description.visualThemes().size());
|
||||
assertEquals("PBS Default", description.visualThemes().getFirst().displayName());
|
||||
assertEquals("#d9e2ec", description.visualThemes().getFirst().editorPalette().baseForeground());
|
||||
assertTrue(description.visualThemes().getFirst().tokenStyles().stream()
|
||||
.anyMatch(tokenStyle -> tokenStyle.semanticKey().equals("pbs-keyword")
|
||||
&& tokenStyle.foreground().equals("#569cd6")));
|
||||
}
|
||||
|
||||
private Path findRepoRoot(final Path start) {
|
||||
var current = start;
|
||||
while (current != null) {
|
||||
|
||||
@ -12,9 +12,12 @@ import org.eclipse.lsp4j.services.LanguageClient;
|
||||
import org.eclipse.lsp4j.services.TextDocumentService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import p.studio.lsp.messages.BaselineDocumentAnalysis;
|
||||
import p.studio.lsp.messages.BaselineEditorPalette;
|
||||
import p.studio.lsp.messages.BaselineHover;
|
||||
import p.studio.lsp.messages.BaselineSemanticTokens;
|
||||
import p.studio.lsp.messages.BaselineServerDescription;
|
||||
import p.studio.lsp.messages.BaselineTokenStyle;
|
||||
import p.studio.lsp.messages.BaselineVisualTheme;
|
||||
import p.studio.lsp.messages.LspProjectContext;
|
||||
import p.studio.lsp.services.LanguageServiceBridge;
|
||||
import p.studio.lsp.services.protocol.mapping.ProtocolMessageMapper;
|
||||
@ -79,7 +82,17 @@ class PrometeuLanguageServerTest {
|
||||
|
||||
private static final class RecordingBridge implements LanguageServiceBridge {
|
||||
private int describeServerCalls;
|
||||
private final BaselineServerDescription serverDescription = new BaselineServerDescription("demo", "1", true, List.of());
|
||||
private final BaselineServerDescription serverDescription = new BaselineServerDescription(
|
||||
"demo",
|
||||
"1",
|
||||
true,
|
||||
List.of(),
|
||||
List.of(new BaselineVisualTheme(
|
||||
"demo-default",
|
||||
"Demo Default",
|
||||
new BaselineEditorPalette("#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777"),
|
||||
List.of(new BaselineTokenStyle("demo-keyword", "#888888", false, false, false)))),
|
||||
"demo-default");
|
||||
|
||||
@Override
|
||||
public BaselineServerDescription describeServer(final LspProjectContext project) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user