From 7138860ce870c2b77a02bfbe84f6a4a6fd3e8620 Mon Sep 17 00:00:00 2001 From: LoveIsGrief Date: Sat, 3 Aug 2024 00:46:37 +0200 Subject: [PATCH] feat: add editor.first-file-sets-work-dir config option When starting helix, it already supports updating the working directory by argument or if the first argument is a directory itself. The missing piece is updating the working directory when the first argument is a file. The user can set this in their configuration now. --- helix-stdx/src/env.rs | 18 ++++++++++++++---- helix-term/src/commands/typed.rs | 2 +- helix-term/src/main.rs | 21 ++++++++++++++++----- helix-view/src/editor.rs | 3 +++ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/helix-stdx/src/env.rs b/helix-stdx/src/env.rs index 51450d225..3bae5f1d3 100644 --- a/helix-stdx/src/env.rs +++ b/helix-stdx/src/env.rs @@ -33,11 +33,21 @@ pub fn current_working_dir() -> PathBuf { cwd } -pub fn set_current_working_dir(path: impl AsRef) -> std::io::Result<()> { +/// Updates the current working directory of the current thread +/// +/// Should the given path be a file, it will fail **unless** `allow_file` is passed and its parent +/// can be found. +pub fn set_current_working_dir(path: impl AsRef, allow_file: bool) -> std::io::Result<()> { let path = crate::path::canonicalize(path); - std::env::set_current_dir(&path)?; + if path.is_file() && allow_file { + std::env::set_current_dir(path.parent().ok_or_else(|| { + std::io::Error::new(std::io::ErrorKind::NotFound, "File has no parent?") + })?)?; + } else { + std::env::set_current_dir(&path)?; + } let mut cwd = CWD.write().unwrap(); - *cwd = Some(path); + *cwd = Some(std::env::current_dir()?); Ok(()) } @@ -83,7 +93,7 @@ mod tests { let cwd = current_working_dir(); assert_ne!(cwd, new_path); - set_current_working_dir(&new_path).expect("Couldn't set new path"); + set_current_working_dir(&new_path, false).expect("Couldn't set new path"); let cwd = current_working_dir(); assert_eq!(cwd, new_path); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 7ad0369fc..a267b01ce 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1093,7 +1093,7 @@ fn change_current_directory( .as_ref(); let dir = helix_stdx::path::expand_tilde(Path::new(dir)); - helix_stdx::env::set_current_working_dir(dir)?; + helix_stdx::env::set_current_working_dir(dir, false)?; cx.editor.set_status(format!( "Current working directory is now {}", diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index a3a27a076..985511062 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -122,12 +122,17 @@ FLAGS: } // NOTE: Set the working directory early so the correct configuration is loaded. Be aware that // Application::new() depends on this logic so it must be updated if this changes. - if let Some(path) = &args.working_directory { - helix_stdx::env::set_current_working_dir(path)?; - } else if let Some((path, _)) = args.files.first().filter(|p| p.0.is_dir()) { + let first_arg = args.files.first(); + let cwd_changed = if let Some(path) = &args.working_directory { + helix_stdx::env::set_current_working_dir(path, false)?; + true + } else if let Some((path, _)) = first_arg.filter(|p| p.0.is_dir()) { // If the first file is a directory, it will be the working directory unless -w was specified - helix_stdx::env::set_current_working_dir(path)?; - } + helix_stdx::env::set_current_working_dir(path, false)?; + true + } else { + false + }; let config = match Config::load_default() { Ok(config) => config, @@ -144,6 +149,12 @@ FLAGS: } }; + if let Some((path, _)) = first_arg { + if !cwd_changed && config.editor.first_file_sets_work_dir { + helix_stdx::env::set_current_working_dir(path, true)?; + } + } + let lang_loader = helix_core::config::user_lang_loader().unwrap_or_else(|err| { eprintln!("{}", err); eprintln!("Press to continue with default language config"); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1708b3b4e..c34ab3907 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -345,6 +345,8 @@ pub struct Config { /// Display diagnostic below the line they occur. pub inline_diagnostics: InlineDiagnosticsConfig, pub end_of_line_diagnostics: DiagnosticFilter, + /// Should the first CLI arg be a file, the working directory may be set to its parent + pub first_file_sets_work_dir: bool, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -979,6 +981,7 @@ impl Default for Config { jump_label_alphabet: ('a'..='z').collect(), inline_diagnostics: InlineDiagnosticsConfig::default(), end_of_line_diagnostics: DiagnosticFilter::Disable, + first_file_sets_work_dir: false, } } }