🐛 fix(vscode): 代码阅读预览记住浏览位置,编辑 / 预览互切位置对齐

This commit is contained in:
cruldra committed 2026-09-25 03:21:14 +08:00
1 parent 6897954644
commit 37306bd23e
13 files changed
+409 -37

No files matched your search

@@ -0,0 +1,77 @@
import type { Disposable, TextEditor } from 'vscode'
import type { PreviewEditorProvider } from './previewEditor'
import { commands, Range, TabInputCustom, TextEditorRevealType, Uri, window } from 'vscode'
import { PREVIEW_VIEW_TYPE } from './previewEditor'
/** VS Code 自带普通文本编辑器的 editor id。 */
const TEXT_EDITOR = 'default'
/**
* VS Code 自带的「重新打开编辑器的方式」:在原标签页位置换成另一种编辑器,新编辑器打开后才返回。
* 原文件有未保存改动也不弹保存框——改动在 TextDocument 里,不跟着标签页走。
*/
const REOPEN_WITH = 'reopenActiveEditorWith'
/** 切换命令返回时文本编辑器还没同步到扩展这边的话,最多再等这么久 */
const EDITOR_WAIT_MS = 1000
function sameUri(a: Uri, b: Uri): boolean {
return a.toString() === b.toString()
}
/** 标题栏按钮传来的是 (文件 Uri, { groupId }),命令面板里调用时没有参数。 */
function resourceArg(args: unknown[]): Uri | undefined {
return args[0] instanceof Uri ? args[0] : undefined
}
function activeCustomEditorUri(): Uri | undefined {
const input = window.tabGroups.activeTabGroup.activeTab?.input
return input instanceof TabInputCustom ? input.uri : undefined
}
function textEditorOf(uri: Uri): TextEditor | undefined {
const active = window.activeTextEditor
if (active && sameUri(active.document.uri, uri))
return active
return window.visibleTextEditors.find(editor => sameUri(editor.document.uri, uri))
}
/** 编辑器变化和命令结果是分开通知到扩展这边的:没看到 uri 的文本编辑器就等它出现。 */
function waitForTextEditor(uri: Uri): Promise<TextEditor | undefined> {
const found = textEditorOf(uri)
if (found)
return Promise.resolve(found)
const disposables: Disposable[] = []
return new Promise<TextEditor | undefined>((resolve) => {
disposables.push(window.onDidChangeVisibleTextEditors(() => {
const editor = textEditorOf(uri)
if (editor)
resolve(editor)
}))
const timer = setTimeout(resolve, EDITOR_WAIT_MS, undefined)
disposables.push({ dispose: () => clearTimeout(timer) })
}).finally(() => disposables.forEach(d => d.dispose()))
}
/** 文本编辑器 → 预览(同一标签页原位替换):新预览先滚到文本编辑器顶部那一行所在的块。 */
export async function showPreview(previews: PreviewEditorProvider, args: unknown[]): Promise<void> {
const uri = resourceArg(args) ?? window.activeTextEditor?.document.uri
const topLine = uri ? textEditorOf(uri)?.visibleRanges[0]?.start.line : undefined
const reopen = (): Thenable<unknown> => commands.executeCommand(REOPEN_WITH, PREVIEW_VIEW_TYPE, ...args)
if (uri && topLine !== undefined)
await previews.openAtLine(uri, topLine, reopen)
else
await reopen()
}
/** 预览 → 文本编辑器(同一标签页原位替换):把预览视口顶部那块的起始行放到文本编辑器顶部。 */
export async function showSource(previews: PreviewEditorProvider, args: unknown[]): Promise<void> {
const uri = resourceArg(args) ?? activeCustomEditorUri()
const line = uri ? previews.visibleLine(uri) : undefined
await commands.executeCommand(REOPEN_WITH, TEXT_EDITOR, ...args)
if (!uri || line === undefined)
return
const editor = await waitForTextEditor(uri)
if (!editor)
return
const target = Math.min(line, editor.document.lineCount - 1)
editor.revealRange(new Range(target, 0, target, 0), TextEditorRevealType.AtTop)
}