feat: toggle diff file review with c in the file picker

This commit is contained in:
Valdemar Lorenzen
2026-10-13 13:17:06 +02:00
parent 38fcf86195
commit 8f87b8d3d1
3 changed files with 45 additions and 2 deletions
+1 -1
View File
@@ -249,7 +249,7 @@ The diff's changed-file explorer and floating picker use these same tree and sel
Ordinary `config.core.file_picker` and `config.core.file_explorer` bindings work inside comparisons. Ctrl+w closes a focused picker/explorer, retaining its query, selection, and expansion state; the panes use the reclaimed width. Ctrl+e has no reserved diff behavior. Escape closes the revision selector in either stage, but an opened comparison still closes explicitly through `:diff.close`, its palette action, or the generated action value below. `config.core.diff` remains the opening action and exposes immutable `close`, `mode.toggle`, `view.toggle`, and `orientation.toggle` children. New comparisons default to Branch changes (merge base → selected After); Normal-mode Ctrl+b, `:diff.mode.toggle`, or the palette toggles to direct Snapshots and back, preserving the selected endpoints. Selecting Working checkout on either side forces Snapshots.
`config.core.diff.review.toggle` is a non-mutating Normal-mode action, also available as `:diff.review.toggle` and in the palette. It marks/unmarks the highlighted changed-file leaf when the comparison's explorer is focused, or the current comparison file from a text pane. Read-only snapshots permit review marks. For example, `config.bind "ctrl+g", config.core.diff.review.toggle`; use the palette or a control-key binding while filtering so printable input stays in the query. No default review shortcut is installed.
`config.core.diff.review.toggle` is a non-mutating Normal-mode action, also available as `:diff.review.toggle` and in the palette. It marks/unmarks the highlighted changed-file leaf when the comparison's explorer is focused, or the current comparison file from a text pane. Read-only snapshots permit review marks. The default `c` shortcut applies only while browsing the diff's changed-file tree; explicit bindings and disabled keys override it. For example, `config.bind "ctrl+g", config.core.diff.review.toggle`; use the palette or a control-key binding while filtering, including List view, so printable input stays in the query.
`config.core.pane.close` and `config.core.pane.force_close` close a focused **docked** file list instead of its editor pane, without discarding buffers or exiting the comparison. A floating picker does not intercept these actions: normal close still protects underlying dirty buffers, while force-close retains its existing discard semantics. For example, bind `config.bind "ctrl+x", config.core.pane.close`; focused tree/selection overrides and printable filter input retain priority. Palette-originated close actions retain the originating dock target through force confirmation.
+1 -1
View File
@@ -370,7 +370,7 @@ Use the ordinary **file-picker/file-explorer actions and bindings**: Space `o` o
File rows show colored **A** (added, green), **M** (modified, yellow), **D** (removed, red), or **R** (renamed, cyan) markers in Tree and List views, including filtered results. Rename rows show `R old/path -> new/path`; directories have no file-status marker. Ordinary file exploration remains unannotated.
Mark or unmark a diff file with **`:diff.review.toggle`** or the command-palette action. With the changed-file explorer focused, it toggles the highlighted file without opening it; from a text pane, it toggles the displayed file. Reviewed files show a green **`✓` immediately before A/M/D/R** in Tree and List views. Directories and ordinary filesystem pickers cannot be marked. There is no default shortcut; a control-key binding is useful while a filter is focused, since printable keys remain filter text.
Mark or unmark a diff file with **`c` while browsing the changed-file tree**, **`:diff.review.toggle`**, or the command-palette action. With the changed-file explorer focused, it toggles the highlighted file without opening it; from a text pane, the command toggles the displayed file. Reviewed files show a green **`✓` immediately before A/M/D/R** in Tree and List views. Directories and ordinary filesystem pickers cannot be marked. While filtering, including List view, `c` remains query text; use the palette or a control-key binding there. Explicit bindings take precedence over the default browsing shortcut.
Review marks belong only to the open comparison and survive filtering, file navigation, lazy loading, tabs, and split/unified/orientation changes. A new or recomputed comparison clears them. Editing a Working After file clears only that file's mark; unchanged refreshes and saves preserve it. Marks do not change document text, undo history, or repository state, and are not persisted after closing the comparison.
+43
View File
@@ -3232,6 +3232,22 @@ impl Editor {
if !self.diff_interacting() && self.handle_selection_binding(&input) {
return None;
}
if files_focused
&& input == Input::Char('c')
&& self
.diff
.as_ref()
.and_then(|diff| diff.files.as_ref())
.is_some_and(|files| files.view == FileView::Tree && !files.searching)
&& input != self.leader
&& !self.has_sequence_prefix(self.binding_mode(), &input)
&& !self
.bindings
.get(&self.binding_mode())
.is_some_and(|keys| keys.contains_key(&input))
{
return self.execute_action(Action::DiffReviewToggle.entry(), "");
}
if self.sequence_pending().is_some()
|| (phase == Phase::View
&& (input == self.leader || self.has_sequence_prefix(self.binding_mode(), &input)))
@@ -13575,6 +13591,33 @@ mod tests {
assert!(editor.diff().unwrap().reviewed_files.is_empty());
}
#[test]
fn diff_review_c_toggles_only_while_browsing_and_respects_overrides() {
let directory = Directory::new();
let mut editor = editor();
historical_diff(
&mut editor,
&directory.0,
vec!["before".into()],
vec!["after".into()],
);
editor.handle(Input::BackTab);
assert_eq!(editor.diff().unwrap().focus, Focus::Files);
editor.handle(Input::Char('c'));
assert_eq!(editor.diff().unwrap().reviewed_files, BTreeSet::from([0]));
editor.handle(Input::Char('c'));
assert!(editor.diff().unwrap().reviewed_files.is_empty());
editor.handle(Input::Char('i'));
editor.handle(Input::Char('c'));
assert_eq!(editor.diff().unwrap().files.as_ref().unwrap().query, "c");
assert!(editor.diff().unwrap().reviewed_files.is_empty());
editor.handle(Input::Escape);
editor.handle(Input::Ctrl('u'));
editor.bind("normal", "c", None).unwrap();
editor.handle(Input::Char('c'));
assert!(editor.diff().unwrap().reviewed_files.is_empty());
}
#[test]
fn diff_review_files_action_targets_highlight_without_stealing_filter_text() {
let directory = Directory::new();