Skip to content

feat: line-level stage hunk in quick diff viewer (SourceTree style)#18

Merged
zelon merged 2 commits into
mainfrom
claude/review-stage-hunk-Pb1dz
May 17, 2026
Merged

feat: line-level stage hunk in quick diff viewer (SourceTree style)#18
zelon merged 2 commits into
mainfrom
claude/review-stage-hunk-Pb1dz

Conversation

@zelon
Copy link
Copy Markdown
Owner

@zelon zelon commented May 17, 2026

$(cat <<'EOF'

Summary

  • Quick Diff 패널에서 pending 파일을 선택하면 각 변경 라인 우측에 [+] / [−] 버튼이 hover 시 표시됩니다.
  • 연속된 변경 라인(context 라인으로 구분되는 블록)은 하나의 단위로 처리되며, 블록 내 어느 라인의 버튼을 눌러도 해당 블록 전체가 한 번에 stage/unstage됩니다.
  • SourceTree의 "Stage selected lines" 방식과 동일한 UX입니다.

변경 파일

파일 내용
src/lib/diff-parser.ts (신규) unified diff → hunk/라인 구조 파싱, blockId 그룹핑, 미니 패치 재조립
src/components/shared/InteractiveDiffViewer.tsx (신규) 블록 hover 강조 + stage/unstage 버튼 포함 diff 뷰어
src/lib/git-api.ts gitApplyPatch() 추가
src/lib/index.ts diff-parser export 추가
src/components/layout/LeftSidebar.tsx untracked가 아닌 pending preview에 InteractiveDiffViewer 사용, localRefresh 추가
src-tauri/src/git/parsers/history.rs apply_patch Tauri command 추가 (임시파일 → git apply [--cached] [--reverse])
src-tauri/src/lib.rs apply_patch command 등록

동작 방식

[변경 라인 hover]
  → 같은 blockId를 가진 연속 라인 전체 배경 강조
  → 각 라인 우측에 [+] (unstaged) 또는 [−] (staged) 버튼 표시

[버튼 클릭]
  → buildBlockPatch()로 해당 블록 + 주변 context로 미니 패치 생성
  → git apply --cached [--reverse] <tempfile>
  → diff 패널 자동 새로고침 + PendingTab 파일 목록 갱신

Test plan

  • unstaged 파일 선택 → 변경 라인 hover 시 블록 강조 및 [+] 버튼 확인
  • [+] 클릭 후 해당 블록이 staged files로 이동되는지 확인
  • staged 파일 선택 → [−] 버튼으로 부분 unstage 확인
  • 여러 블록이 있는 파일에서 특정 블록만 stage 되는지 확인
  • 이미지/untracked 파일은 기존 DiffViewer 유지 확인
  • History 탭 커밋 diff는 기존 DiffViewer 유지 확인 (인터랙티브 버튼 없음)

https://claude.ai/code/session_014c1PNzrbhDMkL3uomdZGYc
EOF
)


Generated by Claude Code

claude added 2 commits May 17, 2026 06:41
When a pending file is selected in the Quick Diff panel, each changed
line now shows a [+] / [−] button on the right side on hover.
Consecutive changed lines without context between them form a block;
clicking the button on any line in the block stages (or unstages) the
entire contiguous block at once.

- diff-parser.ts: parse unified diff into hunks with per-line numbers
  and blockId grouping; buildBlockPatch() reconstructs a minimal valid
  patch for a single block
- InteractiveDiffViewer.tsx: new component rendering the diff with
  per-block hover highlight and stage/unstage buttons
- LeftSidebar.tsx: use InteractiveDiffViewer for non-untracked pending
  previews; add localRefresh to reload diff after patch apply
- git-api.ts: add gitApplyPatch() invoking new apply_patch command
- history.rs: add apply_patch Tauri command (writes to temp file,
  runs git apply [--cached] [--reverse])
- lib.rs: register apply_patch command

https://claude.ai/code/session_014c1PNzrbhDMkL3uomdZGYc
…ailure

diff.split("\n") produces a trailing "" when the diff ends with "\n".
This was parsed as a context line inside the hunk, making oldCount /
newCount one too large. git apply then looked for a non-existent line
and failed with "patch does not apply".

The same skip is already in place for "\ No newline at end of file"
lines, so we extend the condition to cover the empty string case.

https://claude.ai/code/session_014c1PNzrbhDMkL3uomdZGYc
@zelon zelon merged commit cd7be1f into main May 17, 2026
5 checks passed
@zelon zelon deleted the claude/review-stage-hunk-Pb1dz branch May 17, 2026 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants