⚡ perf(vscode): 标差异时旧版本的解析结果按旧内容记着,晚到的答案、翻译插件没变就不再重新解析

This commit is contained in:
cruldra committed 2026-10-13 14:15:33 +11:00
1 parent e9c1c67d6f
commit 5a0c5490ea
8 files changed
+87 -8

No files matched your search

+22 -3
View File
@@ -23,11 +23,12 @@ function base(text: string | null, key = 'k'): DiffBase & { read: ReturnType<typ
return { label: '上一次提交', key, read: vi.fn(async () => text), missing: '上一次提交里没有这个文件' }
}
function setup(current: { base: DiffBase | undefined }) {
function setup(current: { base: DiffBase | undefined, inputs?: string }) {
const posted: (DocumentDiff | null)[] = []
const reports: string[] = []
const diff = new PreviewDiff(() => current.base, parse, value => posted.push(value), message => reports.push(message))
return { diff, posted, reports }
const read = vi.fn(parse)
const diff = new PreviewDiff(() => current.base, read, () => current.inputs ?? '', value => posted.push(value), message => reports.push(message))
return { diff, posted, reports, read }
}
describe('previewDiff', () => {
@@ -75,6 +76,24 @@ describe('previewDiff', () => {
expect(second.read).toHaveBeenCalledTimes(1)
})
it('旧版本解析出来的按旧内容和解析时看的东西(翻译插件、晚到的答案……)记着:都没变不再解析,哪个变了重新解析', async () => {
const current: { base: DiffBase | undefined, inputs: string } = { base: base('x = 1\n', 'a'), inputs: 'v1' }
const { diff, posted, read } = setup(current)
await diff.update(await sent('x = 2\n', 1))
await diff.update(await sent('x = 3\n', 2))
expect(read).toHaveBeenCalledTimes(1)
expect(posted.at(-1)).toMatchObject({ version: 2, stats: { mod: 1 } })
current.inputs = 'v2'
await diff.update(await sent('x = 3\n', 3))
expect(read).toHaveBeenCalledTimes(2)
current.base = base('y = 1\n', 'b')
await diff.update(await sent('x = 3\n', 4))
expect(read).toHaveBeenCalledTimes(3)
current.base = base('y = 1\n', 'c')
await diff.update(await sent('x = 3\n', 5))
expect(read).toHaveBeenCalledTimes(3)
})
it('同一份文档、同一个基准不再比', async () => {
const { diff, posted } = setup({ base: base('x = 1\n') })
const doc = await sent('x = 2\n')
+20 -3
View File
@@ -61,12 +61,14 @@ export function documentDiff(base: DiffBase, sent: SentDocument, old: { source:
/**
* 一个打开着的预览的差异:每发出一份文档之后、对比基准变了之后按眼下的基准重新比,比完再发,预览先照常画、不等它。
* 取过的旧内容按基准的 key 记着(编辑时不用每次去问 git),旧版本每次重新解析:规则查到的定义、调用的种类这些晚到的答案两边要一样。
* 这里不碰 VS Code。
* 取过的旧内容按基准的 key 记着(编辑时不用每次去问 git);旧版本解析出来的按旧内容和解析时还看的东西(oldInputs)记着,
* 都没变不再解析,规则查到的定义、调用的种类这些晚到的答案变了才重新解析,两边同样的写法翻得一样。这里不碰 VS Code。
*/
export class PreviewDiff {
/** 取过的旧内容;key 相同不再取,取失败了下次重取 */
private old: { key: string, text: Promise<string | null> } | undefined
/** 解析过的旧版本;旧内容、oldInputs 都没变不再解析,解析出错了下次重来 */
private parsed: { text: string, inputs: string, document: Promise<OldDocument | undefined> } | undefined
/** 只发最后一次比的结果:慢的旧结果不能盖掉新的 */
private latest = 0
/** 上一次比的是哪份文档、哪个基准:都没变就不再比(git 状态变了、基准没挪) */
@@ -79,6 +81,8 @@ export class PreviewDiff {
private readonly baseOf: () => DiffBase | undefined,
/** 用这份文档的语言、翻译插件和库规则解析旧版本;解析失败是 undefined */
private readonly readOld: (source: string) => Promise<OldDocument | undefined>,
/** 解析旧版本除了旧内容还看的东西(翻译插件、项目入口、晚到的答案)拼成的一串:变了旧版本要重新解析 */
private readonly oldInputs: () => string,
private readonly post: (diff: DocumentDiff | null) => void,
private readonly report: (message: string) => void,
) {}
@@ -97,7 +101,7 @@ export class PreviewDiff {
}
try {
const text = await this.oldText(base)
const document = text === null ? undefined : await this.readOld(text)
const document = text === null ? undefined : await this.oldDocument(text)
if (request !== this.latest)
return
if (text !== null && !document) {
@@ -135,4 +139,17 @@ export class PreviewDiff {
}
return this.old.text
}
private oldDocument(text: string): Promise<OldDocument | undefined> {
const inputs = this.oldInputs()
if (this.parsed?.text !== text || this.parsed.inputs !== inputs) {
const document = this.readOld(text)
this.parsed = { text, inputs, document }
document.catch(() => {
if (this.parsed?.document === document)
this.parsed = undefined
})
}
return this.parsed.document
}
}