mirror of
https://github.com/ilyakooo0/helix.git
synced 2024-09-11 16:07:00 +03:00
Fix crash when cwd is deleted (#7185)
This commit is contained in:
parent
1adb19464f
commit
8afc0282f2
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1260,6 +1260,7 @@ version = "0.6.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cc",
|
"cc",
|
||||||
|
"dunce",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
"libloading",
|
"libloading",
|
||||||
"log",
|
"log",
|
||||||
|
@ -88,7 +88,7 @@ pub fn get_normalized_path(path: &Path) -> PathBuf {
|
|||||||
pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
|
pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
|
||||||
let path = expand_tilde(path);
|
let path = expand_tilde(path);
|
||||||
let path = if path.is_relative() {
|
let path = if path.is_relative() {
|
||||||
std::env::current_dir().map(|current_dir| current_dir.join(path))?
|
helix_loader::current_working_dir().join(path)
|
||||||
} else {
|
} else {
|
||||||
path
|
path
|
||||||
};
|
};
|
||||||
@ -99,9 +99,7 @@ pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
|
|||||||
pub fn get_relative_path(path: &Path) -> PathBuf {
|
pub fn get_relative_path(path: &Path) -> PathBuf {
|
||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path);
|
||||||
let path = if path.is_absolute() {
|
let path = if path.is_absolute() {
|
||||||
let cwdir = std::env::current_dir()
|
let cwdir = get_normalized_path(&helix_loader::current_working_dir());
|
||||||
.map(|path| get_normalized_path(&path))
|
|
||||||
.expect("couldn't determine current directory");
|
|
||||||
get_normalized_path(&path)
|
get_normalized_path(&path)
|
||||||
.strip_prefix(cwdir)
|
.strip_prefix(cwdir)
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
@ -142,7 +140,7 @@ pub fn get_relative_path(path: &Path) -> PathBuf {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
pub fn get_truncated_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
pub fn get_truncated_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||||
let cwd = std::env::current_dir().unwrap_or_default();
|
let cwd = helix_loader::current_working_dir();
|
||||||
let path = path
|
let path = path
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.strip_prefix(cwd)
|
.strip_prefix(cwd)
|
||||||
|
@ -29,6 +29,7 @@ which = "4.4"
|
|||||||
cc = { version = "1" }
|
cc = { version = "1" }
|
||||||
threadpool = { version = "1.0" }
|
threadpool = { version = "1.0" }
|
||||||
tempfile = "3.6.0"
|
tempfile = "3.6.0"
|
||||||
|
dunce = "1.0.4"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
libloading = "0.8"
|
libloading = "0.8"
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
|
use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
pub const VERSION_AND_GIT_HASH: &str = env!("VERSION_AND_GIT_HASH");
|
pub const VERSION_AND_GIT_HASH: &str = env!("VERSION_AND_GIT_HASH");
|
||||||
|
|
||||||
|
static CWD: RwLock<Option<PathBuf>> = RwLock::new(None);
|
||||||
|
|
||||||
static RUNTIME_DIRS: once_cell::sync::Lazy<Vec<PathBuf>> =
|
static RUNTIME_DIRS: once_cell::sync::Lazy<Vec<PathBuf>> =
|
||||||
once_cell::sync::Lazy::new(prioritize_runtime_dirs);
|
once_cell::sync::Lazy::new(prioritize_runtime_dirs);
|
||||||
|
|
||||||
@ -13,6 +16,31 @@
|
|||||||
|
|
||||||
static LOG_FILE: once_cell::sync::OnceCell<PathBuf> = once_cell::sync::OnceCell::new();
|
static LOG_FILE: once_cell::sync::OnceCell<PathBuf> = once_cell::sync::OnceCell::new();
|
||||||
|
|
||||||
|
// Get the current working directory.
|
||||||
|
// This information is managed internally as the call to std::env::current_dir
|
||||||
|
// might fail if the cwd has been deleted.
|
||||||
|
pub fn current_working_dir() -> PathBuf {
|
||||||
|
if let Some(path) = &*CWD.read().unwrap() {
|
||||||
|
return path.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = std::env::current_dir()
|
||||||
|
.and_then(dunce::canonicalize)
|
||||||
|
.expect("Couldn't determine current working directory");
|
||||||
|
let mut cwd = CWD.write().unwrap();
|
||||||
|
*cwd = Some(path.clone());
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_current_working_dir(path: PathBuf) -> std::io::Result<()> {
|
||||||
|
let path = dunce::canonicalize(path)?;
|
||||||
|
std::env::set_current_dir(path.clone())?;
|
||||||
|
let mut cwd = CWD.write().unwrap();
|
||||||
|
*cwd = Some(path);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn initialize_config_file(specified_file: Option<PathBuf>) {
|
pub fn initialize_config_file(specified_file: Option<PathBuf>) {
|
||||||
let config_file = specified_file.unwrap_or_else(default_config_file);
|
let config_file = specified_file.unwrap_or_else(default_config_file);
|
||||||
ensure_parent_dir(&config_file);
|
ensure_parent_dir(&config_file);
|
||||||
@ -217,7 +245,7 @@ fn get_name(v: &Value) -> Option<&str> {
|
|||||||
/// If no workspace was found returns (CWD, true).
|
/// If no workspace was found returns (CWD, true).
|
||||||
/// Otherwise (workspace, false) is returned
|
/// Otherwise (workspace, false) is returned
|
||||||
pub fn find_workspace() -> (PathBuf, bool) {
|
pub fn find_workspace() -> (PathBuf, bool) {
|
||||||
let current_dir = std::env::current_dir().expect("unable to determine current directory");
|
let current_dir = current_working_dir();
|
||||||
for ancestor in current_dir.ancestors() {
|
for ancestor in current_dir.ancestors() {
|
||||||
if ancestor.join(".git").exists() || ancestor.join(".helix").exists() {
|
if ancestor.join(".git").exists() || ancestor.join(".helix").exists() {
|
||||||
return (ancestor.to_owned(), false);
|
return (ancestor.to_owned(), false);
|
||||||
@ -243,9 +271,21 @@ fn ensure_parent_dir(path: &Path) {
|
|||||||
mod merge_toml_tests {
|
mod merge_toml_tests {
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use super::merge_toml_values;
|
use super::{current_working_dir, merge_toml_values, set_current_working_dir};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn current_dir_is_set() {
|
||||||
|
let new_path = dunce::canonicalize(std::env::temp_dir()).unwrap();
|
||||||
|
let cwd = current_working_dir();
|
||||||
|
assert_ne!(cwd, new_path);
|
||||||
|
|
||||||
|
set_current_working_dir(new_path.clone()).expect("Couldn't set new path");
|
||||||
|
|
||||||
|
let cwd = current_working_dir();
|
||||||
|
assert_eq!(cwd, new_path);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn language_toml_map_merges() {
|
fn language_toml_map_merges() {
|
||||||
const USER: &str = r#"
|
const USER: &str = r#"
|
||||||
|
@ -931,7 +931,7 @@ pub fn find_lsp_workspace(
|
|||||||
let mut file = if file.is_absolute() {
|
let mut file = if file.is_absolute() {
|
||||||
file.to_path_buf()
|
file.to_path_buf()
|
||||||
} else {
|
} else {
|
||||||
let current_dir = std::env::current_dir().expect("unable to determine current directory");
|
let current_dir = helix_loader::current_working_dir();
|
||||||
current_dir.join(file)
|
current_dir.join(file)
|
||||||
};
|
};
|
||||||
file = path::get_normalized_path(&file);
|
file = path::get_normalized_path(&file);
|
||||||
|
@ -163,7 +163,7 @@ pub fn new(
|
|||||||
} else if !args.files.is_empty() {
|
} else if !args.files.is_empty() {
|
||||||
let first = &args.files[0].0; // we know it's not empty
|
let first = &args.files[0].0; // we know it's not empty
|
||||||
if first.is_dir() {
|
if first.is_dir() {
|
||||||
std::env::set_current_dir(first).context("set current dir")?;
|
helix_loader::set_current_working_dir(first.clone())?;
|
||||||
editor.new_file(Action::VerticalSplit);
|
editor.new_file(Action::VerticalSplit);
|
||||||
let picker = ui::file_picker(".".into(), &config.load().editor);
|
let picker = ui::file_picker(".".into(), &config.load().editor);
|
||||||
compositor.push(Box::new(overlaid(picker)));
|
compositor.push(Box::new(overlaid(picker)));
|
||||||
|
@ -2080,8 +2080,12 @@ fn format(&self, current_path: &Self::Data) -> Row {
|
|||||||
.binary_detection(BinaryDetection::quit(b'\x00'))
|
.binary_detection(BinaryDetection::quit(b'\x00'))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let search_root = std::env::current_dir()
|
let search_root = helix_loader::current_working_dir();
|
||||||
.expect("Global search error: Failed to get current dir");
|
if !search_root.exists() {
|
||||||
|
editor.set_error("Current working directory does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let dedup_symlinks = file_picker_config.deduplicate_links;
|
let dedup_symlinks = file_picker_config.deduplicate_links;
|
||||||
let absolute_root = search_root
|
let absolute_root = search_root
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
@ -2173,7 +2177,9 @@ fn format(&self, current_path: &Self::Data) -> Row {
|
|||||||
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
let call: job::Callback = Callback::EditorCompositor(Box::new(
|
||||||
move |editor: &mut Editor, compositor: &mut Compositor| {
|
move |editor: &mut Editor, compositor: &mut Compositor| {
|
||||||
if all_matches.is_empty() {
|
if all_matches.is_empty() {
|
||||||
editor.set_status("No matches found");
|
if !editor.is_err() {
|
||||||
|
editor.set_status("No matches found");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2518,6 +2524,10 @@ fn append_mode(cx: &mut Context) {
|
|||||||
|
|
||||||
fn file_picker(cx: &mut Context) {
|
fn file_picker(cx: &mut Context) {
|
||||||
let root = find_workspace().0;
|
let root = find_workspace().0;
|
||||||
|
if !root.exists() {
|
||||||
|
cx.editor.set_error("Workspace directory does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let picker = ui::file_picker(root, &cx.editor.config());
|
let picker = ui::file_picker(root, &cx.editor.config());
|
||||||
cx.push_layer(Box::new(overlaid(picker)));
|
cx.push_layer(Box::new(overlaid(picker)));
|
||||||
}
|
}
|
||||||
@ -2539,7 +2549,12 @@ fn file_picker_in_current_buffer_directory(cx: &mut Context) {
|
|||||||
cx.push_layer(Box::new(overlaid(picker)));
|
cx.push_layer(Box::new(overlaid(picker)));
|
||||||
}
|
}
|
||||||
fn file_picker_in_current_directory(cx: &mut Context) {
|
fn file_picker_in_current_directory(cx: &mut Context) {
|
||||||
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("./"));
|
let cwd = helix_loader::current_working_dir();
|
||||||
|
if !cwd.exists() {
|
||||||
|
cx.editor
|
||||||
|
.set_error("Current working directory does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let picker = ui::file_picker(cwd, &cx.editor.config());
|
let picker = ui::file_picker(cwd, &cx.editor.config());
|
||||||
cx.push_layer(Box::new(overlaid(picker)));
|
cx.push_layer(Box::new(overlaid(picker)));
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ pub fn dap_start_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args.insert("cwd", to_value(std::env::current_dir().unwrap())?);
|
args.insert("cwd", to_value(helix_loader::current_working_dir())?);
|
||||||
|
|
||||||
let args = to_value(args).unwrap();
|
let args = to_value(args).unwrap();
|
||||||
|
|
||||||
|
@ -1033,7 +1033,7 @@ fn goto_impl(
|
|||||||
locations: Vec<lsp::Location>,
|
locations: Vec<lsp::Location>,
|
||||||
offset_encoding: OffsetEncoding,
|
offset_encoding: OffsetEncoding,
|
||||||
) {
|
) {
|
||||||
let cwdir = std::env::current_dir().unwrap_or_default();
|
let cwdir = helix_loader::current_working_dir();
|
||||||
|
|
||||||
match locations.as_slice() {
|
match locations.as_slice() {
|
||||||
[location] => {
|
[location] => {
|
||||||
|
@ -1093,14 +1093,11 @@ fn change_current_directory(
|
|||||||
.as_ref(),
|
.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Err(e) = std::env::set_current_dir(dir) {
|
helix_loader::set_current_working_dir(dir)?;
|
||||||
bail!("Couldn't change the current working directory: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
|
|
||||||
cx.editor.set_status(format!(
|
cx.editor.set_status(format!(
|
||||||
"Current working directory is now {}",
|
"Current working directory is now {}",
|
||||||
cwd.display()
|
helix_loader::current_working_dir().display()
|
||||||
));
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1114,9 +1111,14 @@ fn show_current_directory(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
|
let cwd = helix_loader::current_working_dir();
|
||||||
cx.editor
|
let message = format!("Current working directory is {}", cwd.display());
|
||||||
.set_status(format!("Current working directory is {}", cwd.display()));
|
|
||||||
|
if cwd.exists() {
|
||||||
|
cx.editor.set_status(message);
|
||||||
|
} else {
|
||||||
|
cx.editor.set_error(format!("{} (deleted)", message));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ fn filename_impl<F>(_editor: &Editor, input: &str, filter_fn: F) -> Vec<Completi
|
|||||||
match path.parent() {
|
match path.parent() {
|
||||||
Some(path) if !path.as_os_str().is_empty() => path.to_path_buf(),
|
Some(path) if !path.as_os_str().is_empty() => path.to_path_buf(),
|
||||||
// Path::new("h")'s parent is Some("")...
|
// Path::new("h")'s parent is Some("")...
|
||||||
_ => std::env::current_dir().expect("couldn't determine current directory"),
|
_ => helix_loader::current_working_dir(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user