55 lines
2.2 KiB
TypeScript
55 lines
2.2 KiB
TypeScript
import type { NamedKind } from './blockView'
|
|
import type { BlockKind, LanguageAdapter } from './contract'
|
|
import type { TreeSitterRuntime } from './runtime'
|
|
import { kindAt, readNamedKinds } from './blockView'
|
|
import { RecentPromises } from './recentPromises'
|
|
|
|
/** 定义所在的那份文件(TextDocument 的子集):uri、版本、语言、内容。 */
|
|
export interface KindSource {
|
|
uri: string
|
|
version: number
|
|
languageId: string
|
|
getText: () => string
|
|
}
|
|
|
|
/** 默认记几份文件 */
|
|
const LIMIT = 64
|
|
|
|
/**
|
|
* 调用的名字的定义是哪种块(分新建还是调用):定义所在的文件解析一遍,按 uri 记着这一版各块的名字和种类(见 NamedKind),
|
|
* 同一版再问不再解析,几处同时问同一版也只解析一次;预览发文档时把读出的那份交进来(remember),定义就在这份文档里时直接用。
|
|
* 最近用过的留 limit 份。这里不碰 VS Code。
|
|
*/
|
|
export class DefinitionKinds {
|
|
private readonly files: RecentPromises<NamedKind[] | undefined>
|
|
|
|
constructor(
|
|
private readonly languageFor: (languageId: string) => LanguageAdapter | undefined,
|
|
private readonly runtime: Pick<TreeSitterRuntime, 'parse'>,
|
|
limit = LIMIT,
|
|
) {
|
|
this.files = new RecentPromises(limit)
|
|
}
|
|
|
|
/** uri 这份文件 version 这一版各块的名字和种类(预览发文档时读出的)。 */
|
|
remember(uri: string, version: number, kinds: NamedKind[]): void {
|
|
this.files.set(uri, version, Promise.resolve(kinds))
|
|
}
|
|
|
|
/** file 里 offset 处的名字定义的是哪种块;没有语言插件、不在哪块的名字上时没有。 */
|
|
async kindAt(file: KindSource, offset: number): Promise<BlockKind | undefined> {
|
|
const kinds = await this.kindsOf(file)
|
|
return kinds && kindAt(kinds, offset)
|
|
}
|
|
|
|
private kindsOf(file: KindSource): Promise<NamedKind[] | undefined> {
|
|
const known = this.files.get(file.uri, file.version)
|
|
if (known)
|
|
return known
|
|
const adapter = this.languageFor(file.languageId)
|
|
if (!adapter)
|
|
return Promise.resolve(undefined)
|
|
return this.files.set(file.uri, file.version, readNamedKinds(this.runtime, adapter, file.languageId, file.getText()))
|
|
}
|
|
}
|