semantic highlight based on squiggle-lang AST
This commit is contained in:
parent
5a2b5b2a4d
commit
96c2a982cb
|
@ -4,6 +4,7 @@ import * as vscode from "vscode";
|
|||
import { startClient, stopClient } from "./client";
|
||||
|
||||
import { SquiggleEditorProvider } from "./editor";
|
||||
import { registerSemanticHighlight } from "./highlight";
|
||||
import { registerPreviewCommand } from "./preview";
|
||||
|
||||
// this method is called when your extension is activated
|
||||
|
@ -13,6 +14,8 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
|
||||
registerPreviewCommand(context);
|
||||
|
||||
registerSemanticHighlight();
|
||||
|
||||
startClient(context);
|
||||
}
|
||||
|
||||
|
|
90
packages/vscode-ext/client/src/highlight.ts
Normal file
90
packages/vscode-ext/client/src/highlight.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import * as vscode from "vscode";
|
||||
|
||||
import { parse } from "@quri/squiggle-lang";
|
||||
import { AnyPeggyNode } from "@quri/squiggle-lang/dist/src/rescript/Reducer/Reducer_Peggy/helpers";
|
||||
|
||||
const tokenTypes = ["class", "interface", "enum", "function", "variable"];
|
||||
const tokenModifiers = ["declaration", "documentation"];
|
||||
const legend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers);
|
||||
|
||||
const convertRange = (
|
||||
range: Extract<AnyPeggyNode, { type: "Identifier" }>["location"]
|
||||
) =>
|
||||
new vscode.Range(
|
||||
new vscode.Position(range.start.line - 1, range.start.column - 1),
|
||||
new vscode.Position(range.end.line - 1, range.end.column - 1)
|
||||
);
|
||||
|
||||
const populateTokensBuilder = (
|
||||
tokensBuilder: vscode.SemanticTokensBuilder,
|
||||
node: AnyPeggyNode
|
||||
// bindings: { [key: string]: boolean }
|
||||
) => {
|
||||
switch (node.type) {
|
||||
case "Expression":
|
||||
for (const child of node.nodes) {
|
||||
populateTokensBuilder(tokensBuilder, child);
|
||||
}
|
||||
break;
|
||||
case "Block":
|
||||
for (const child of node.statements) {
|
||||
populateTokensBuilder(tokensBuilder, child);
|
||||
}
|
||||
break;
|
||||
case "LetStatement":
|
||||
tokensBuilder.push(
|
||||
convertRange(node.variable.location),
|
||||
node.value.type === "Lambda" ? "function" : "variable",
|
||||
["declaration"]
|
||||
);
|
||||
populateTokensBuilder(tokensBuilder, node.value);
|
||||
break;
|
||||
case "Lambda":
|
||||
for (const arg of node.args) {
|
||||
populateTokensBuilder(tokensBuilder, arg);
|
||||
}
|
||||
populateTokensBuilder(tokensBuilder, node.body);
|
||||
break;
|
||||
case "Ternary":
|
||||
populateTokensBuilder(tokensBuilder, node.condition);
|
||||
populateTokensBuilder(tokensBuilder, node.trueExpression);
|
||||
populateTokensBuilder(tokensBuilder, node.falseExpression);
|
||||
break;
|
||||
case "KeyValue":
|
||||
populateTokensBuilder(tokensBuilder, node.key);
|
||||
populateTokensBuilder(tokensBuilder, node.value);
|
||||
break;
|
||||
case "Identifier":
|
||||
tokensBuilder.push(convertRange(node.location), "variable", []);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export const registerSemanticHighlight = () => {
|
||||
const provider: vscode.DocumentSemanticTokensProvider = {
|
||||
provideDocumentSemanticTokens(
|
||||
document: vscode.TextDocument
|
||||
): vscode.ProviderResult<vscode.SemanticTokens> {
|
||||
const parseResult = parse(document.getText());
|
||||
|
||||
const tokensBuilder = new vscode.SemanticTokensBuilder(legend);
|
||||
if (parseResult.tag === "Ok") {
|
||||
populateTokensBuilder(
|
||||
tokensBuilder,
|
||||
parseResult.value
|
||||
// {}
|
||||
);
|
||||
}
|
||||
|
||||
return tokensBuilder.build();
|
||||
},
|
||||
};
|
||||
|
||||
const selector = { language: "squiggle", scheme: "file" };
|
||||
|
||||
vscode.languages.registerDocumentSemanticTokensProvider(
|
||||
selector,
|
||||
provider,
|
||||
legend
|
||||
);
|
||||
};
|
|
@ -13,6 +13,10 @@ import { parse } from "@quri/squiggle-lang";
|
|||
|
||||
import { TextDocument } from "vscode-languageserver-textdocument";
|
||||
|
||||
// Documentation:
|
||||
// - https://code.visualstudio.com/api/language-extensions/language-server-extension-guide
|
||||
// - https://microsoft.github.io/language-server-protocol/specifications/specification-current
|
||||
|
||||
// Create a connection for the server, using Node's IPC as a transport.
|
||||
// Also include all preview / proposed LSP features.
|
||||
let connection = createConnection(ProposedFeatures.all);
|
||||
|
@ -23,17 +27,7 @@ documents.onDidChangeContent((change) => {
|
|||
validateSquiggleDocument(change.document);
|
||||
});
|
||||
|
||||
let hasDiagnosticRelatedInformationCapability = false;
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
const capabilities = params.capabilities;
|
||||
|
||||
hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
|
|
Loading…
Reference in New Issue
Block a user