Skip to content

Commit b6cce96

Browse files
add status line stats for files/additions/deletions pre-commit (#35)
1 parent eba32c6 commit b6cce96

3 files changed

Lines changed: 242 additions & 10 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# ripdiff Feature Suggestions
2+
3+
## Priority Ranking
4+
5+
| Priority | Feature | Effort | Impact |
6+
|----------|---------|--------|--------|
7+
| 🔥 | Prefetch adjacent diffs (#13) | Low | High |
8+
| 🔥 | File search/filter (#1) | Medium | High |
9+
| 🔥 | Copy path to clipboard (#7) | Low | Medium |
10+
| 🔥 | Mouse support (#12) | Low | Medium |
11+
|| Diff statistics summary (#2) | Low | Medium |
12+
|| File discard (#4) | Medium | High |
13+
|| Watch pause toggle (#8) | Low | Medium |
14+
|| Commit log viewer (#15) | Medium | High |
15+
| 💎 | Hunk-level staging (#3) | High | Very High |
16+
| 💎 | Commit range diffs (#10) | High | High |
17+
| 💎 | Config file (#9) | Medium | Medium |
18+
19+
---
20+
21+
## 1. File Search / Fuzzy Filter (`/` key)
22+
23+
When you have many changed files, there's no way to quickly find one. Adding a `/` keybinding to open a filter input (like vim's `/` or fzf) that narrows the file list as you type would be very useful, especially in large agent-driven changesets.
24+
25+
**Files to modify:** `app.rs` (new `FilterDialog` state, key handling), `ui.rs` (render filter input overlay, filtered file list)
26+
27+
## 2. Diff Statistics Summary Bar
28+
29+
Show a summary like `12 files changed, +340 -87` in the status bar (bottom). The data is already available in `RepoSnapshot` — just needs aggregation and rendering. Gives instant context on change magnitude.
30+
31+
**Files to modify:** `ui.rs` (`render_statusline` — aggregate `FileStat.additions`/`deletions` across all files)
32+
33+
## 3. Hunk-level Staging (partial staging)
34+
35+
Currently staging is file-level only (`git add`). Supporting `git add -p` style hunk-level staging would be a killer feature — select a hunk in the diff panel and stage just that hunk. This is the main gap vs. tools like lazygit/magit.
36+
37+
**Files to modify:** `git.rs` (new `stage_hunk` function using `git apply --cached`), `app.rs` (hunk selection state, key handling for staging hunks), `diff.rs` (extract hunk boundaries from diff output), `ui.rs` (hunk highlight/selection rendering)
38+
39+
**Approach:** Generate a patch for the selected hunk and pipe it to `git apply --cached`. Need to track hunk boundaries in `DiffContent` alongside the rendered lines.
40+
41+
## 4. File Discard / Checkout (`d` key)
42+
43+
Add the ability to discard changes for a file (`git checkout -- <file>` / `git restore <file>`) with a confirmation prompt. Currently you can stage/unstage but can't revert unwanted changes without leaving the TUI.
44+
45+
**Files to modify:** `git.rs` (new `discard_file` function), `app.rs` (new `ConfirmDialog` state, `d` key handling), `ui.rs` (render confirmation dialog)
46+
47+
## 5. Stash Support (`z` key prefix)
48+
49+
Add `zz` to stash, `zp` to pop, `zl` to list stashes. Stashing is a common workflow when reviewing agent changes — you might want to stash some changes before testing.
50+
51+
**Files to modify:** `git.rs` (new `stash`, `stash_pop`, `stash_list` functions), `app.rs` (pending `z` key sequence, stash dialog state), `ui.rs` (stash list overlay)
52+
53+
## 6. Diff Word-wrap / Horizontal Scroll
54+
55+
Long lines get truncated in the diff panel. Adding horizontal scroll (`H`/`L` or arrow keys when in diff) or optional word-wrap toggle would help with minified files or long lines.
56+
57+
**Files to modify:** `app.rs` (new `horizontal_offset` in `UiState`, key handling for horizontal scroll), `ui.rs` (`render_diff_panel` — apply horizontal offset to visible lines)
58+
59+
## 7. Copy File Path to Clipboard (`y` key)
60+
61+
Press `y` to yank the selected file path to the system clipboard. Useful in the tmux panel workflow described in the README — quickly grab a path to use in the other pane.
62+
63+
**Files to modify:** `app.rs` (`y` key handler), new clipboard utility (use `xclip`/`pbcopy`/`wl-copy` via `Command`, or add `arboard` crate dependency)
64+
65+
## 8. Watch Mode Indicator & Manual Pause
66+
67+
Show a visual indicator that file-watching is active (e.g., a small `👁` icon in the title bar). Add a keybinding to pause/resume auto-refresh — useful when an agent is rapidly writing files and you want to freeze the view to read a diff.
68+
69+
**Files to modify:** `app.rs` (new `paused` bool in `App`, modify `refresh` to respect it, key handler for toggle), `ui.rs` (`render_title` — show pause/watch indicator)
70+
71+
## 9. Configurable Color Theme / `.ripdiffrc`
72+
73+
Colors are hardcoded (e.g., `Color::Rgb(22, 48, 30)` for addition backgrounds). A config file (TOML) supporting custom themes would let users match their terminal theme. Could also persist preferences like default diff mode and sidebar visibility.
74+
75+
**Files to modify:** New `config.rs` module (parse TOML config from `~/.config/ripdiff/config.toml`), `ui.rs` (replace hardcoded colors with config lookups), `main.rs` (load config on startup), `Cargo.toml` (add `toml` crate)
76+
77+
## 10. Diff for Specific Commits / Ranges
78+
79+
Currently only shows uncommitted changes. Adding `ripdiff HEAD~3..HEAD` or `ripdiff <commit>` to review committed diffs would make it useful beyond just watching agent progress — general-purpose commit review.
80+
81+
**Files to modify:** `main.rs` (new CLI arg for commit range), `git.rs` (new `load_snapshot_for_range` using `git diff <range> --numstat`), `diff.rs` (new `fetch_diff_for_range` using revision pairs), `app.rs` (store range context)
82+
83+
## 11. Binary File Detection & Preview
84+
85+
Binary files (images, compiled assets) currently show `[binary file]` or error. Could show file size, type info, and for images, a sixel/kitty protocol inline preview on supported terminals.
86+
87+
**Files to modify:** `diff.rs` (`show_new_file` — detect binary via `tree_magic_mini` already in deps, show metadata), `ui.rs` (optional image protocol rendering)
88+
89+
## 12. Mouse Support
90+
91+
Ratatui supports mouse events via crossterm. Click to select files, scroll with mouse wheel in the diff panel. Low effort, high QoL for users who aren't vim-native.
92+
93+
**Files to modify:** `main.rs` (enable mouse capture in crossterm setup), `event.rs` (handle `CrosstermEvent::Mouse` variants), `app.rs` (new `handle_mouse` method — map click coordinates to file selection or diff scroll)
94+
95+
## 13. Prefetch Adjacent Diffs
96+
97+
Currently only the selected file's diff is computed. Prefetching diffs for files ±1 from the selection would make navigation feel instant. The `DiffService` async architecture already supports this — just call `ensure_diff` for neighbors.
98+
99+
**Files to modify:** `app.rs` (new `ensure_adjacent_diffs` method called alongside `ensure_selected_diff`, request diffs for `selected ± 1`)
100+
101+
## 14. Branch Switching / Checkout
102+
103+
A branch picker dialog (like the commit dialog) to switch branches. Useful when reviewing agent work across multiple branches.
104+
105+
**Files to modify:** `git.rs` (new `list_branches`, `checkout_branch` functions), `app.rs` (new `BranchDialog` state, key handling), `ui.rs` (branch picker overlay with scrollable list)
106+
107+
## 15. Commit Log Viewer
108+
109+
A `l` keybinding to show recent commit history (like `git log --oneline`). Helps understand context when reviewing agent progress — "what did the agent already commit?"
110+
111+
**Files to modify:** `git.rs` (new `recent_commits` function), `app.rs` (new `LogDialog` state, `l` key handler), `ui.rs` (log overlay with scrollable list)

src/ui.rs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,19 +166,53 @@ fn render_commit_dialog(frame: &mut Frame, app: &App, area: Rect) {
166166
}
167167

168168
fn render_statusline(frame: &mut Frame, app: &App, area: Rect) {
169-
let (content, style) = match app.snapshot.unpushed_commits {
170-
Some(n) if n > 0 => {
169+
let file_count = app.snapshot.files.len();
170+
let total_additions: u32 = app.snapshot.files.iter().map(|f| f.additions).sum();
171+
let total_deletions: u32 = app.snapshot.files.iter().map(|f| f.deletions).sum();
172+
173+
let stats_text = if file_count > 0 {
174+
let file_label = if file_count == 1 { "file" } else { "files" };
175+
let mut parts = vec![format!("{file_count} {file_label} changed")];
176+
if total_additions > 0 {
177+
parts.push(format!("+{total_additions}"));
178+
}
179+
if total_deletions > 0 {
180+
parts.push(format!("-{total_deletions}"));
181+
}
182+
parts.join(", ")
183+
} else {
184+
String::new()
185+
};
186+
187+
let bg = Color::Rgb(30, 30, 30);
188+
189+
let mut spans: Vec<Span> = Vec::new();
190+
191+
if let Some(n) = app.snapshot.unpushed_commits {
192+
if n > 0 {
171193
let label = if n == 1 { "commit" } else { "commits" };
172-
(
194+
spans.push(Span::styled(
173195
format!(" \u{2191}{n} {label} to push \u{2502} p:push"),
174-
Style::default()
175-
.fg(Color::Yellow)
176-
.bg(Color::Rgb(30, 30, 30)),
177-
)
196+
Style::default().fg(Color::Yellow),
197+
));
178198
}
179-
_ => (String::new(), Style::default().bg(Color::Rgb(20, 20, 20))),
180-
};
181-
frame.render_widget(Paragraph::new(content).style(style), area);
199+
}
200+
201+
if !stats_text.is_empty() {
202+
if !spans.is_empty() {
203+
spans.push(Span::styled(
204+
" \u{2502} ",
205+
Style::default().fg(Color::DarkGray),
206+
));
207+
} else {
208+
spans.push(Span::raw(" "));
209+
}
210+
spans.push(Span::styled(stats_text, Style::default().fg(Color::Yellow)));
211+
}
212+
213+
let line = Line::from(spans);
214+
let style = Style::default().bg(bg);
215+
frame.render_widget(Paragraph::new(line).style(style), area);
182216
}
183217

184218
fn render_push_dialog(frame: &mut Frame, app: &App, area: Rect) {

src/vendored_parsers/tree-sitter-hare/Cargo.lock

Lines changed: 87 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)