Skip to content

fix(windows): 单文件工作区 Diff 可展开省略的代码行 (#557) - #1009

Merged
1lck merged 3 commits into
previewfrom
fix/557-diff-expand-hidden-lines
Oct 1, 2026
Merged

1lck merged 3 commits into
previewfrom
fix/557-diff-expand-hidden-lines

Conversation

@1lck

@1lck 1lck commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Closes #557

问题

Windows 端「源代码管理 → 更改」中点开单个文件的 Diff 后,无法展开两个修改块之间省略的未改动代码。#910 修复了 Diff 自动关闭,但折叠/展开按钮也一起消失了(issue 最新评论:“之前有按钮现在按钮都没有了”)。

根因

  1. 补丁里本来就没有这些行:单文件 Diff 用的是 Git 默认的稀疏补丁,只带每个修改块附近的上下文,中间的代码根本不在数据里,所以没有可“展开”的内容。
  2. 折叠被强制关闭:monaco-git-diff.tsx 传了 collapse: false,Monaco 不生成折叠条,按钮因此消失。
  3. 首次打开不折叠(修复过程中发现):渲染器先挂载空模型,Monaco 会把旧折叠状态带到新内容上。空模型没有未改动区域,所以第一份真实文本的所有区域都被当成“已展开”,开了折叠也不显示折叠条。

改动

请求完整文件内容(Windows 前端)

  • api/git-diff-api.ts:getWorkingTreePathDiff 新增 fullContext 参数;新增 getFullContextFileDiff(暂存区单文件),用独立的 read key,不写入现有 getFileDiff 缓存,避免行号栏、AI 等需要稀疏补丁的调用方拿到整份文件。两者请求 contextLines: 2147483647(Git 接受的最大值),结果标记 is_full_context: true。
  • types/git.types.ts:GitDiff 新增可选字段 is_full_context。
  • 单文件打开与刷新切到完整上下文:hooks/use-git-diff-actions.ts(有/无 Git 状态两条路径)、services/working-tree-diff-refresh.ts(默认 loader)、sidebar/utils/open-sidebar-resource.ts(侧边栏拖出的单文件 Diff)。
  • 多文件、提交历史、分支比较、stash 仍用稀疏补丁,行为不变。

按块暂存保持原粒度(Windows 前端)

  • utils/monaco-diff-rows.ts:完整上下文补丁只有一个 @@ -1,N +1,N @@,直接拿来暂存会一次把整个文件写进索引。现在按 Git 默认 3 行上下文重新切出分块(相邻修改块的合并规则与 Git 一致),并生成正确的 @@ 范围(包括空侧的 -0,0 写法)。完整文件的 @@ 行不再显示;每块第一处修改标记 actionAnchor,用来放「暂存/取消暂存」按钮。
  • components/diff/monaco-git-diff.tsx:只有 is_full_context 的补丁才开启折叠,稀疏补丁维持 collapse: false。

共享渲染器(frontend/editor/src/diff-review.ts)

  • ReviewRow 新增可选 actionAnchor。按钮区(view zone)的位置改为按每一侧实际显示的行数计算:锚点行只在一侧存在时(例如纯新增行在左侧没有),左右两侧仍保持对齐。原有 @@ 信息行的位置算法不变。
  • 文本被替换时重新挂接模型(setModel(null) → setModel(...)),让 Monaco 的未改动区域从头计算并默认折叠。文本相同的刷新(比如 Git 元数据变化)不重挂,读者已展开的区域会保留。

验证与文档

  • .agents/notes/.../2026-09-15-macos-monaco-feasibility-probe.md:补充为什么只对单文件用完整上下文、分块如何切、为什么要重挂模型。
  • shared/platform-feature-matrix.json:git-diff-review 的验证动作补充“展开折叠且每块仍可单独暂存”,并重新生成 docs/development/ 下两个视图。实现状态和验证状态不变。

验证

  • bun test src/features/git src/features/sidebar:412 个全部通过。新增内容:

    • monaco-diff-rows.test.ts:同一次修改的真实 git diff --unified=2147483647 和默认 --unified=3 输出逐块比对,确认切出的分块与 Git 一致;另有空侧 @@ 范围、非完整上下文不变、非法分块 ID 拒绝等用例。
    • git-status-api.test.ts:两个 API 发出的 contextLines 请求和 is_full_context 标记。
  • cargo test(lithe-core):新增 git_snapshot_diff_returns_the_whole_file_for_maximum_context,用真实 Git 仓库确认快照 Diff 接受最大上下文并返回单个完整分块。

  • cargo test(src-tauri):新增 preserves_full_file_context_for_single_file_review,platform::tests 37 个全部通过。

  • 真实 WebKit 集成(./scripts/probe-macos-monaco.sh --workbench-tests,CI 中已有):新增“首次完整文件 Diff 默认折叠、只有一个按钮、搜索可揭示折叠行”,68 个全部通过。去掉重挂模型后该用例会失败,已验证。

  • 浏览器内手动验证(Vite + 真实 Monaco,临时页面已删除):折叠条显示“88 hidden lines”;点击展开后原本隐藏的代码出现,Diff 不关闭;Stage 按钮回传派生分块 ID;并排与合并视图都能折叠,且各只有一个按钮区。

  • bun run typecheck、vp lint(改动文件)、verify-agent-notes、verify-test-stability、verify-platform-feature-matrix、verify-platform-feature-matrix-change origin/preview HEAD、verify-windows-boundaries、verify-shared-contracts、verify-rust-core-comments、verify-runtime-bundle-immutability 全部通过。

  • CI 修复(aeb54b8d):git-status-api.test.ts 新增的两个用例原先用 mockImplementationOnce 排队返回值,假设下一次 invoke 一定是 git_diff_file。CI 以随机顺序(seed 1/3/7)运行时,仓库发现缓存有时还没建立,git_discover_repo 先消费了排队的返回值,导致 seed=1 失败。改为按命令名返回响应;本地 17 个 seed 全部通过。

未覆盖

  • 没有在真实 Windows / WebView2 宿主上手动点击验证;按块暂存后的 Git 状态联动依赖已有的刷新逻辑,同样需要 Windows 宿主验收。
  • 超大文件的单文件 Diff 现在会携带整份文件。传输量与“打开该文件”同一量级,Core 现有 Diff 路径没有额外截断,这里没有新增上限。

🤖 Generated with Claude Code

Single-file working-tree diffs were rendered from a sparse Git patch with
Monaco folding disabled, so there was nothing to expand and the fold
controls disappeared.

- Request the whole file as context for single-file reviews and mark the
  result as full context; only those reviews enable folding.
- Split full-context patches back into Git-equivalent 3-line hunks so
  hunk staging keeps its granularity.
- Place hunk action bands by an explicit row anchor and per-side line
  count, keeping both sides aligned.
- Re-attach the diff models when the text is replaced so the first real
  text after the empty mount folds instead of opening fully revealed.

Co-Authored-By: Claude <noreply@anthropic.com>
@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Oct 1, 2026
1lck and others added 2 commits October 1, 2026 13:37
The new full-context API tests queued their response with
mockImplementationOnce, which assumed git_diff_file was the next invoke.
Under CI's randomized order, repository discovery is sometimes not yet
cached, so git_discover_repo consumed the queued response and the diff
returned null (seed=1). Answer git_diff_file by command instead.

Co-Authored-By: Claude <noreply@anthropic.com>
@1lck
1lck merged commit 7cb138b into preview Oct 1, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant