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