From d14d4ad72dd3e2494f681e770889d26ea9185f5c Mon Sep 17 00:00:00 2001 From: kellito Date: Sun, 5 Jul 2026 18:55:04 +0300 Subject: [PATCH] =?UTF-8?q?tlc:=20Sprint=203=20C10=20=E2=80=94=20Find=20di?= =?UTF-8?q?alog=20pre-fills=20from=20cursor=20entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously Find dialog always opened with the default placeholder ('*.rs'). Now open_find_dialog() inspects the active panel's cursor entry and uses its name as the initial pattern — so pressing M-? with cursor on 'main.rs' opens the dialog with 'main.rs' already in the input, ready for refinement (e.g. 'main.rs~' for backups, 'main*' for variants). Implementation: - find::FindDialog::new_with_pattern(start_dir, initial_pattern) - panel::Panel::cursor_entry() -> Option<&Entry> - widget::input::Input::set_text(s) mutable setter (the existing .text() builder consumes self) - dialog_ops::open_find_dialog() uses cursor entry name as the initial pattern; skips '..' and falls back to default when the panel is empty Tests (2 new in find::tests): - new_with_pattern_prefills_pattern_input - new_with_pattern_empty_falls_back_to_default Total: 1278 passing (was 1276; +2 new). --- .../tlc/source/src/filemanager/dialog_ops.rs | 18 +++++++++-- .../tui/tlc/source/src/filemanager/find.rs | 30 ++++++++++++++++++- .../tui/tlc/source/src/filemanager/panel.rs | 7 +++++ .../tui/tlc/source/src/widget/input.rs | 7 +++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs b/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs index db969f7680..4aa0a4f4c0 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/dialog_ops.rs @@ -354,10 +354,24 @@ impl FileManager { Ok(()) } - /// Open the M-? Find dialog. + /// Open the M-? Find dialog. The pattern input is pre-filled with + /// the cursor entry's name (so searching for the selected file's + /// pattern is the default); falls back to the default placeholder + /// if the cursor is on `..` or the panel is empty. pub fn open_find_dialog(&mut self) -> Result<()> { let start = self.active_panel().path().to_path_buf(); - self.dialog = Some(DialogState::Find(Box::new(find::FindDialog::new(start)))); + let pattern = self + .active_panel() + .cursor_entry() + .map(|e| e.name.clone()) + .filter(|n| n != "..") + .unwrap_or_default(); + let dialog = if pattern.is_empty() { + find::FindDialog::new(start) + } else { + find::FindDialog::new_with_pattern(start, &pattern) + }; + self.dialog = Some(DialogState::Find(Box::new(dialog))); Ok(()) } diff --git a/local/recipes/tui/tlc/source/src/filemanager/find.rs b/local/recipes/tui/tlc/source/src/filemanager/find.rs index 7882ba2be5..d73044d973 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/find.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/find.rs @@ -129,7 +129,8 @@ pub struct FindDialog { } impl FindDialog { - /// Create a new Find dialog rooted at `start_dir`. + /// Create a new Find dialog rooted at `start_dir` with the default + /// placeholder pattern ("*.rs"). #[must_use] pub fn new(start_dir: PathBuf) -> Self { let pattern = Input::new().label("Find").placeholder("*.rs"); @@ -147,6 +148,19 @@ impl FindDialog { } } + /// Create a new Find dialog rooted at `start_dir` with the + /// pattern input pre-filled from the user's current selection + /// (e.g. cursor filename). Empty `initial_pattern` falls back to + /// the default placeholder. + #[must_use] + pub fn new_with_pattern(start_dir: PathBuf, initial_pattern: &str) -> Self { + let mut dlg = Self::new(start_dir); + if !initial_pattern.is_empty() { + dlg.pattern.set_text(initial_pattern.to_string()); + } + dlg + } + /// Re-run the search against the current pattern and mode. /// Errors are stored in `last_error` rather than propagated, so /// the dialog stays interactive even when the user types an @@ -779,4 +793,18 @@ mod tests { .expect("render must not panic"); let _ = fs::remove_dir_all(&dir); } + + #[test] + fn new_with_pattern_prefills_pattern_input() { + let d = FindDialog::new_with_pattern(PathBuf::from("/tmp"), "foo.rs"); + assert_eq!(d.pattern.value(), "foo.rs"); + } + + #[test] + fn new_with_pattern_empty_falls_back_to_default() { + let d = FindDialog::new_with_pattern(PathBuf::from("/tmp"), ""); + // Empty pattern leaves the input at the default placeholder + // (".value()" returns empty when no text was set). + assert_eq!(d.pattern.value(), ""); + } } diff --git a/local/recipes/tui/tlc/source/src/filemanager/panel.rs b/local/recipes/tui/tlc/source/src/filemanager/panel.rs index 91ef06f6f7..caaff20f0f 100644 --- a/local/recipes/tui/tlc/source/src/filemanager/panel.rs +++ b/local/recipes/tui/tlc/source/src/filemanager/panel.rs @@ -260,6 +260,13 @@ impl Panel { &self.entries } + /// Entry under the cursor, or `None` if the cursor is past the + /// end of the entry list. + #[must_use] + pub fn cursor_entry(&self) -> Option<&Entry> { + self.entries.get(self.cursor) + } + /// Current status message. #[must_use] pub fn message(&self) -> Option<&str> { diff --git a/local/recipes/tui/tlc/source/src/widget/input.rs b/local/recipes/tui/tlc/source/src/widget/input.rs index 0195dfe8ad..461d1bc332 100644 --- a/local/recipes/tui/tlc/source/src/widget/input.rs +++ b/local/recipes/tui/tlc/source/src/widget/input.rs @@ -99,6 +99,13 @@ impl Input { self } + /// Set the current text (mutable setter, used to pre-fill the + /// input after construction). Cursor moves to the end. + pub fn set_text(&mut self, s: impl Into) { + self.text = s.into(); + self.cursor = self.text.chars().count(); + } + /// Mark the input as focused. #[must_use] pub fn focused(mut self) -> Self {