Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
270e65c
test: merge per-file integration tests into one harness per crate
lettertwo Jul 13, 2026
20f185e
feat(review): diff gap fold-all keys and n/p hunk navigation
lettertwo Jul 15, 2026
9e4a503
feat(review): warn at startup when a bare key shadows under a chord p…
lettertwo Jul 16, 2026
7e69122
refactor(review): share the strict-prefix test with key dispatch
lettertwo Jul 16, 2026
6008d4d
fix(review): refusal notice shows the resolved cycle-zoom key
lettertwo Jul 16, 2026
176bdaa
refactor(review): reuse primary_key for the zoom refusal label
lettertwo Jul 16, 2026
5aae0c6
feat(review): base16 slot and tint override keys under workon.review.…
lettertwo Jul 15, 2026
ee6cf18
feat(review): render monochrome when NO_COLOR is set
lettertwo Jul 15, 2026
4d34623
fix(review): collapse nerd icon colors to foreground under NO_COLOR
lettertwo Jul 15, 2026
894123c
feat(review): per-pane headers replace the global winbar row
lettertwo Jul 16, 2026
9ac9636
refactor(review): single-source the pane-header diffstat spans
lettertwo Jul 16, 2026
ac1be6d
feat(review): light the focused pane's header label
lettertwo Jul 16, 2026
d0bd9c6
feat(review): dim the cursorline wash in unfocused panes
lettertwo Jul 16, 2026
4411264
feat(review): dim header counters with their pane's focus
lettertwo Jul 17, 2026
70ba1b0
feat(review): run split caption rules full width as pane divider
lettertwo Jul 17, 2026
bcc4bfa
fix(review): dedupe caption_row helper across split-caption tests
lettertwo Jul 23, 2026
73f347a
fix(review): render one-sided patch headers git apply accepts
lettertwo Jul 17, 2026
b76bc82
feat(review): line stage and discard on untracked and added files
lettertwo Jul 17, 2026
3030249
fix(review): extract shared git_apply_cached test helper
lettertwo Jul 23, 2026
1e4c90b
test(review): pin canvas paint under split-view content rows
lettertwo Jul 20, 2026
9309158
fix(review): key silent-probe cache to the concrete tty device
lettertwo Jul 20, 2026
c5fa833
feat(review): derive auto diff washes from probed terminal accents
lettertwo Jul 20, 2026
5fb5680
feat(review): render comment captures in italics
lettertwo Jul 20, 2026
dfcd5d7
feat(review): screen the filler hatch back to its own base01 fg
lettertwo Jul 20, 2026
7819409
refactor(review): unify startup config resolution into resolve_runtime
lettertwo Jul 22, 2026
82fcc82
feat(review): add reload-config command for live theme/keymap reload
lettertwo Jul 22, 2026
8abac2f
fix(review): re-plumb the zoom key hint on config reload
lettertwo Jul 22, 2026
23603bb
fix(review): share seat-time zoom hint and warning plumbing with reload
lettertwo Jul 23, 2026
3c0c245
fix(review): fold the theme fallback ladder into one shared path
lettertwo Jul 23, 2026
dca814c
docs(review): record the diff line/edit fg-bg split decision
lettertwo Jul 22, 2026
c74dbfb
feat(review): split diff wash fg from bg, rename line/edit
lettertwo Jul 22, 2026
083ffae
style(review): bind dark() staged-fg washes and fix a test init
lettertwo Jul 22, 2026
64de057
feat(review): add workon.review.diff.text foreground modes
lettertwo Jul 22, 2026
fc38c0c
refactor(review): resolve syntax fg and italic from one lookup
lettertwo Jul 22, 2026
7d54b11
fix(review): share the staged-ness attribution cascade
lettertwo Jul 23, 2026
0a7be4e
fix(review): bundle diff text-mode params into one struct
lettertwo Jul 23, 2026
25558bc
docs(review): record the config validation completeness decision
lettertwo Jul 23, 2026
5d3ddc7
feat(review): warn on unknown workon.review.* config keys
lettertwo Jul 23, 2026
810bb60
test(review): import width bounds into the app test module
lettertwo Jul 23, 2026
b5f5dbc
feat(review): name the expected format in invalid color warnings
lettertwo Jul 23, 2026
d7fbd33
fix(review): use fixture layers in the dedup warning test
lettertwo Jul 23, 2026
299b47e
fix(review): share the parse-warn-default shape across view settings
lettertwo Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ Terms used throughout the `git-workon` codebase. Implementation details do not b

