Add client and server support to navigate, inspect, reference, and rename block template and address symbols declared in PSC .def files: - Client: register language providers for .def (definition, hover, references, prepare/provide rename) and send the current document text with each request. - Server: parse .def files into DefDocument/DefDeclaration/DefReference, expose def-specific LSP endpoints (definition/hover/references/prepareRename/rename), and integrate .def lookups into existing Tcl hover/definition/references/rename flows so Tcl calls jump to .def declarations. - Tcl server keeps a snapshot API for .def documents (current editor content can replace file on request); only declared names in loaded .def files can be renamed. Name validation uses DEF_NAME_RE. Update README and CHANGELOG to document navigation features.
82 lines
3.7 KiB
TypeScript
82 lines
3.7 KiB
TypeScript
import * as vscode from "vscode"
|
|
import { LanguageClient, Range, State } from "vscode-languageclient/node"
|
|
|
|
// .def files are not synchronized with the language server, so each request
|
|
// carries the current text of the document.
|
|
const DEF_SELECTOR: vscode.DocumentSelector = { scheme: "file", language: "def" }
|
|
|
|
function params(document: vscode.TextDocument, position: vscode.Position, extra: object = {}) {
|
|
return {
|
|
textDocument: { uri: document.uri.toString() },
|
|
position: { line: position.line, character: position.character },
|
|
text: document.getText(),
|
|
...extra
|
|
}
|
|
}
|
|
|
|
export function registerDefProviders(getClient: () => LanguageClient | undefined): vscode.Disposable[] {
|
|
const request = async <T>(
|
|
method: string,
|
|
document: vscode.TextDocument,
|
|
position: vscode.Position,
|
|
token: vscode.CancellationToken,
|
|
extra: object = {}
|
|
): Promise<{ client: LanguageClient; result: T } | undefined> => {
|
|
const client = getClient()
|
|
if (!client || client.state !== State.Running) {
|
|
return undefined
|
|
}
|
|
const result = await client.sendRequest<T>(method, params(document, position, extra), token)
|
|
return result ? { client, result } : undefined
|
|
}
|
|
|
|
return [
|
|
vscode.languages.registerDefinitionProvider(DEF_SELECTOR, {
|
|
async provideDefinition(document, position, token) {
|
|
const response = await request<any>("nxPostSupport/def/definition", document, position, token)
|
|
return response && response.client.protocol2CodeConverter.asDefinitionResult(response.result, token)
|
|
}
|
|
}),
|
|
vscode.languages.registerHoverProvider(DEF_SELECTOR, {
|
|
async provideHover(document, position, token) {
|
|
const response = await request<any>("nxPostSupport/def/hover", document, position, token)
|
|
return response && response.client.protocol2CodeConverter.asHover(response.result)
|
|
}
|
|
}),
|
|
vscode.languages.registerReferenceProvider(DEF_SELECTOR, {
|
|
async provideReferences(document, position, context, token) {
|
|
const response = await request<any>("nxPostSupport/def/references", document, position, token, {
|
|
includeDeclaration: context.includeDeclaration
|
|
})
|
|
return response && response.client.protocol2CodeConverter.asReferences(response.result, token)
|
|
}
|
|
}),
|
|
vscode.languages.registerRenameProvider(DEF_SELECTOR, {
|
|
async prepareRename(document, position, token) {
|
|
const response = await request<{ range: Range; placeholder: string }>(
|
|
"nxPostSupport/def/prepareRename",
|
|
document,
|
|
position,
|
|
token
|
|
)
|
|
if (!response) {
|
|
throw new Error("Only declared block templates and addresses can be renamed.")
|
|
}
|
|
return {
|
|
range: response.client.protocol2CodeConverter.asRange(response.result.range),
|
|
placeholder: response.result.placeholder
|
|
}
|
|
},
|
|
async provideRenameEdits(document, position, newName, token) {
|
|
const response = await request<any>("nxPostSupport/def/rename", document, position, token, {
|
|
newName
|
|
})
|
|
if (!response) {
|
|
throw new Error(`"${newName}" is not a valid block template or address name.`)
|
|
}
|
|
return response.client.protocol2CodeConverter.asWorkspaceEdit(response.result, token)
|
|
}
|
|
})
|
|
]
|
|
}
|