Skip to content

Commit

Permalink
feat: store current dir internally
Browse files Browse the repository at this point in the history
The call to std::env::current_dir might fail
if the cwd has been deleted. As a way to prevent
this from happening, we keep track internally of
the current working directory and display an error
message when any I/O is attempted.
  • Loading branch information
yo-main committed Jul 10, 2023
1 parent f68956a commit def2505
Show file tree
Hide file tree
Showing 11 changed files with 57 additions and 21 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions helix-core/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub fn get_normalized_path(path: &Path) -> PathBuf {
pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
let path = expand_tilde(path);
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 {
path
};
Expand All @@ -99,9 +99,7 @@ pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
pub fn get_relative_path(path: &Path) -> PathBuf {
let path = PathBuf::from(path);
let path = if path.is_absolute() {
let cwdir = std::env::current_dir()
.map(|path| get_normalized_path(&path))
.expect("couldn't determine current directory");
let cwdir = get_normalized_path(&helix_loader::current_working_dir());
get_normalized_path(&path)
.strip_prefix(cwdir)
.map(PathBuf::from)
Expand Down Expand Up @@ -142,7 +140,7 @@ pub fn get_relative_path(path: &Path) -> 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
.as_ref()
.strip_prefix(cwd)
Expand Down
1 change: 1 addition & 0 deletions helix-loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ which = "4.4"
cc = { version = "1" }
threadpool = { version = "1.0" }
tempfile = "3.6.0"
dunce = "1.0.4"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libloading = "0.8"
44 changes: 42 additions & 2 deletions helix-loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,44 @@ pub mod grammar;

use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
use std::path::{Path, PathBuf};
use std::sync::RwLock;

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>> =
once_cell::sync::Lazy::new(prioritize_runtime_dirs);

static CONFIG_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>) {
let config_file = specified_file.unwrap_or_else(default_config_file);
ensure_parent_dir(&config_file);
Expand Down Expand Up @@ -217,7 +245,7 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value, merge_depth: usi
/// If no workspace was found returns (CWD, true).
/// Otherwise (workspace, false) is returned
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() {
if ancestor.join(".git").exists() || ancestor.join(".helix").exists() {
return (ancestor.to_owned(), false);
Expand All @@ -243,9 +271,21 @@ fn ensure_parent_dir(path: &Path) {
mod merge_toml_tests {
use std::str;

use super::merge_toml_values;
use super::{current_working_dir, merge_toml_values, set_current_working_dir};
use toml::Value;

#[test]
fn current_dir_is_set() {
let new_path = std::env::temp_dir();
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]
fn language_toml_map_merges() {
const USER: &str = r#"
Expand Down
2 changes: 1 addition & 1 deletion helix-lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ pub fn find_lsp_workspace(
let mut file = if file.is_absolute() {
file.to_path_buf()
} 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)
};
file = path::get_normalized_path(&file);
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl Application {
} else if !args.files.is_empty() {
let first = &args.files[0].0; // we know it's not empty
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);
let picker = ui::file_picker(".".into(), &config.load().editor);
compositor.push(Box::new(overlaid(picker)));
Expand Down
5 changes: 2 additions & 3 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2075,8 +2075,7 @@ fn global_search(cx: &mut Context) {
.binary_detection(BinaryDetection::quit(b'\x00'))
.build();

let search_root = std::env::current_dir()
.expect("Global search error: Failed to get current dir");
let search_root = helix_loader::current_working_dir();
let dedup_symlinks = file_picker_config.deduplicate_links;
let absolute_root = search_root
.canonicalize()
Expand Down Expand Up @@ -2514,7 +2513,7 @@ fn file_picker_in_current_buffer_directory(cx: &mut Context) {
cx.push_layer(Box::new(overlaid(picker)));
}
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();
let picker = ui::file_picker(cwd, &cx.editor.config());
cx.push_layer(Box::new(overlaid(picker)));
}
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/commands/dap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,7 @@ fn goto_impl(
locations: Vec<lsp::Location>,
offset_encoding: OffsetEncoding,
) {
let cwdir = std::env::current_dir().unwrap_or_default();
let cwdir = helix_loader::current_working_dir();

match locations.as_slice() {
[location] => {
Expand Down
9 changes: 3 additions & 6 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1093,14 +1093,11 @@ fn change_current_directory(
.as_ref(),
);

if let Err(e) = std::env::set_current_dir(dir) {
bail!("Couldn't change the current working directory: {}", e);
}
helix_loader::set_current_working_dir(dir)?;

let cwd = std::env::current_dir().context("Couldn't get the new working directory")?;
cx.editor.set_status(format!(
"Current working directory is now {}",
cwd.display()
helix_loader::current_working_dir().display()
));
Ok(())
}
Expand All @@ -1114,7 +1111,7 @@ fn show_current_directory(
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
.set_status(format!("Current working directory is {}", cwd.display()));
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ pub mod completers {
match path.parent() {
Some(path) if !path.as_os_str().is_empty() => path.to_path_buf(),
// Path::new("h")'s parent is Some("")...
_ => std::env::current_dir().expect("couldn't determine current directory"),
_ => helix_loader::current_working_dir(),
}
};

Expand Down

0 comments on commit def2505

Please sign in to comment.