|
| 1 | +# Split Status Bar into Status Line + Help Overlay |
| 2 | + |
| 3 | +## Overview |
| 4 | +Replace the current single status bar (which mixes status info and shortcut hints) with two separate concerns: |
| 5 | +1. **Status line** — shows file info, diff stats, hunk position, mode indicators, annotation count |
| 6 | +2. **Help overlay** — a modal popup triggered by `?` showing all keybindings organized by section |
| 7 | + |
| 8 | +The current `statusBarText()` in `ui/model.go:488-551` is crowded and hard to scan. Splitting status from help makes both more useful: the status line becomes a clean info strip, and the help overlay provides comprehensive reference without cluttering the screen. |
| 9 | + |
| 10 | +## Context |
| 11 | +- **Primary file:** `ui/model.go` — `statusBarText()` (lines 488-551), `View()` (lines 442-486), `handleKey()` (lines 188-259) |
| 12 | +- **Styles:** `ui/styles.go` — `StatusBar` style, `Colors` struct |
| 13 | +- **Diff navigation:** `ui/diffview.go` — `currentHunk()`, `findHunks()` |
| 14 | +- **Collapsed mode:** `ui/collapsed.go` — `collapsedState` |
| 15 | +- **Model fields:** `ui/model.go` — `currFile`, `diffLines`, `store`, `collapsed`, etc. |
| 16 | + |
| 17 | +## Solution Overview |
| 18 | + |
| 19 | +### Status line layout (left to right) |
| 20 | +``` |
| 21 | +filename +N/-N hunk X/Y ▼ ◉ 3 annotations ? help |
| 22 | +``` |
| 23 | +- **filename** — current file path (truncated from left with `…` if too long) |
| 24 | +- **+N/-N** — additions/deletions count for the current file |
| 25 | +- **hunk X/Y** — current hunk position (only when cursor is on a changed line) |
| 26 | +- **▼** — collapsed mode indicator (only when active) |
| 27 | +- **◉** — filter active indicator (only when active) |
| 28 | +- **right-aligned:** annotation count + `? help` hint |
| 29 | + |
| 30 | +### Help overlay |
| 31 | +- Triggered by `?` key, dismissed by `?` or `esc` |
| 32 | +- Centered bordered box rendered on top of the main view |
| 33 | +- Sections: Navigation, Annotations, View, Quit |
| 34 | +- Uses lipgloss border styling consistent with existing pane borders |
| 35 | + |
| 36 | +## Technical Details |
| 37 | + |
| 38 | +### New fields in Model |
| 39 | +- `showHelp bool` — true when help overlay is visible |
| 40 | +- No new files needed — help rendering goes in a new `helpOverlay()` method in `model.go` |
| 41 | + |
| 42 | +### File stats computation |
| 43 | +- Count adds/removes from `m.diffLines` on file load (in `handleFileLoaded`) |
| 44 | +- Cache as `fileAdds int`, `fileRemoves int` fields on Model |
| 45 | +- Reset on file change |
| 46 | + |
| 47 | +### Status line segments |
| 48 | +Each segment is a small string. Segments are joined with double-space separators. Right-aligned section uses padding like current implementation. |
| 49 | + |
| 50 | +### Help overlay rendering |
| 51 | +- Build help text as a lipgloss-bordered box |
| 52 | +- When `m.showHelp` is true, `View()` replaces the main content area with the centered help popup (standard bubbletea modal pattern — no true compositing, the help box replaces tree+diff content) |
| 53 | +- Use `lipgloss.Place(m.width, paneHeight, lipgloss.Center, lipgloss.Center, helpBox)` + status bar below |
| 54 | +- Note: bubbletea reports `?` key correctly via `msg.String()` (shifted `/` key) |
| 55 | + |
| 56 | +### Narrow terminal handling |
| 57 | +- Truncate filename from left with `…` prefix when space is tight |
| 58 | +- Drop lower-priority segments (hunk, mode icons) if width is insufficient |
| 59 | + |
| 60 | +## Development Approach |
| 61 | +- **Testing approach:** regular (code first, then tests) |
| 62 | +- Complete each task fully before moving to the next |
| 63 | +- Run tests after each change |
| 64 | +- Maintain backward compatibility (existing CLI flags, config, styles all still work) |
| 65 | + |
| 66 | +## Implementation Steps |
| 67 | + |
| 68 | +### Task 1: Compute and cache file diff stats |
| 69 | + |
| 70 | +**Files:** |
| 71 | +- Modify: `ui/model.go` |
| 72 | +- Modify: `ui/model_test.go` |
| 73 | + |
| 74 | +- [x] add `fileAdds` and `fileRemoves` int fields to `Model` struct |
| 75 | +- [x] add `computeFileStats()` method that counts add/remove lines from `m.diffLines` |
| 76 | +- [x] call `computeFileStats()` in `handleFileLoaded` after setting `m.diffLines` |
| 77 | +- [x] write tests for `computeFileStats()` with various diff line combinations |
| 78 | +- [x] run `make test` — must pass before task 2 |
| 79 | + |
| 80 | +### Task 2: Rewrite status line and update tests |
| 81 | + |
| 82 | +**Files:** |
| 83 | +- Modify: `ui/model.go` |
| 84 | +- Modify: `ui/model_test.go` |
| 85 | + |
| 86 | +- [x] rewrite `statusBarText()` to show: filename, +N/-N stats, hunk X/Y, mode icons (▼ ◉), right-aligned annotation count + `? help` |
| 87 | +- [x] keep special cases for `inConfirmDiscard` and `annotating` modes unchanged |
| 88 | +- [x] implement filename truncation with `…` prefix for narrow terminals |
| 89 | +- [x] drop hunk and mode icons gracefully when terminal is too narrow |
| 90 | +- [x] update existing `statusBarText` tests to match new format (no shortcut hints, has filename/stats) |
| 91 | +- [x] add test cases for: filename truncation, mode indicators present/absent, stats display |
| 92 | +- [x] add test cases for narrow terminal width graceful degradation |
| 93 | +- [x] run `make test` — must pass before task 3 |
| 94 | + |
| 95 | +### Task 3: Add help overlay rendering |
| 96 | + |
| 97 | +**Files:** |
| 98 | +- Modify: `ui/model.go` |
| 99 | + |
| 100 | +- [x] add `showHelp bool` field to Model |
| 101 | +- [x] add `helpOverlay()` method returning the bordered help text with sections (Navigation, Annotations, View, Quit) |
| 102 | +- [x] modify `View()` to overlay help popup using `lipgloss.Place()` when `m.showHelp` is true |
| 103 | +- [x] write tests for `helpOverlay()` verifying section headers and key listings are present |
| 104 | +- [x] run `make test` — must pass before task 4 |
| 105 | + |
| 106 | +### Task 4: Wire up `?` key handling |
| 107 | + |
| 108 | +**Files:** |
| 109 | +- Modify: `ui/model.go` |
| 110 | +- Modify: `ui/model_test.go` |
| 111 | + |
| 112 | +- [x] handle `?` key in `handleKey()` to toggle `m.showHelp` |
| 113 | +- [x] handle `esc` key to close help when `m.showHelp` is true |
| 114 | +- [x] block all other key handling when help overlay is showing (except `?` and `esc`) |
| 115 | +- [x] write tests for help toggle behavior (open, close with ?, close with esc) |
| 116 | +- [x] write test that other keys are blocked when help is showing |
| 117 | +- [x] run `make test` — must pass before task 5 |
| 118 | + |
| 119 | +### Task 5: Verify acceptance criteria |
| 120 | +- [x] verify status line shows filename, stats, hunk, mode icons, annotations, help hint |
| 121 | +- [x] verify help overlay opens with `?` and closes with `?` or `esc` |
| 122 | +- [x] verify no shortcut hints in status bar anymore (all moved to help overlay) |
| 123 | +- [x] verify special modes (annotation input, discard confirm) still work in status bar |
| 124 | +- [x] run full test suite: `make test` |
| 125 | +- [x] run linter: `make lint` |
| 126 | + |
| 127 | +### Task 6: [Final] Update documentation |
| 128 | +- [x] update README.md with new `?` help shortcut and status line description |
| 129 | +- [x] update `.claude-plugin/skills/revdiff/references/usage.md` with `?` help keybinding |
| 130 | +- [x] update CLAUDE.md if any new patterns discovered |
| 131 | +- [x] move this plan to `docs/plans/completed/` |
| 132 | + |
| 133 | +## Post-Completion |
| 134 | + |
| 135 | +**Manual verification:** |
| 136 | +- test with narrow terminal widths (< 80 cols) to verify truncation |
| 137 | +- test with large diffs (many hunks) to verify hunk counter |
| 138 | +- test collapsed mode + filter active to verify both icons show |
| 139 | +- verify help overlay looks correct with different color themes |
0 commit comments