77 lines
3.4 KiB
TypeScript
77 lines
3.4 KiB
TypeScript
import type { IndexEntry, RuleContext, WorkspaceIndex } from './contract'
|
|
import type { DefinitionStart } from './nameResolution'
|
|
import type { IndexedEntry } from './workspaceIndex'
|
|
import { DeferredAnswers } from './deferredAnswers'
|
|
|
|
/**
|
|
* 库规则认领时查的名字(RuleContext.lookup):名字的定义在规则的工作区索引里是哪一项。
|
|
* 同「中文名」查别的文件里的定义:索引里有同名的项才问语言扩展定义在哪,定义处正是索引里那一项才算。这里不碰 VS Code。
|
|
*/
|
|
|
|
/** 规则问的一个名字:哪个索引、名字原文,和名字在源码里的下标(问语言扩展定义用)。 */
|
|
export interface LookupRequest { index: WorkspaceIndex, key: string, offset: number }
|
|
|
|
/** 查规则问的名字要问的:工作区索引里认出的各项,这份文档里 offset 处名字的定义(语言扩展)。 */
|
|
export interface LookupSources {
|
|
find: (index: WorkspaceIndex, key: string) => Promise<IndexedEntry[]>
|
|
definitions: (offset: number) => Promise<DefinitionStart[]>
|
|
}
|
|
|
|
/** 排一遍视图数据用的:交给规则的 lookup,和这一遍规则问了哪些名字。 */
|
|
export interface LookupSession {
|
|
lookup: RuleContext['lookup']
|
|
requests: () => LookupRequest[]
|
|
}
|
|
|
|
function idOf(index: WorkspaceIndex, key: string): string {
|
|
return `${index.id}\n${key}`
|
|
}
|
|
|
|
/** 查到的项对规则来说一样不一样:规则只看键和值。 */
|
|
function same(a: IndexEntry | null | undefined, b: IndexEntry | null | undefined): boolean {
|
|
return a?.key === b?.key && a?.value === b?.value
|
|
}
|
|
|
|
/**
|
|
* 一份打开着的文档里库规则问的名字查到了什么:按「索引 id + 名字原文」记,同一份文档里同名的名字按一处查;
|
|
* 什么时候查、查到了怎么叫宿主重排见 DeferredAnswers。
|
|
*/
|
|
export class DocumentLookups {
|
|
private readonly answers: DeferredAnswers<LookupRequest, IndexEntry>
|
|
|
|
constructor(changed: () => void, delays?: readonly number[], schedule?: (run: () => void, ms: number) => ReturnType<typeof setTimeout>) {
|
|
this.answers = new DeferredAnswers(({ index, key }) => idOf(index, key), same, changed, delays, schedule)
|
|
}
|
|
|
|
session(): LookupSession {
|
|
const session = this.answers.session()
|
|
return {
|
|
lookup: (index, name) => session.ask({ index, key: name.text, offset: name.startIndex }),
|
|
requests: session.questions,
|
|
}
|
|
}
|
|
|
|
/** 查 version 这一版规则问的名字:这个版本查过的不再查。 */
|
|
resolve(version: number, requests: readonly LookupRequest[], sources: LookupSources): void {
|
|
this.answers.resolve(version, requests, request => find(request, sources))
|
|
}
|
|
|
|
dispose(): void {
|
|
this.answers.dispose()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 查规则问的一个名字:索引里没有同名的项就是没有这个定义;有就问语言扩展,定义处正是其中一项才算。
|
|
* 语言扩展没答(还没起来)是 undefined。
|
|
*/
|
|
async function find({ index, key, offset }: LookupRequest, sources: LookupSources): Promise<IndexEntry | null | undefined> {
|
|
const candidates = await sources.find(index, key)
|
|
if (candidates.length === 0)
|
|
return null
|
|
const definitions = await sources.definitions(offset)
|
|
if (definitions.length === 0)
|
|
return undefined
|
|
return candidates.find(({ location }) => definitions.some(at => at.uri === location.uri && at.line === location.start.line && at.character === location.start.character))?.entry ?? null
|
|
}
|