⚡ perf(vscode): 认调用分新建还是调用时,定义所在的文件按版本记着解析结果,同一版不再整份重解析;定义就在本文件时用发文档时读出的
This commit is contained in:
1 parent
80d9962856
commit
e9c1c67d6f
8 files changed
+194
-45
No files matched your search
@@ -0,0 +1,71 @@
|
||||
import type { NamedKind } from './blockView'
|
||||
import type { BlockKind, LanguageAdapter } from './contract'
|
||||
import type { TreeSitterRuntime } from './runtime'
|
||||
import { kindAt, readNamedKinds } from './blockView'
|
||||
|
||||
/** 定义所在的那份文件(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 = new Map<string, { version: number, kinds: Promise<NamedKind[] | undefined> }>()
|
||||
|
||||
constructor(
|
||||
private readonly languageFor: (languageId: string) => LanguageAdapter | undefined,
|
||||
private readonly runtime: Pick<TreeSitterRuntime, 'parse'>,
|
||||
private readonly limit = LIMIT,
|
||||
) {}
|
||||
|
||||
/** uri 这份文件 version 这一版各块的名字和种类(预览发文档时读出的)。 */
|
||||
remember(uri: string, version: number, kinds: NamedKind[]): void {
|
||||
this.keep(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)
|
||||
if (known?.version === file.version) {
|
||||
this.keep(file.uri, known.version, known.kinds)
|
||||
return known.kinds
|
||||
}
|
||||
const adapter = this.languageFor(file.languageId)
|
||||
if (!adapter)
|
||||
return Promise.resolve(undefined)
|
||||
const kinds = readNamedKinds(this.runtime, adapter, file.languageId, file.getText())
|
||||
this.keep(file.uri, file.version, kinds)
|
||||
// 解析失败的不记,下次重来
|
||||
kinds.catch(() => {
|
||||
if (this.files.get(file.uri)?.kinds === kinds)
|
||||
this.files.delete(file.uri)
|
||||
})
|
||||
return kinds
|
||||
}
|
||||
|
||||
/** 记下(或用到了)一份:挪到最近用过的那头,多了丢最久没用的。 */
|
||||
private keep(uri: string, version: number, kinds: Promise<NamedKind[] | undefined>): void {
|
||||
this.files.delete(uri)
|
||||
this.files.set(uri, { version, kinds })
|
||||
for (const oldest of this.files.keys()) {
|
||||
if (this.files.size <= this.limit)
|
||||
break
|
||||
this.files.delete(oldest)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user