✨ feat(vscode): 跳定义、点链接、编辑切回预览不改开着的预览对比什么

This commit is contained in:
cruldra committed 2026-10-12 16:10:41 +11:00
1 parent d4416e7b26
commit ce5327dcd5
8 files changed
+239 -47

No files matched your search

+60 -23
View File
@@ -1,6 +1,7 @@
import type { Disposable, TextEditor } from 'vscode'
import type { Disposable, TextEditor, ViewColumn } from 'vscode'
import type { OpenedFrom } from '../diff/diffBase'
import type { PreviewEditorProvider } from './previewEditor'
import { commands, Range, TabInputCustom, TextEditorRevealType, Uri, window } from 'vscode'
import { commands, Range, TabInputCustom, TabInputText, TextEditorRevealType, Uri, window } from 'vscode'
import { PREVIEW_VIEW_TYPE } from './previewEditor'
/** VS Code 自带普通文本编辑器的 editor id。 */
@@ -51,27 +52,63 @@ function waitForTextEditor(uri: Uri): Promise<TextEditor | undefined> {
}).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)
await previews.open(uri, { from: 'other', ...(topLine !== undefined && { reveal: { line: topLine } }) }, reopen)
else
await reopen()
/** 一个编辑器组里的一个文件:同一个标签页在预览和文本编辑器之间换着看时按它认。 */
function tabKey(viewColumn: ViewColumn | undefined, uri: Uri): string {
return `${viewColumn ?? ''}:${uri.toString()}`
}
/** 预览 → 文本编辑器(同一标签页原位替换):把预览视口顶部那块的起始行放到文本编辑器顶部。 */
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)
/**
* 编辑器右上角的「预览 / 编辑」:同一个标签页原位换成另一种编辑器,换回预览时照切走前的样子对比,不算从别处重新打开。
* 切走的预览是从哪儿打开的按编辑器组和文件记着,换上的那个文本编辑器标签页关了就忘掉。
*/
export class EditorSwitch implements Disposable {
/** 切到文本编辑器的预览原来是从哪儿打开的,按 [tabKey] 记 */
private readonly sourceFrom = new Map<string, OpenedFrom>()
private readonly closing: Disposable
constructor(private readonly previews: Pick<PreviewEditorProvider, 'open' | 'visibleLine' | 'openedFrom'>) {
this.closing = window.tabGroups.onDidChangeTabs(({ closed }) => {
for (const tab of closed) {
if (tab.input instanceof TabInputText)
this.sourceFrom.delete(tabKey(tab.group.viewColumn, tab.input.uri))
}
})
}
/** 文本编辑器 → 预览:新预览先滚到文本编辑器顶部那一行所在的块;这个文本编辑器是从预览切过来的,照原来的从哪儿打开。 */
async showPreview(args: unknown[]): Promise<void> {
const uri = resourceArg(args) ?? window.activeTextEditor?.document.uri
const reopen = (): Thenable<unknown> => commands.executeCommand(REOPEN_WITH, PREVIEW_VIEW_TYPE, ...args)
if (!uri) {
await reopen()
return
}
const editor = textEditorOf(uri)
const topLine = editor?.visibleRanges[0]?.start.line
const from = editor && this.sourceFrom.get(tabKey(editor.viewColumn, uri))
await this.previews.open(uri, { ...(from && { from }), ...(topLine !== undefined && { reveal: { line: topLine } }) }, reopen)
}
/** 预览 → 文本编辑器:把预览视口顶部那块的起始行放到文本编辑器顶部,记下这个预览是从哪儿打开的。 */
async showSource(args: unknown[]): Promise<void> {
const uri = resourceArg(args) ?? activeCustomEditorUri()
const line = uri ? this.previews.visibleLine(uri) : undefined
const from = uri ? this.previews.openedFrom(uri) : undefined
await commands.executeCommand(REOPEN_WITH, TEXT_EDITOR, ...args)
if (!uri || (line === undefined && from === undefined))
return
const editor = await waitForTextEditor(uri)
if (!editor)
return
if (from)
this.sourceFrom.set(tabKey(editor.viewColumn, uri), from)
if (line === undefined)
return
const target = Math.min(line, editor.document.lineCount - 1)
editor.revealRange(new Range(target, 0, target, 0), TextEditorRevealType.AtTop)
}
dispose(): void {
this.closing.dispose()
}
}