✨ feat(vscode): 只有从「未提交的更改」点开的预览才对比上一次提交

This commit is contained in:
cruldra committed 2026-10-12 15:52:35 +11:00
1 parent 4ec2b9d5d6
commit 3c7513b7cd
18 files changed
+366 -143

No files matched your search

+14 -10
View File
@@ -1,7 +1,7 @@
import type { Uri } from 'vscode'
import type { DiffBase, DiffBaseSource } from './diffBase'
import { describe, expect, it, vi } from 'vitest'
import { locatedDiffBases } from './diffBase'
import { previewDiffBases } from './diffBase'
vi.mock('vscode', () => ({
Disposable: {
@@ -25,20 +25,24 @@ function source(root: string, label: string): DiffBaseSource & { fire: () => voi
}
}
describe('预览按文件所在的位置取对比基准', () => {
describe('预览对比什么:审查按位置,上一次提交看是不是从「未提交的更改」点开的', () => {
const review = source('/worktrees/issue-446', 'PR 目标分支 master')
const head = source('/ws', '上一次提交')
const bases = locatedDiffBases([review, head])
const bases = previewDiffBases(review, head)
it('审查工作副本里的对比 PR 目标分支,工作区仓库里的对比上一次提交,都不管的不比', () => {
expect(bases.diffBase(uri('/worktrees/issue-446/src/a.ts'))?.label).toBe('PR 目标分支 master')
expect(bases.diffBase(uri('/ws/src/a.ts'))?.label).toBe('上一次提交')
expect(bases.diffBase(uri('/elsewhere/a.ts'))).toBeUndefined()
it('审查工作副本里的文件对比 PR 目标分支,从哪儿打开的都一样', () => {
expect(bases.diffBase(uri('/worktrees/issue-446/src/a.ts'), 'uncommitted')?.label).toBe('PR 目标分支 master')
expect(bases.diffBase(uri('/worktrees/issue-446/src/a.ts'), 'other')?.label).toBe('PR 目标分支 master')
})
it('两方都管的文件按顺序取前面那方', () => {
const both = locatedDiffBases([source('/ws', '前面'), source('/ws', '后面')])
expect(both.diffBase(uri('/ws/a.ts'))?.label).toBe('前面')
it('工作区仓库里有改动的文件:从「未提交的更改」点开的对比上一次提交,别处打开的不比', () => {
expect(bases.diffBase(uri('/ws/src/a.ts'), 'uncommitted')?.label).toBe('上一次提交')
expect(bases.diffBase(uri('/ws/src/a.ts'), 'other')).toBeUndefined()
})
it('两方都不管的不比', () => {
expect(bases.diffBase(uri('/elsewhere/a.ts'), 'uncommitted')).toBeUndefined()
expect(bases.diffBase(uri('/elsewhere/a.ts'), 'other')).toBeUndefined()
})
it('哪一方的基准变了都通知预览重新问;不听了就不再通知', () => {
+17 -13
View File
@@ -3,7 +3,7 @@ import { Disposable } from 'vscode'
/**
* 对比基准:预览拿它取这个文件改之前的样子,和现在的比出差异。
* 按文件所在的位置给(见 locatedDiffBases):审查工作副本里的对比 PR 的目标分支,工作区仓库里有改动的对比上一次提交。
* 给哪个基准见 [previewDiffBases]:审查工作副本里的对比 PR 的目标分支,从「未提交的更改」一栏点开的有改动的文件对比上一次提交。
*/
export interface DiffBase {
/** 筛选栏上「对比:」后面的字:「上一次提交」「PR 目标分支 master」 */
@@ -22,22 +22,26 @@ export interface DiffBaseSource {
readonly onDidChange: Event<void>
}
/** 一个预览标签页是从哪儿打开的:从侧栏「未提交的更改」一栏点开的是 `uncommitted`,别处(主栏、收藏栏、点链接、跳定义……)打开的是 `other`。 */
export type OpenedFrom = 'uncommitted' | 'other'
/** 预览问对比基准的地方:同一个文件从哪儿打开的不一样,对比的也可能不一样;基准变了发 onDidChange,打开着的预览重新问。 */
export interface PreviewDiffBases {
diffBase: (uri: Uri, from: OpenedFrom) => DiffBase | undefined
readonly onDidChange: Event<void>
}
/**
* 预览对比什么按文件所在的位置定,不看是从哪一栏、点链接还是切标签打开的:
* 按顺序问各方(审查工作副本在前、工作区仓库在后),第一个管这个文件的说了算,都不管的不比;哪一方的基准变了都通知。
* 预览对比什么:审查工作副本里的文件不管从哪儿打开都对比 PR 的目标分支,其余的只有从「未提交的更改」一栏点开的才对比上一次提交,别处打开的不比。
*
* @param review 审查:工作副本里的文件给 PR 目标分支
* @param uncommitted 工作区仓库里有改动的文件给上一次提交
*/
export function locatedDiffBases(sources: readonly DiffBaseSource[]): DiffBaseSource {
export function previewDiffBases(review: DiffBaseSource, uncommitted: DiffBaseSource): PreviewDiffBases {
return {
diffBase: (uri) => {
for (const source of sources) {
const base = source.diffBase(uri)
if (base)
return base
}
return undefined
},
diffBase: (uri, from) => review.diffBase(uri) ?? (from === 'uncommitted' ? uncommitted.diffBase(uri) : undefined),
onDidChange: (listener, thisArgs, disposables) => {
const all = Disposable.from(...sources.map(source => source.onDidChange(listener, thisArgs)))
const all = Disposable.from(review.onDidChange(listener, thisArgs), uncommitted.onDidChange(listener, thisArgs))
disposables?.push(all)
return all
},
+1 -1
View File
@@ -75,7 +75,7 @@ export class PreviewDiff {
private showing = false
constructor(
/** 眼下对比的基准;没有是不比(普通文件树) */
/** 眼下对比的基准;没有是不比(别处打开的、没有改动的) */
private readonly baseOf: () => DiffBase | undefined,
/** 用这份文档的语言、翻译插件和库规则解析旧版本;解析失败是 undefined */
private readonly readOld: (source: string) => Promise<OldDocument | undefined>,