⚡ perf(vscode): 切走的预览文件改了不在后台生成文档,切回来再补一次

This commit is contained in:
cruldra committed 2026-10-13 13:31:20 +11:00
1 parent 50672c70d1
commit 7d6e7592c9
2 files changed
+88 -9

No files matched your search

+21 -5
View File
@@ -104,7 +104,7 @@ export class PreviewEditorProvider implements CustomTextEditorProvider {
) {}
/**
* 注册成预览编辑器。标签页切走时页面留着(`retainContextWhenHidden`):切回来不用重新生成、重发文档,页面也不用整份重画,
* 注册成预览编辑器。标签页切走时页面留着(`retainContextWhenHidden`):切回来不用重新生成、重发文档(切走期间改过的才补一次),页面也不用整份重画,
* 代价是每个开着的预览切走后仍占着它那个页面的内存。
*/
register(): Disposable {
@@ -183,10 +183,14 @@ export class PreviewEditorProvider implements CustomTextEditorProvider {
class Preview {
/**
* 页面发过 ready(装好了、能收消息)之后才发消息。标签页切走时页面留着,照常收消息,切回来什么都不用补;
* 页面发过 ready(装好了、能收消息)之后才发消息。标签页切走时页面留着,照常收消息;
* 页面真的重新加载了(webview 进程崩了重建、开发者重载 webview)会再发 ready,那时整份重发
*/
private ready = false
/** 切走期间该重新生成的文档没生成(文件改了、规则变了):重新看得见时补一次;没过期的切回来什么都不用做 */
private outdated = false
/** 页面上那份文档的版本:还不是眼下这一版时(正在生成、切走期间改过),要滚到的位置等新的那份一起带过去 */
private shown: number | undefined
/** 侧栏「问 AI」打开的:页面准备好后把光标放进顶部输入框 */
private pendingPathFocus = false
/** 解析是异步的:只发最后一次请求的结果,慢的旧结果不能盖掉新的 */
@@ -226,7 +230,7 @@ class Preview {
/** 这份文件相比对比基准改了什么:发完文档再算、补发 */
private readonly diff: PreviewDiff
/**
* 随下一份真正发出去的文档走、只走一次:新预览第一份文档要滚到的位置,或页面 ready 之前又来的 reveal。
* 随下一份真正发出去的文档走、只走一次:新预览第一份文档要滚到的位置,或页面上还不是眼下这一版文档时来的 reveal。
* 之后页面真的重新加载了,按 webview 自己记的位置恢复
*/
private pendingReveal: Reveal | undefined
@@ -271,6 +275,10 @@ class Preview {
void this.diff.update(this.sent)
}),
panel.webview.onDidReceiveMessage((msg: WebviewToExtension) => this.handleMessage(msg)),
panel.onDidChangeViewState(() => {
if (panel.visible && this.outdated)
void this.push()
}),
workspace.onDidChangeTextDocument((e) => {
if (e.document !== document || e.contentChanges.length === 0)
return
@@ -366,12 +374,19 @@ class Preview {
clearTimeout(this.timer)
if (!this.ready)
return
// 切走的预览不在后台生成,后面跟着文档的查询也不起;分屏同时看得见的照常马上生成
if (!this.panel.visible) {
this.outdated = true
return
}
this.outdated = false
const request = ++this.latest
// 路径页、功能对话页:文档是空的,只在顶部聊天
if (this.document.uri.scheme === PATH_PREVIEW_SCHEME) {
this.sent = undefined
const reveal = this.pendingReveal
this.pendingReveal = undefined
this.shown = this.document.version
this.post({
type: 'document',
version: this.document.version,
@@ -401,6 +416,7 @@ class Preview {
this.imports = imports
const reveal = this.pendingReveal
this.pendingReveal = undefined
this.shown = version
this.post({ ...message, names: this.names.known(version), ...(reveal && { reveal }) })
if (this.sent)
void this.diff.update(this.sent)
@@ -513,9 +529,9 @@ class Preview {
this.focusPathAsk()
}
/** 滚到 reveal:页面 ready 了就直接发,还没 ready 就等它发 ready 后随文档带过去。 */
/** 滚到 reveal:页面上已是眼下这一版文档就直接发;还不是(还没 ready、正在生成、切走期间改过)就随新的那份文档带过去。 */
private reveal(reveal: Reveal): void {
if (this.ready)
if (this.shown === this.document.version)
this.post({ type: 'reveal', ...reveal })
else
this.pendingReveal = reveal