✨ feat(vscode): 代码阅读「未提交的更改」点文件行改成打开标准预览(和主栏一样不标差异),文件行上加「打开更改」按钮才打开对比上一次提交的预览,语言没有代码阅读的走 VS Code 自带的差异视图,删掉的文件行不挂这个按钮

This commit is contained in:
cruldra committed 2026-10-14 13:47:59 +11:00
1 parent 4b6e110a44
commit c2a13e5691
18 files changed
+211 -79

No files matched your search

+1 -1
View File
@@ -208,7 +208,7 @@ export interface StickyScrollSettings {
* openFind:打开查找栏,由「查找」命令发给活动的预览
* moveFind:查找栏里跳到下一处(step 1)/ 上一处(step -1)命中,由「查找下一处 / 上一处」命令发给查找栏开着的预览
* displayNames:version 这份文档里显示成中文名的名字,查到一步发一步(先本文件定义的,再别的文件定义的);不是页面上这个版本的不理
* diff:这份文件相比对比基准改了什么(审查工作副本里的、从「未提交的更改」点开的有改动的才有,见 [对比基准](vscode/src/codeReader/diff/diffBase.ts#DiffBase)):每发一份文档之后算好了补发,
* diff:这份文件相比对比基准改了什么(审查工作副本里的、用「未提交的更改」文件行上的「打开更改」打开的有改动的才有,见 [对比基准](vscode/src/codeReader/diff/diffBase.ts#DiffBase)):每发一份文档之后算好了补发,
* 基准变了(提交后 HEAD 动了、换了审查的工单、文件有了改动、这个标签页换了从哪儿打开)再发;null 是不比了(退出了审查、改动提交了、从别处点开了)
* openedFrom:这个标签页是从哪儿打开的,页面记进自己的状态,VS Code 重启后恢复这个标签页时随 ready 报回来;ready 后发一次,开着时又从侧栏点开、换了从哪儿打开的再发
* repoLinksChecked:id 那次 checkRepoLinks 的回答,missing 是仓库里没有的路径,unresolved 是找不到的不带路径的引用(原样带回问的那几条)
@@ -1,9 +1,11 @@
import type { Uri } from 'vscode'
import { describe, expect, it, vi } from 'vitest'
import { Range, workspace } from 'vscode'
import { languageOf, linesSpot, openingFor } from './openTarget'
import type { PreviewEditorProvider } from './previewEditor'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { commands, Range, workspace } from 'vscode'
import { languageOf, linesSpot, openFile, openingFor } from './openTarget'
vi.mock('vscode', () => ({
commands: { executeCommand: vi.fn() },
workspace: { openTextDocument: vi.fn() },
Range: class {
readonly start: { line: number, character: number }
@@ -77,3 +79,58 @@ describe('文件的语言', () => {
expect(await languageOf({} as Uri)).toBeUndefined()
})
})
describe('侧栏打开文件', () => {
const uri = { path: '/ws/src/a' } as Uri
const executeCommand = vi.mocked(commands.executeCommand)
const previews = { open: vi.fn<PreviewEditorProvider['open']>(async () => {}) }
/** VS Code 把这个文件认成 languageId;undefined 是打不开成文本(图片等) */
function languageIs(languageId: string | undefined): void {
const openTextDocument = vi.mocked(workspace.openTextDocument)
if (languageId === undefined)
openTextDocument.mockRejectedValueOnce(new Error('binary'))
else
openTextDocument.mockResolvedValueOnce({ languageId } as Awaited<ReturnType<typeof workspace.openTextDocument>>)
}
beforeEach(() => {
executeCommand.mockClear()
previews.open.mockClear()
})
it('「打开更改」:语言有代码阅读的用预览打开,带上 uncommitted(预览对比上一次提交)', async () => {
languageIs('python')
await openFile(uri, 'uncommitted', supports, previews)
expect(previews.open).toHaveBeenCalledWith(uri, { from: 'uncommitted' })
expect(executeCommand).not.toHaveBeenCalled()
})
it('「打开更改」:预览打不开的(语言没有代码阅读、打不开成文本)用 VS Code 自带的差异视图', async () => {
for (const languageId of ['c', undefined]) {
languageIs(languageId)
await openFile(uri, 'uncommitted', supports, previews)
expect(executeCommand).toHaveBeenLastCalledWith('git.openChange', uri)
}
expect(previews.open).not.toHaveBeenCalled()
})
it('点文件行:语言有代码阅读的用预览打开、带上 other(不标差异),没有的用 VS Code 默认的打开方式', async () => {
languageIs('python')
await openFile(uri, 'other', supports, previews)
expect(previews.open).toHaveBeenCalledWith(uri, { from: 'other' })
languageIs('c')
await openFile(uri, 'other', supports, previews)
expect(executeCommand).toHaveBeenCalledWith('vscode.open', uri, undefined)
expect(executeCommand).not.toHaveBeenCalledWith('git.openChange', expect.anything())
})
it('给了位置:预览滚过去、闪这处定义,普通编辑器选中它', async () => {
languageIs('python')
await openFile(uri, 'other', supports, previews, spot)
expect(previews.open).toHaveBeenCalledWith(uri, { from: 'other', reveal: { line: 41, definition: 1200 } })
languageIs('c')
await openFile(uri, 'other', supports, previews, spot)
expect(executeCommand).toHaveBeenCalledWith('vscode.open', uri, { selection: range })
})
})
+26 -1
View File
@@ -1,6 +1,8 @@
import type { Uri } from 'vscode'
import type { OpenedFrom } from '../diff/diffBase'
import type { LineRange, Reveal } from './messages'
import { Range, workspace } from 'vscode'
import type { PreviewEditorProvider } from './previewEditor'
import { commands, Range, workspace } from 'vscode'
/**
* 别的文件里要打开的一处:普通编辑器选中 `range`;预览按 `offset`(定义处的下标)滚过去、闪这处定义。
@@ -29,6 +31,29 @@ export function openingFor(languageId: string | undefined, supports: (languageId
return { kind: 'default', ...(spot && { selection: spot.range }) }
}
/**
* 侧栏打开一个文件(点文件行、点「打开更改」、点「了解一块代码」栏里的一条):语言受支持的用预览打开,告诉预览是从哪儿打开的;
* 预览打不开的(见 [openingFor]),从「打开更改」来的用 VS Code 自带的差异视图看这个文件的改动,别处来的用 VS Code 默认的打开方式。
*
* @param uri 要打开的文件
* @param from 从哪儿打开的:`uncommitted` 时预览标出和上一次提交的差异
* @param supports 这种语言有没有代码阅读
* @param previews 语言受支持时用它打开预览
* @param spot 要跳到的那一处(预览滚过去、闪一下,普通编辑器选中它);只打开文件时没有
*/
export async function openFile(uri: Uri, from: OpenedFrom, supports: (languageId: string) => boolean, previews: Pick<PreviewEditorProvider, 'open'>, spot?: TargetSpot): Promise<void> {
const opening = openingFor(await languageOf(uri), supports, spot)
if (opening.kind === 'preview') {
await previews.open(uri, { from, ...(opening.reveal && { reveal: opening.reveal }) })
return
}
if (from === 'uncommitted') {
await commands.executeCommand('git.openChange', uri)
return
}
await commands.executeCommand('vscode.open', uri, opening.selection && { selection: opening.selection })
}
/** 预览怎么滚到这一处:有 `offset` 的跳到定义,没有的跳到 `range` 那几行。 */
export function revealOf({ range, offset }: TargetSpot): Reveal {
return offset === undefined ? { line: range.start.line, endLine: range.end.line } : { line: range.start.line, definition: offset }
@@ -197,7 +197,7 @@ function themeColors(colors: CodeColors) {
}
}
/** 对比基准只认从「未提交的更改」点开的:从那儿点开的对比上一次提交,别处打开的不比 */
/** 对比基准只认用「未提交的更改」文件行上的「打开更改」打开的:这样打开的对比上一次提交,别处打开的不比 */
function opening(profiles = { ask: profileSet(''), rewrite: profileSet('') }, colors = themeColors(COLORS), languageFor: (languageId: string) => unknown = () => undefined) {
const subscribe = () => ({ dispose: () => {} })
const diffBase = vi.fn((_uri: unknown, from: OpenedFrom): DiffBase | undefined => from === 'uncommitted' ? HEAD_BASE : undefined)
@@ -276,7 +276,7 @@ function edit(document: { version: number }, version: number): void {
const comparedWithHead = expect.objectContaining({ type: 'diff', diff: expect.objectContaining({ base: '上一次提交' }) })
describe('预览对比什么看这个标签页是从哪儿打开的', () => {
it('从「未提交的更改」点开的新预览对比上一次提交,页面记下是从哪儿打开的', async () => {
it('用「打开更改」打开的新预览对比上一次提交,页面记下是从哪儿打开的', async () => {
const { provider, document } = opening()
const page = tab()
await provider.open(document.uri as never, { from: 'uncommitted' }, async () => provider.resolveCustomTextEditor(document as never, page.panel))
@@ -307,7 +307,7 @@ describe('预览对比什么看这个标签页是从哪儿打开的', () => {
expect(diffBase).not.toHaveBeenCalledWith(document.uri, 'uncommitted')
})
it('开着的预览再从主栏点开就不比,再从「未提交的更改」点开又比;页面重新加载后按它记着的照旧比', async () => {
it('开着的预览再点文件行打开就不比,再点「打开更改」又比;页面重新加载后按它记着的照旧比', async () => {
const { provider, document } = opening()
const page = tab()
await provider.open(document.uri as never, { from: 'uncommitted' }, async () => provider.resolveCustomTextEditor(document as never, page.panel))