feat(diff-mode): implement interactive diff/compare#1
Conversation
mode for refs
Add a new diff/compare mode (W key) allowing users to
select two refs
(branches, tags, commits) and explore side-by-side file
diffs.
Features:
- Searchable combobox dropdowns for ref selection (A
and B)
- File list view with tree/flat toggle (backtick key)
- Side-by-side diff exploration with full navigation
controls
- Keyboard shortcuts: Tab (cycle), 1-4 (jump panel),
Ctrl+S (swap),
{/} (hunks), [/] (toggle view), g/G (top/bottom)
- Mouse support for clicking, scrolling, and text
selection in diff
Implementation:
- New git commands: diff_refs_files() and
diff_refs_file()
- Complete state management (DiffModeState) with
dropdown search
- Controller for key and mouse event handling
- Presentation layer with dedicated rendering
There was a problem hiding this comment.
π‘ Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2e957ea911
βΉοΈ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with π.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let mut parts = line.splitn(2, '\t'); | ||
| let status_str = parts.next().unwrap_or(""); | ||
| let name = parts.next().unwrap_or("").to_string(); | ||
| if name.is_empty() { |
There was a problem hiding this comment.
Parse rename/copy entries from
--name-status correctly
diff_refs_files splits each status line with splitn(2, '\t'), but git diff --name-status emits three fields for renames/copies (for example, R100\told.txt\tnew.txt). That makes name become old\tnew, which is not a valid path for diff_refs_file, so selecting renamed/copied files in compare mode yields an empty/error diff instead of the file content.
Useful? React with πΒ / π.
| let (ref_value, display) = if let Some(candidate) = self.search_results.get(self.search_selected) { | ||
| (candidate.ref_value.clone(), candidate.display.clone()) | ||
| } else if !query.is_empty() { |
There was a problem hiding this comment.
Allow raw ref input when dropdown has non-matching items
confirm_selection always prefers search_results[search_selected] over the typed query, but search_refs populates the dropdown with all refs (not filtered). In normal repos this means search_results is almost always non-empty, so typing a raw ref like HEAD~20 or a commit outside the 200 cached commits can select an unrelated candidate (often the first branch) instead of the user-entered ref.
Useful? React with πΒ / π.
| Some(selected) | ||
| }; | ||
|
|
||
| let Some(idx) = file_idx else { return }; |
There was a problem hiding this comment.
Clear diff panel when tree selection is a directory node
When tree view is enabled, selecting a directory produces file_index == None, and maybe_request_diff returns immediately without resetting diff_view. This leaves the previous file's diff visible while a directory is highlighted, which is inconsistent with other tree-based panels that clear diff content on non-file selections.
Useful? React with πΒ / π.
mode for refs
Add a new diff/compare mode (W key) allowing users to select two refs
(branches, tags, commits) and explore side-by-side file diffs.
Features:
{/} (hunks), [/] (toggle view), g/G (top/bottom)
Implementation: