✨ feat(vscode): 代码阅读侧栏拆成多栏:常驻未提交的更改、收藏目录各占一栏
This commit is contained in:
1 parent
45e526afa9
commit
b40ddb5e3a
27 files changed
+2427
-674
No files matched your search
@@ -0,0 +1,55 @@
|
||||
import type { Uri } from 'vscode'
|
||||
import type { DiffBase, DiffBaseSource } from './diffBase'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { locatedDiffBases } from './diffBase'
|
||||
|
||||
vi.mock('vscode', () => ({
|
||||
Disposable: {
|
||||
from: (...items: { dispose: () => void }[]) => ({ dispose: () => items.forEach(item => item.dispose()) }),
|
||||
},
|
||||
}))
|
||||
|
||||
const uri = (path: string): Uri => ({ path }) as Uri
|
||||
const base = (label: string): DiffBase => ({ label, key: label, read: async () => null, missing: '' })
|
||||
|
||||
/** 只管 root 下面的文件的一方;fire 模拟它的基准变了 */
|
||||
function source(root: string, label: string): DiffBaseSource & { fire: () => void } {
|
||||
const listeners = new Set<() => void>()
|
||||
return {
|
||||
diffBase: file => file.path.startsWith(`${root}/`) ? base(label) : undefined,
|
||||
onDidChange: (listener) => {
|
||||
listeners.add(listener)
|
||||
return { dispose: () => listeners.delete(listener) }
|
||||
},
|
||||
fire: () => listeners.forEach(listener => listener()),
|
||||
}
|
||||
}
|
||||
|
||||
describe('预览按文件所在的位置取对比基准', () => {
|
||||
const review = source('/worktrees/issue-446', 'PR 目标分支 master')
|
||||
const head = source('/ws', '上一次提交')
|
||||
const bases = locatedDiffBases([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('两方都管的文件按顺序取前面那方', () => {
|
||||
const both = locatedDiffBases([source('/ws', '前面'), source('/ws', '后面')])
|
||||
expect(both.diffBase(uri('/ws/a.ts'))?.label).toBe('前面')
|
||||
})
|
||||
|
||||
it('哪一方的基准变了都通知预览重新问;不听了就不再通知', () => {
|
||||
const changed = vi.fn()
|
||||
const listening = bases.onDidChange(changed)
|
||||
review.fire()
|
||||
head.fire()
|
||||
expect(changed).toHaveBeenCalledTimes(2)
|
||||
|
||||
listening.dispose()
|
||||
head.fire()
|
||||
expect(changed).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { Event, Uri } from 'vscode'
|
||||
import { Disposable } from 'vscode'
|
||||
|
||||
/**
|
||||
* 对比基准:侧栏只列改动的文件时(「未提交的更改」对比上一次提交,「选工单」审查对比 PR 的目标分支),
|
||||
* 预览拿它取这个文件改之前的样子,和现在的比出差异。由开着的那种侧栏筛选给(TreeFilter.diffBase)。
|
||||
* 对比基准:预览拿它取这个文件改之前的样子,和现在的比出差异。
|
||||
* 按文件所在的位置给(见 locatedDiffBases):审查工作副本里的对比 PR 的目标分支,工作区仓库里有改动的对比上一次提交。
|
||||
*/
|
||||
export interface DiffBase {
|
||||
/** 筛选栏上「对比:」后面的字:「上一次提交」「PR 目标分支 master」 */
|
||||
@@ -12,3 +15,31 @@ export interface DiffBase {
|
||||
/** 基准里没有这个文件时横幅上的一句说明 */
|
||||
missing: string
|
||||
}
|
||||
|
||||
/** 给对比基准的一方:它管的文件给基准,不管的没有;基准变了(HEAD 动了、换了审查的 PR)发 onDidChange,打开着的预览重新问。 */
|
||||
export interface DiffBaseSource {
|
||||
diffBase: (uri: Uri) => DiffBase | undefined
|
||||
readonly onDidChange: Event<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览对比什么按文件所在的位置定,不看是从哪一栏、点链接还是切标签打开的:
|
||||
* 按顺序问各方(审查工作副本在前、工作区仓库在后),第一个管这个文件的说了算,都不管的不比;哪一方的基准变了都通知。
|
||||
*/
|
||||
export function locatedDiffBases(sources: readonly DiffBaseSource[]): DiffBaseSource {
|
||||
return {
|
||||
diffBase: (uri) => {
|
||||
for (const source of sources) {
|
||||
const base = source.diffBase(uri)
|
||||
if (base)
|
||||
return base
|
||||
}
|
||||
return undefined
|
||||
},
|
||||
onDidChange: (listener, thisArgs, disposables) => {
|
||||
const all = Disposable.from(...sources.map(source => source.onDidChange(listener, thisArgs)))
|
||||
disposables?.push(all)
|
||||
return all
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user