on master help sign in
Fix crash when cwd is deleted (#7185)
commit8afc0282f28e73cf78d1bd7b11d78fd853ae2036 authorYomain <40139584+yo-main@users.noreply.github.com> dateTue 11 Jul 2023, 19:51 (3 years ago) parent1adb194
11 files changed+81−24
Cargo.lock+1 helix-core/src/path.rs+3−5 helix-loader/Cargo.toml+1 helix-loader/src/lib.rs+42−2 helix-lsp/src/lib.rs+1−1 helix-term/src/application.rs+1−1 helix-term/src/commands.rs+19−4 helix-term/src/commands/dap.rs+1−1 helix-term/src/commands/lsp.rs+1−1 helix-term/src/commands/typed.rs+10−8 helix-term/src/ui/mod.rs+1−1
Cargo.lock+1
@@ -1260,6 +1260,7 @@ version = "0.6.0"
12601260dependencies = [
12611261 "anyhow",
12621262 "cc",
1263+ "dunce",
12631264 "etcetera",
12641265 "libloading",
12651266 "log",
helix-core/src/path.rs+3−5
@@ -88,7 +88,7 @@ pub fn get_normalized_path(path: &Path) -> PathBuf {
8888pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
8989 let path = expand_tilde(path);
9090 let path = if path.is_relative() {
91− std::env::current_dir().map(|current_dir| current_dir.join(path))?
91+ helix_loader::current_working_dir().join(path)
9292 } else {
9393 path
9494 };
@@ -99,9 +99,7 @@ pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
9999pub fn get_relative_path(path: &Path) -> PathBuf {
100100 let path = PathBuf::from(path);
101101 let path = if path.is_absolute() {
102− let cwdir = std::env::current_dir()
103− .map(|path| get_normalized_path(&path))
104− .expect("couldn't determine current directory");
102+ let cwdir = get_normalized_path(&helix_loader::current_working_dir());
105103 get_normalized_path(&path)
106104 .strip_prefix(cwdir)
107105 .map(PathBuf::from)
@@ -142,7 +140,7 @@ pub fn get_relative_path(path: &Path) -> PathBuf {
142140/// ```
143141///
144142pub fn get_truncated_path<P: AsRef<Path>>(path: P) -> PathBuf {
145− let cwd = std::env::current_dir().unwrap_or_default();
143+ let cwd = helix_loader::current_working_dir();
146144 let path = path
147145 .as_ref()
148146 .strip_prefix(cwd)
helix-loader/Cargo.toml+1
@@ -29,6 +29,7 @@ which = "4.4"
2929cc = { version = "1" }
3030threadpool = { version = "1.0" }
3131tempfile = "3.6.0"
32+dunce = "1.0.4"
3233
3334[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
3435libloading = "0.8"
helix-loader/src/lib.rs+42−2
@@ -3,9 +3,12 @@ pub mod grammar;
33
44use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
55use std::path::{Path, PathBuf};
6+use std::sync::RwLock;
67
78pub const VERSION_AND_GIT_HASH: &str = env!("VERSION_AND_GIT_HASH");
89
10+static CWD: RwLock<Option<PathBuf>> = RwLock::new(None);
11+
912static RUNTIME_DIRS: once_cell::sync::Lazy<Vec<PathBuf>> =
1013 once_cell::sync::Lazy::new(prioritize_runtime_dirs);
1114
@@ -13,6 +16,31 @@ static CONFIG_FILE: once_cell::sync::OnceCell<PathBuf> = once_cell::sync::OnceCe
1316
1417static LOG_FILE: once_cell::sync::OnceCell<PathBuf> = once_cell::sync::OnceCell::new();
1518
19+// Get the current working directory.
20+// This information is managed internally as the call to std::env::current_dir
21+// might fail if the cwd has been deleted.
22+pub fn current_working_dir() -> PathBuf {
23+ if let Some(path) = &*CWD.read().unwrap() {
24+ return path.clone();
25+ }
26+
27+ let path = std::env::current_dir()
28+ .and_then(dunce::canonicalize)
29+ .expect("Couldn't determine current working directory");
30+ let mut cwd = CWD.write().unwrap();
31+ *cwd = Some(path.clone());
32+
33+ path
34+}
35+
36+pub fn set_current_working_dir(path: PathBuf) -> std::io::Result<()> {
37+ let path = dunce::canonicalize(path)?;
38+ std::env::set_current_dir(path.clone())?;
39+ let mut cwd = CWD.write().unwrap();
40+ *cwd = Some(path);
41+ Ok(())
42+}
43+
1644pub fn initialize_config_file(specified_file: Option<PathBuf>) {
1745 let config_file = specified_file.unwrap_or_else(default_config_file);
1846 ensure_parent_dir(&config_file);
@@ -217,7 +245,7 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value, merge_depth: usi
217245/// If no workspace was found returns (CWD, true).
218246/// Otherwise (workspace, false) is returned
219247pub fn find_workspace() -> (PathBuf, bool) {
220− let current_dir = std::env::current_dir().expect("unable to determine current directory");
248+ let current_dir = current_working_dir();
221249 for ancestor in current_dir.ancestors() {
222250 if ancestor.join(".git").exists() || ancestor.join(".helix").exists() {
223251 return (ancestor.to_owned(), false);
@@ -243,9 +271,21 @@ fn ensure_parent_dir(path: &Path) {
243271mod merge_toml_tests {
244272 use std::str;
245273
246− use super::merge_toml_values;
274+ use super::{current_working_dir, merge_toml_values, set_current_working_dir};
247275 use toml::Value;
248276
277+ #[test]
278+ fn current_dir_is_set() {
279+ let new_path = dunce::canonicalize(std::env::temp_dir()).unwrap();
280+ let cwd = current_working_dir();
281+ assert_ne!(cwd, new_path);
282+
283+ set_current_working_dir(new_path.clone()).expect("Couldn't set new path");
284+
285+ let cwd = current_working_dir();
286+ assert_eq!(cwd, new_path);
287+ }
288+
249289 #[test]
250290 fn language_toml_map_merges() {
251291 const USER: &str = r#"
helix-lsp/src/lib.rs+1−1
@@ -931,7 +931,7 @@ pub fn find_lsp_workspace(
931931 let mut file = if file.is_absolute() {
932932 file.to_path_buf()
933933 } else {
934− let current_dir = std::env::current_dir().expect("unable to determine current directory");
934+ let current_dir = helix_loader::current_working_dir();
935935 current_dir.join(file)
936936 };
937937 file = path::get_normalized_path(&file);
helix-term/src/application.rs+1−1
@@ -163,7 +163,7 @@ impl Application {
163163 } else if !args.files.is_empty() {
164164 let first = &args.files[0].0; // we know it's not empty
165165 if first.is_dir() {
166− std::env::set_current_dir(first).context("set current dir")?;
166+ helix_loader::set_current_working_dir(first.clone())?;
167167 editor.new_file(Action::VerticalSplit);
168168 let picker = ui::file_picker(".".into(), &config.load().editor);
169169 compositor.push(Box::new(overlaid(picker)));
helix-term/src/commands.rs+19−4
@@ -2080,8 +2080,12 @@ fn global_search(cx: &mut Context) {
20802080 .binary_detection(BinaryDetection::quit(b'\x00'))
20812081 .build();
20822082
2083− let search_root = std::env::current_dir()
2084− .expect("Global search error: Failed to get current dir");
2083+ let search_root = helix_loader::current_working_dir();
2084+ if !search_root.exists() {
2085+ editor.set_error("Current working directory does not exist");
2086+ return;
2087+ }
2088+
20852089 let dedup_symlinks = file_picker_config.deduplicate_links;
20862090 let absolute_root = search_root
20872091 .canonicalize()
@@ -2173,7 +2177,9 @@ fn global_search(cx: &mut Context) {
21732177 let call: job::Callback = Callback::EditorCompositor(Box::new(
21742178 move |editor: &mut Editor, compositor: &mut Compositor| {
21752179 if all_matches.is_empty() {
2176− editor.set_status("No matches found");
2180+ if !editor.is_err() {
2181+ editor.set_status("No matches found");
2182+ }
21772183 return;
21782184 }
21792185
@@ -2518,6 +2524,10 @@ fn append_mode(cx: &mut Context) {
25182524
25192525fn file_picker(cx: &mut Context) {
25202526 let root = find_workspace().0;
2527+ if !root.exists() {
2528+ cx.editor.set_error("Workspace directory does not exist");
2529+ return;
2530+ }
25212531 let picker = ui::file_picker(root, &cx.editor.config());
25222532 cx.push_layer(Box::new(overlaid(picker)));
25232533}
@@ -2539,7 +2549,12 @@ fn file_picker_in_current_buffer_directory(cx: &mut Context) {
25392549 cx.push_layer(Box::new(overlaid(picker)));
25402550}
25412551fn file_picker_in_current_directory(cx: &mut Context) {
2542− let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("./"));
2552+ let cwd = helix_loader::current_working_dir();
2553+ if !cwd.exists() {
2554+ cx.editor
2555+ .set_error("Current working directory does not exist");
2556+ return;
2557+ }
25432558 let picker = ui::file_picker(cwd, &cx.editor.config());
25442559 cx.push_layer(Box::new(overlaid(picker)));
25452560}
helix-term/src/commands/dap.rs+1−1
@@ -217,7 +217,7 @@ pub fn dap_start_impl(
217217 }
218218 }
219219
220− args.insert("cwd", to_value(std::env::current_dir().unwrap())?);
220+ args.insert("cwd", to_value(helix_loader::current_working_dir())?);
221221
222222 let args = to_value(args).unwrap();
223223
helix-term/src/commands/lsp.rs+1−1
@@ -1033,7 +1033,7 @@ fn goto_impl(
10331033 locations: Vec<lsp::Location>,
10341034 offset_encoding: OffsetEncoding,
10351035) {
1036− let cwdir = std::env::current_dir().unwrap_or_default();
1036+ let cwdir = helix_loader::current_working_dir();
10371037
10381038 match locations.as_slice() {
10391039 [location] => {
helix-term/src/commands/typed.rs+10−8
@@ -1093,14 +1093,11 @@ fn change_current_directory(
10931093 .as_ref(),
10941094 );
10951095
1096− if let Err(e) = std::env::set_current_dir(dir) {
1097− bail!("Couldn't change the current working directory: {}", e);
1098− }
1096+ helix_loader::set_current_working_dir(dir)?;
10991097
1100− let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
11011098 cx.editor.set_status(format!(
11021099 "Current working directory is now {}",
1103− cwd.display()
1100+ helix_loader::current_working_dir().display()
11041101 ));
11051102 Ok(())
11061103}
@@ -1114,9 +1111,14 @@ fn show_current_directory(
11141111 return Ok(());
11151112 }
11161113
1117− let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
1118− cx.editor
1119− .set_status(format!("Current working directory is {}", cwd.display()));
1114+ let cwd = helix_loader::current_working_dir();
1115+ let message = format!("Current working directory is {}", cwd.display());
1116+
1117+ if cwd.exists() {
1118+ cx.editor.set_status(message);
1119+ } else {
1120+ cx.editor.set_error(format!("{} (deleted)", message));
1121+ }
11201122 Ok(())
11211123}
11221124
helix-term/src/ui/mod.rs+1−1
@@ -472,7 +472,7 @@ pub mod completers {
472472 match path.parent() {
473473 Some(path) if !path.as_os_str().is_empty() => path.to_path_buf(),
474474 // Path::new("h")'s parent is Some("")...
475− _ => std::env::current_dir().expect("couldn't determine current directory"),
475+ _ => helix_loader::current_working_dir(),
476476 }
477477 };
478478