From 658fdcf0a75e9bc5f224ead2ba6edcc66849164b Mon Sep 17 00:00:00 2001 From: lawrence3699 Date: Sun, 19 Apr 2026 12:50:00 +1000 Subject: [PATCH] fix: resolve --file paths from subdirectories --- src/app.rs | 135 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 127 insertions(+), 8 deletions(-) diff --git a/src/app.rs b/src/app.rs index 8626aa3b8e..f8f4e6bf95 100644 --- a/src/app.rs +++ b/src/app.rs @@ -54,6 +54,7 @@ use ratatui::{ }; use std::{ cell::{Cell, RefCell}, + env, path::{Path, PathBuf}, rc::Rc, }; @@ -178,14 +179,10 @@ impl App { let mut select_file: Option = None; let tab = if let Some(file) = cliargs.select_file { - // convert to relative git path - if let Ok(abs) = file.canonicalize() { - if let Ok(path) = abs.strip_prefix( - env.repo.borrow().gitpath().canonicalize()?, - ) { - select_file = Some(Path::new(".").join(path)); - } - } + select_file = resolve_initial_select_file( + file.as_path(), + &env.repo.borrow(), + ); 2 } else { env.options.borrow().current_tab() @@ -490,6 +487,48 @@ impl App { } } +fn resolve_initial_select_file( + file: &Path, + repo_path: &RepoPath, +) -> Option { + resolve_initial_select_file_from_cwd( + file, + repo_path, + &env::current_dir().ok()?, + ) +} + +fn resolve_initial_select_file_from_cwd( + file: &Path, + repo_path: &RepoPath, + cwd: &Path, +) -> Option { + let repo_root = PathBuf::from(repo_work_dir(repo_path).ok()?) + .canonicalize() + .ok()?; + let cwd = cwd.canonicalize().ok()?; + let mut candidates = Vec::new(); + + if file.is_absolute() { + candidates.push(file.to_path_buf()); + } else { + candidates.push(cwd.join(file)); + if cwd != repo_root { + candidates.push(repo_root.join(file)); + } + } + + for candidate in candidates { + if let Ok(abs) = candidate.canonicalize() { + if let Ok(path) = abs.strip_prefix(&repo_root) { + return Some(Path::new(".").join(path)); + } + } + } + + None +} + // private impls impl App { accessors!( @@ -1227,3 +1266,83 @@ impl App { ); } } + +#[cfg(test)] +mod tests { + use super::{resolve_initial_select_file_from_cwd, RepoPath}; + use std::{fs, path::Path, process::Command}; + use tempfile::TempDir; + + fn make_repo_with_nested_file() -> (TempDir, RepoPath) { + let temp_dir = TempDir::new().expect("create temp repo"); + let status = Command::new("git") + .arg("init") + .arg("-q") + .arg(temp_dir.path()) + .status() + .expect("run git init"); + assert!(status.success(), "git init should succeed"); + + let nested_dir = temp_dir.path().join("frontend/src"); + fs::create_dir_all(&nested_dir) + .expect("create nested frontend/src directory"); + fs::write(nested_dir.join("index.html"), "\n") + .expect("write nested test file"); + let repo_path: RepoPath = temp_dir + .path() + .to_str() + .expect("temp path should be utf-8") + .into(); + (temp_dir, repo_path) + } + + #[test] + fn resolve_initial_select_file_from_repo_root() { + let (temp_dir, repo_path) = make_repo_with_nested_file(); + + let selected = resolve_initial_select_file_from_cwd( + Path::new("frontend/src/index.html"), + &repo_path, + temp_dir.path(), + ); + + assert_eq!( + selected, + Some(Path::new(".").join("frontend/src/index.html")) + ); + } + + #[test] + fn resolve_initial_select_file_from_subdir_cwd_relative_path() { + let (temp_dir, repo_path) = make_repo_with_nested_file(); + let cwd = temp_dir.path().join("frontend"); + + let selected = resolve_initial_select_file_from_cwd( + Path::new("src/index.html"), + &repo_path, + &cwd, + ); + + assert_eq!( + selected, + Some(Path::new(".").join("frontend/src/index.html")) + ); + } + + #[test] + fn resolve_initial_select_file_from_subdir_repo_relative_path() { + let (temp_dir, repo_path) = make_repo_with_nested_file(); + let cwd = temp_dir.path().join("frontend"); + + let selected = resolve_initial_select_file_from_cwd( + Path::new("frontend/src/index.html"), + &repo_path, + &cwd, + ); + + assert_eq!( + selected, + Some(Path::new(".").join("frontend/src/index.html")) + ); + } +}