✨ feat(vscode): 代码阅读预览按侧栏筛选算代码差异(未提交的更改对比上一次提交、审查对比 PR 目标分支;兄弟块按名字 / 相似度对齐,卡片内按行 / 值 / 词比对),算好后补发给预览

This commit is contained in:
cruldra committed 2026-09-30 08:35:17 +08:00
1 parent 3db44f84ae
commit 2a5806c6b5
23 files changed
+1527 -31

No files matched your search

+26 -2
View File
@@ -1,6 +1,7 @@
import type { TreeView } from 'vscode'
import type { Event, TreeView, Uri } from 'vscode'
import type { DiffBase } from '../diff/diffBase'
import type { FileTreeProvider, TreeNode } from './fileTree'
import { commands, Disposable } from 'vscode'
import { commands, Disposable, EventEmitter } from 'vscode'
/** 上下文键:侧栏树开着哪种筛选,没设是全部文件。标题栏的「显示全部」、行上的注释按钮按它显示 / 藏起来。 */
const FILTER_CONTEXT = 'superpowers.codeReader.filter'
@@ -14,18 +15,39 @@ export interface TreeFilter {
reload: () => Promise<void>
/** 「显示全部」或换成别的筛选:不再筛、不再记着,正在进的作废 */
exit: () => Promise<void>
/** 开着这种筛选时 uri 这个文件的预览对比什么(见 DiffBase);不在这种筛选管的范围里(仓库外、工作副本外)时没有 */
diffBase: (uri: Uri) => DiffBase | undefined
}
/**
* 侧栏树上的几种筛选,同时只开一种:开一种时别的都退出;上下文键跟着开着的那种。
* 筛选开起来时自己换上树、标题后面的字(description)、标题下面的一行(message);退出时由这里回到工作区文件树。
* 开着的筛选也定打开着的预览对比什么(diffBase),换了筛选、基准变了都通知预览重新比。
*/
export class TreeFilters {
private readonly filters: TreeFilter[] = []
private current: TreeFilter | undefined
private readonly baseChange = new EventEmitter<void>()
/** 开着的筛选换了(开了、换了、关了),或它的对比基准变了(git 状态变了、审查重读了 PR):打开着的预览照 diffBase 重新比 */
readonly onDidChangeDiffBase: Event<void> = this.baseChange.event
constructor(private readonly files: FileTreeProvider, private readonly view: TreeView<TreeNode>) {}
/** 开着的筛选下 uri 这个文件的预览对比什么;没开筛选(全部文件)时没有,预览不标差异。 */
diffBase(uri: Uri): DiffBase | undefined {
return this.current?.diffBase(uri)
}
/** filter 的对比基准变了时调;它没开着就不理。 */
baseChanged(filter: TreeFilter): void {
if (this.current === filter)
this.baseChange.fire()
}
dispose(): void {
this.baseChange.dispose()
}
/** 开着的那种筛选;没开是全部文件 */
get active(): TreeFilter | undefined {
return this.current
@@ -57,6 +79,7 @@ export class TreeFilters {
/** filter 换上侧栏树之前调:别的筛选都退出(同步的部分在这里就做完了,调用方紧接着换上自己的),上下文键设成 kind。 */
async enter(filter: TreeFilter, kind: TreeFilterKind): Promise<void> {
this.current = filter
this.baseChange.fire()
await Promise.all([
...this.filters.filter(other => other !== filter).map(other => other.exit()),
commands.executeCommand('setContext', FILTER_CONTEXT, kind),
@@ -68,6 +91,7 @@ export class TreeFilters {
if (this.current !== filter)
return
this.current = undefined
this.baseChange.fire()
this.files.showChanges(undefined)
this.view.description = undefined
this.view.message = undefined