diff --git a/package.json b/package.json index 3952ad2..80d25bd 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,13 @@ ], "configuration": "./language-configuration.json" } + ], + "grammars": [ + { + "language": "jref", + "scopeName": "source.jref", + "path": "./syntaxes/jref.tmLanguage.json" + } ] }, "workspaces": [ diff --git a/server/src/definition.ts b/server/src/definition.ts index 2158133..24976e5 100644 --- a/server/src/definition.ts +++ b/server/src/definition.ts @@ -1,14 +1,10 @@ import path from 'path'; import { URI } from 'vscode-uri'; -import { DefinitionParams, DefinitionLink, TextDocuments, Range } from 'vscode-languageserver/node'; +import { DefinitionParams, DefinitionLink, Range } from 'vscode-languageserver/node'; import { TextDocument } from 'vscode-languageserver-textdocument'; -import { JRefSymbol, SymbolTable } from './visitor'; - -interface ServerContext { - documents: TextDocuments; - documentSymbols: WeakMap; -} +import { JRefSymbol } from './visitor'; +import { ServerContext } from './utils'; const defaultTargetRange: Range = { start: { line: 0, character: 0 }, diff --git a/server/src/semanticTokens.ts b/server/src/semanticTokens.ts new file mode 100644 index 0000000..a56f6e1 --- /dev/null +++ b/server/src/semanticTokens.ts @@ -0,0 +1,43 @@ +import { + SemanticTokensBuilder, + SemanticTokens, + SemanticTokensParams, +} from 'vscode-languageserver/node'; +import { ServerContext } from './utils'; + +export const tokenTypes = ['function']; + +const tokenToIndex = Object.fromEntries(tokenTypes.map((type, index) => [type, index])) as Record< + string, + number +>; + +export function handleSemanticTokens( + params: SemanticTokensParams, + context: ServerContext, +): SemanticTokens { + const { documents, documentSymbols } = context; + const document = documents.get(params.textDocument.uri); + if (!document) return { data: [] }; + const tokensBuilder = new SemanticTokensBuilder(); + + const symbols = documentSymbols.get(document); + if (!symbols || symbols.size === 0) return { data: [] }; + + const refs = Array.from(symbols.values()).filter((symbol) => symbol.isReference); + for (const ref of refs) { + const valueNode = ref.node; + const valuePosition = document.positionAt(valueNode.offset); + + // Highlight the value string + tokensBuilder.push( + valuePosition.line, + valuePosition.character, + valueNode.length, + tokenToIndex['function'], + 0, + ); + } + + return tokensBuilder.build(); +} diff --git a/server/src/server.ts b/server/src/server.ts index b0e3559..3447b5e 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -14,7 +14,8 @@ import { Node, ParseError, parseTree } from 'jsonc-parser'; import { createParseErrorDiagnostic } from './diagnostics'; import { onDefinition } from './definition'; -import { JRefSymbol, SymbolTable, visit } from './visitor'; +import { SymbolTable, visit } from './visitor'; +import { handleSemanticTokens, tokenTypes } from './semanticTokens'; // Create a connection for the server, using Node's IPC as a transport. // Also include all preview / proposed LSP features. @@ -28,6 +29,13 @@ connection.onInitialize((params: InitializeParams) => { capabilities: { textDocumentSync: TextDocumentSyncKind.Incremental, definitionProvider: true, + semanticTokensProvider: { + legend: { + tokenTypes, + tokenModifiers: [], + }, + full: true, + }, }, }; return result; @@ -53,6 +61,10 @@ function sendDiagnostics(document: TextDocument, parseErrors: ParseError[]) { connection.onDefinition((params) => onDefinition(params, { documents, documentSymbols })); +connection.languages.semanticTokens.on((params) => + handleSemanticTokens(params, { documents, documentSymbols }), +); + // Make the text document manager listen on the connection // for open, change and close text document events documents.listen(connection); diff --git a/server/src/utils.ts b/server/src/utils.ts new file mode 100644 index 0000000..6986815 --- /dev/null +++ b/server/src/utils.ts @@ -0,0 +1,8 @@ +import { TextDocuments } from 'vscode-languageserver/node'; +import { SymbolTable } from './visitor'; +import { TextDocument } from 'vscode-languageserver-textdocument'; + +export interface ServerContext { + documents: TextDocuments; + documentSymbols: WeakMap; +} diff --git a/syntaxes/jref.tmlanguage.json b/syntaxes/jref.tmlanguage.json new file mode 100644 index 0000000..33298e7 --- /dev/null +++ b/syntaxes/jref.tmlanguage.json @@ -0,0 +1,9 @@ +{ + "scopeName": "source.jref", + "injectionSelector": "L:source.json", + "patterns": [ + { + "include": "source.json" + } + ] +}