feat(def): add cross-file navigation and rename for PSC .def block templates and addresses
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.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
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)
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
defDocumentSymbolProvider,
|
||||
definitionCdlEventHandler
|
||||
} from "./common/handlers"
|
||||
import { registerDefProviders } from "./common/defProviders"
|
||||
import { registerLogger, traceError, traceLog, traceVerbose } from "./common/log/logging"
|
||||
import {
|
||||
checkVersion,
|
||||
@@ -234,6 +235,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
)
|
||||
|
||||
context.subscriptions.push(formatDefProvider)
|
||||
context.subscriptions.push(...registerDefProviders(() => client))
|
||||
|
||||
const cdlSymbolProvider = vscode.languages.registerDocumentSymbolProvider(
|
||||
{ scheme: "file", language: "cdl" },
|
||||
|
||||
Reference in New Issue
Block a user