Files
superwork/vscode/src/codeReader/editor/definitionSources.ts
T

52 lines
2.1 KiB
TypeScript

import type { BlockView } from '../blockView'
import type { RuleReference } from '../contract'
import { referencedSegments } from '../libraryRules'
/** 视图数据里库规则标了引用的名字:源码下标 → 引用。引用只出在规则认领的块的属性表里。 */
export function referencesIn(blocks: readonly BlockView[]): Map<number, RuleReference> {
const found = new Map<number, RuleReference>()
const visit = (list: readonly BlockView[]): void => {
for (const block of list) {
if ('properties' in block) {
for (const { offset, reference } of referencedSegments(block.properties)) {
if (offset !== undefined && reference)
found.set(offset, reference)
}
}
visit(block.children)
}
}
visit(blocks)
return found
}
/** 两处查定义的地方:库规则(查它自己标的引用)和语言扩展(其余的名字,和普通编辑器同一套)。 */
export interface DefinitionProviders<L> {
rule: (reference: RuleReference) => Promise<L[]>
language: (offset: number) => Promise<L[]>
}
/**
* 预览里一个名字的定义去哪儿查:发出去的文档里库规则标了引用的问规则,其余问语言扩展。
* webview 只报名字的源码下标,⌘ / Ctrl 悬停、点击都走这一条路,链接样子、跳转、挑选、闪都一样。
* 引用按最近发出去的那份文档记,只对它的版本有效。
*/
export class DefinitionSources<L> {
private version: number | undefined
private references = new Map<number, RuleReference>()
constructor(private readonly providers: DefinitionProviders<L>) {}
/** 发出去了一份文档:记下它里面的引用。 */
remember(version: number, blocks: readonly BlockView[]): void {
this.version = version
this.references = referencesIn(blocks)
}
/** version 这份文档里 offset 处名字的各处定义。 */
locate(version: number, offset: number): Promise<L[]> {
const reference = version === this.version ? this.references.get(offset) : undefined
return reference ? this.providers.rule(reference) : this.providers.language(offset)
}
}