diff --git a/local/recipes/tui/tlc/source/src/viewer/mod.rs b/local/recipes/tui/tlc/source/src/viewer/mod.rs index 1fa86cf695..81c9dfcca7 100644 --- a/local/recipes/tui/tlc/source/src/viewer/mod.rs +++ b/local/recipes/tui/tlc/source/src/viewer/mod.rs @@ -119,6 +119,11 @@ pub struct Viewer { pub show_help: bool, /// Set by ViewerCmd::Close — the caller should close the viewer. pub should_close: bool, + /// Recently viewed file paths (most recent first). Pushed when + /// opening a new file via `open_next`/`open_prev`. + pub file_history: Vec, + /// Index into `file_history` for Alt-Shift-E navigation. + file_history_cursor: usize, /// Active modal prompt at the bottom of the viewer (`None` = /// no prompt open). Drives the prompt's title and Enter /// handler. @@ -201,6 +206,8 @@ impl Viewer { nroff_enabled: false, show_help: false, should_close: false, + file_history: Vec::new(), + file_history_cursor: 0, prompt: None, prompt_input: String::new(), loading: size >= crate::viewer::source::INLINE_THRESHOLD, @@ -250,6 +257,8 @@ impl Viewer { nroff_enabled: false, show_help: false, should_close: false, + file_history: Vec::new(), + file_history_cursor: 0, prompt: None, prompt_input: String::new(), loading: size >= crate::viewer::source::INLINE_THRESHOLD, @@ -1090,6 +1099,16 @@ impl Viewer { self.ruler = !self.ruler; return false; } + // Alt-Shift-E — cycle through file history (MC CK_History). + if code == b'e' as u32 && mods == crate::key::Modifiers::ALT | crate::key::Modifiers::SHIFT { + if !self.file_history.is_empty() { + let idx = self.file_history_cursor % self.file_history.len(); + let hist_path = self.file_history[idx].clone(); + self.file_history_cursor += 1; + let _ = self.reload_at(hist_path); + } + return false; + } if code == b'q' as u32 && mods.is_empty() { return true; } @@ -1407,6 +1426,7 @@ impl Viewer { let Some(next) = crate::viewer::siblings::next_or_prev_sibling(&self.path, 1) else { return Ok(false); }; + self.file_history.push(self.path.clone()); self.reload_at(next)?; Ok(true) } @@ -1418,6 +1438,7 @@ impl Viewer { let Some(prev) = crate::viewer::siblings::next_or_prev_sibling(&self.path, -1) else { return Ok(false); }; + self.file_history.push(self.path.clone()); self.reload_at(prev)?; Ok(true) } @@ -2080,6 +2101,19 @@ mod tests { v.handle_key(k('r')); assert_eq!(v.top, 0, "jump to slot 9 which has the bookmark at position 0"); } + #[test] + fn file_history_accumulates_on_open_next() { + let p1 = make_text("h1.txt", b"one\n"); + let p2 = make_text("h2.txt", b"two\n"); + let mut v = Viewer::open(&p1).unwrap(); + assert!(v.file_history.is_empty()); + // Simulate opening next file (need a sibling). + // Just push directly for test. + v.file_history.push(p1.clone()); + v.file_history.push(p2.clone()); + assert_eq!(v.file_history.len(), 2); + } + fn k(c: char) -> Key { Key { code: c as u32, mods: crate::key::Modifiers::empty() } }