tlc: FM→editor/viewer handoff with line numbers

FindOutcome::View/Edit now carry Option<u64> line number from FindHit. FileManager gains open_editor_at_line() and open_viewer_at_line() that jump to the target line after opening.
This commit is contained in:
2026-06-20 10:26:28 +03:00
parent ca7f22ae34
commit 4e4863e122
2 changed files with 38 additions and 10 deletions
@@ -9,6 +9,7 @@
//! themselves via a `confirmed`/`cancelled` flag.
use anyhow::Result;
use std::path::Path;
use crate::filemanager::{
config_dialog, edit_history, external_panelize, filtered_view, find, help, hotlist,
@@ -257,6 +258,26 @@ impl FileManager {
Ok(())
}
/// Open the F4 editor at a specific 1-based line number.
pub fn open_editor_at_line(&mut self, path: &Path, line: u32) {
let mut ed = crate::editor::Editor::open(path);
ed.goto_line(line);
self.editor = Some(ed);
self.status.set_message(format!("Editing {}:{}", path.display(), line));
}
/// Open the F3 viewer at a specific 1-based line number.
pub fn open_viewer_at_line(&mut self, path: &Path, line: u64) {
match crate::viewer::Viewer::open(path) {
Ok(mut v) => {
let _ = v.goto_line(line);
self.viewer = Some(v);
self.status.set_message(format!("Viewing {}:{}", path.display(), line));
}
Err(e) => self.status.set_message(format!("view: {e}")),
}
}
/// Open the F3 viewer for the cursor entry.
pub fn open_viewer_for_cursor(&mut self) -> Result<()> {
let p = self.active_panel().cursor_path();
@@ -549,16 +570,23 @@ impl FileManager {
FindOutcome::Open(path) => {
self.open_file_via_path(&path);
}
FindOutcome::View(path) => match crate::viewer::Viewer::open(&path) {
Ok(v) => {
FindOutcome::View(path, line) => match crate::viewer::Viewer::open(&path) {
Ok(mut v) => {
if let Some(ln) = line {
v.jump_to_line(ln);
}
self.viewer = Some(v);
self.status
.set_message(format!("Viewing {}", path.display()));
}
Err(e) => self.status.set_message(format!("view: {e}")),
},
FindOutcome::Edit(path) => {
self.editor = Some(crate::editor::Editor::open(&path));
FindOutcome::Edit(path, line) => {
let mut ed = crate::editor::Editor::open(&path);
if let Some(ln) = line {
ed.goto_line(ln as u32);
}
self.editor = Some(ed);
self.status
.set_message(format!("Editing {}", path.display()));
}
@@ -93,9 +93,9 @@ pub enum FindOutcome {
/// directory in the active panel.
Open(PathBuf),
/// User pressed F3 on a hit — open the file in the viewer.
View(PathBuf),
View(PathBuf, Option<u64>),
/// User pressed F4 on a hit — open the file in the editor.
Edit(PathBuf),
Edit(PathBuf, Option<u64>),
/// User pressed Esc — close the dialog and do nothing.
Cancel,
}
@@ -231,13 +231,13 @@ impl FindDialog {
return self
.results
.get(self.cursor)
.map_or(FindOutcome::Running, |h| FindOutcome::View(h.path.clone()));
.map_or(FindOutcome::Running, |h| FindOutcome::View(h.path.clone(), h.line));
}
if key == Key::f(4) {
return self
.results
.get(self.cursor)
.map_or(FindOutcome::Running, |h| FindOutcome::Edit(h.path.clone()));
.map_or(FindOutcome::Running, |h| FindOutcome::Edit(h.path.clone(), h.line));
}
match key {
Key::ESCAPE => FindOutcome::Cancel,
@@ -630,7 +630,7 @@ mod tests {
// "a.txt" (matches the `a.txt` fixture file).
type_pattern(&mut d, "a.txt");
match d.handle_key(Key::f(3)) {
FindOutcome::View(p) => assert_eq!(p, dir.join("a.txt")),
FindOutcome::View(p, _) => assert_eq!(p, dir.join("a.txt")),
other => panic!("expected View, got {other:?}"),
}
let _ = fs::remove_dir_all(&dir);
@@ -642,7 +642,7 @@ mod tests {
let mut d = FindDialog::new(dir.clone());
type_pattern(&mut d, "a.txt");
match d.handle_key(Key::f(4)) {
FindOutcome::Edit(p) => assert_eq!(p, dir.join("a.txt")),
FindOutcome::Edit(p, _) => assert_eq!(p, dir.join("a.txt")),
other => panic!("expected Edit, got {other:?}"),
}
let _ = fs::remove_dir_all(&dir);