**Uncommitted layer** — the synthetic changeset spanning the dirty working tree + index. Appears in a review only when the review is focused where `HEAD` actually is, since uncommitted changes diff against `HEAD`.

## Review Theming

**Wash** — a background color painted behind diff text to signal that the text changed. Washes carry the diff signal; foreground carries syntax meaning unless a theme says otherwise. _Avoid_: "tint" for the background specifically (see below), "highlight".

**Line wash** — the wash covering an entire line that contains a change. Answers "something here changed". _Avoid_: "subtle" (renamed — it named intensity, not scope).

**Edit** — the exact text that changed. On a line paired with a counterpart, the word-diff ranges within it; on a line with no counterpart, the whole line. _Avoid_: "word" (true only for the paired case), "change" (reserved for a file's change kind).

**Edit wash** — the wash covering an edit. Answers "this precisely is the change". _Avoid_: "strong" (renamed — its intensity-flavored name is what let it drift into a foreground role).

**Tint foreground** — a text color that encodes added-ness or deleted-ness rather than syntax meaning. Distinct from a wash: same fact, opposite channel. _Avoid_: "diff color" (ambiguous between the two channels).

**Slot** — one of the sixteen base16 palette positions (`base00`–`base0f`) a theme assigns colors to. A slot has a *role* only when some part of the TUI reads it; the key space accepts all sixteen regardless.

## Prune Candidate Reasons

**BranchDeleted** — the local branch ref for the worktree no longer exists in the repository. Always a prune candidate regardless of flags.
Expand Down
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ build:
test:
cargo test --workspace

# PTY smoke tests (ignored by default: wall-clock-bound and load-sensitive).
# Spawns the review binary under a pseudo-terminal and plays the terminal's
# side of the theme=auto probe conversation; see tests/pty_smoke.rs.
# PTY tests (ignored by default: wall-clock-bound and load-sensitive). Spawns the review
# binary under a pseudo-terminal; covers the theme=auto probe conversation (see
# tests/pty/pty_smoke.rs) and launch/nav/streamed-startup responsiveness bounds (see
# tests/pty/pty_responsiveness.rs) — merged into one `pty` test binary, see tests/pty/main.rs.
smoke:
cargo test -p git-workon-review --test pty_smoke -- --ignored
cargo test -p git-workon-review --test pty -- --ignored

fmt:
cargo fmt
Expand Down
57 changes: 57 additions & 0 deletions docs/adr/034-review-git-native-config-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ is stored **action-as-key** in **per-view subsections**:

```
workon.review.theme = dark ; global, non-view
workon.review.theme.<slot> = #rrggbb ; base00-base0f override (CS1)
workon.review.theme.<tint> = #rrggbb ; diff/cursor tint override (CS1)
workon.review.<view>.bind.<action> = "<key tokens>" ; a keymap entry
workon.review.<view>.<setting> = <value> ; view config
```
Expand All @@ -58,6 +60,12 @@ workon.review.<view>.<setting> = <value> ; view config
- **View config** (non-binding) shares the view namespace: `workon.review.outline.width`,
`workon.review.outline.mode`, `workon.review.diff.layout`, `workon.review.diff.zoom`.
The `.bind.` marker is what distinguishes a keymap entry from a view setting.
- **Theme overrides** (CS1, user-configurable colors tier — see
[ADR-035](035-review-theming-base16-hybrid.md)'s CS1 revision) live in the `review.theme`
subsection, distinct from the top-level `workon.review.theme` selection itself: `workon.review
.theme.base00`–`workon.review.theme.base0f` (base16 slot overrides) and eleven kebab-case tint
keys (`workon.review.theme.cursor-bg`, …). Same validation posture as an unknown bind
action — an unrecognized key or malformed `#rrggbb` value is a startup warning, not an error.
- **Load-time inversion:** on startup, walk every `workon.review.*.bind.*` variable, split
values into key tokens, and build the per-view key→action dispatch maps. This pass
validates (unknown `bind.<action>` → warning; the action set is enumerable) and detects
Expand All @@ -67,6 +75,16 @@ workon.review.<view>.<setting> = <value> ; view config
cascade (confirm > outline-unfocus > selection-cancel > quit) stay hardcoded — they are
conventional, safety-sensitive, and the Esc cascade's documented precedence would break
if rebound.
- **`reload-config` (`R`, global view, rebindable like any other action):** re-reads the
whole `workon.review.*` tree and swaps it in without restarting — this ADR's schema was
originally "read once at startup"; live reload makes it "read once, re-readable on
demand" instead, with no schema change (the same getters just run again). One exception:
`theme = auto`'s terminal-derivation probe (ADR-035) never re-runs mid-session — it needs
the tty, which the TUI owns once the alternate screen is live, and a second probe
conversation there would corrupt input. Reload caches the startup probe result and reuses
it whenever the resolved theme is `auto`, so switching `theme` to `dark`/`light` takes
effect on reload, but switching back to `auto` reuses the cached base rather than
re-probing.

## Consequences

Expand All @@ -88,6 +106,45 @@ workon.review.<view>.<setting> = <value> ; view config
- Adding a rebindable action = adding it to the enumerable action set (code default +
dispatch + help entry); it is automatically configurable, validated, and documented.

## Revised (config validation completeness)

The validation posture above ("an unrecognized key … is a startup warning, not an error") turned
out to hold in only two of the four places it reads as a promise. `workon.review.theme.*` warns on
an unrecognized key, and the bind pass warns on an unknown action — but every *other* key under
`workon.review.*` is read by an explicit getter, so a name no getter asks for is never seen by
anything. A typo'd `workon.review.diff.laoyut` or `workon.review.outline.wdith` is silently
dropped: no warning, no effect, and nothing to distinguish it from a setting that simply had no
visible result. This bit in practice, twice in one session, on two different subsections.

**Unknown-key detection now covers the whole `workon.review.*` tree**, via a single validation pass
over `entries("workon.review.*")` driven by a central known-key registry: exact scalar names, plus
pattern arms for the two open-ended subspaces (`theme.<slot|tint>`, `<view>.bind.<action>`). Any
name no arm claims warns and is ignored, same non-fatal posture as everything else here.

Scope stops at `workon.review.*` deliberately. That subsection is this crate's exclusively;
`workon.*` at large belongs to `git-workon-lib`, and scanning wider would warn about
`workon.autocopy` and every other key this crate has no business knowing.

**The registry is a second source of truth, and that is the real cost.** A getter added without a
matching registry entry would make its key warn as unknown *while working correctly* — worse than
the silent-drop it replaces. The mitigation is a drift test that enumerates the getters' keys and
asserts each is claimed by the registry, so the failure lands in CI rather than in a user's footer.
The alternative — threading consumed-key tracking through every getter so the getters *are* the
registry — removes the drift class outright but reworks every reader's signature or call site; the
registry-plus-test was judged the better trade at this schema's size, and the choice is revisitable
if the schema grows a third open-ended subspace.

**Invalid-value warnings now carry the allowed set and the fallback being applied.** The existing
messages named the offending value but neither what was legal nor what the reader did instead —
`"workon.review.diff.text = 'edt' unrecognized; using default"` leaves a user to go read source or
docs for both halves. They now read `(valid: syntax, tint, edit); using default 'syntax'`, and the
range-checked and color-format cases get the same treatment. Theme keys keep saying `ignoring`
rather than naming a default, because an ignored override genuinely has no default to apply — the
underlying scheme's value stands.

**Unknown keys suggest a nearest match** by edit distance against the registry when one is close
enough, since the overwhelmingly common cause of an unknown key is a typo of a real one.

## References

- [ADR-006](006-git-native-config.md) — git-native config under `workon.*` this extends
Expand Down
Loading