52 lines
2.1 KiB
TypeScript
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)
|
|
}
|
|
}
|