summaryrefslogtreecommitdiff
path: root/helix-loader/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-loader/src/lib.rs')
-rw-r--r--helix-loader/src/lib.rs81
1 files changed, 67 insertions, 14 deletions
diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs
index 8dc2928a..04b44b5a 100644
--- a/helix-loader/src/lib.rs
+++ b/helix-loader/src/lib.rs
@@ -2,11 +2,12 @@ pub mod config;
pub mod grammar;
use etcetera::base_strategy::{choose_base_strategy, BaseStrategy};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
pub const VERSION_AND_GIT_HASH: &str = env!("VERSION_AND_GIT_HASH");
-pub static RUNTIME_DIR: once_cell::sync::Lazy<PathBuf> = once_cell::sync::Lazy::new(runtime_dir);
+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();
@@ -25,31 +26,83 @@ pub fn initialize_config_file(specified_file: Option<PathBuf>) {
CONFIG_FILE.set(config_file).ok();
}
-pub fn runtime_dir() -> PathBuf {
- if let Ok(dir) = std::env::var("HELIX_RUNTIME") {
- return dir.into();
- }
-
+/// A list of runtime directories from highest to lowest priority
+///
+/// The priority is:
+///
+/// 1. sibling directory to `CARGO_MANIFEST_DIR` (if environment variable is set)
+/// 2. subdirectory of user config directory (always included)
+/// 3. `HELIX_RUNTIME` (if environment variable is set)
+/// 4. subdirectory of path to helix executable (always included)
+///
+/// Postcondition: returns at least two paths (they might not exist).
+fn prioritize_runtime_dirs() -> Vec<PathBuf> {
+ const RT_DIR: &str = "runtime";
+ // Adding higher priority first
+ let mut rt_dirs = Vec::new();
if let Ok(dir) = std::env::var("CARGO_MANIFEST_DIR") {
// this is the directory of the crate being run by cargo, we need the workspace path so we take the parent
let path = std::path::PathBuf::from(dir).parent().unwrap().join(RT_DIR);
log::debug!("runtime dir: {}", path.to_string_lossy());
- return path;
+ rt_dirs.push(path);
}
- const RT_DIR: &str = "runtime";
- let conf_dir = config_dir().join(RT_DIR);
- if conf_dir.exists() {
- return conf_dir;
+ let conf_rt_dir = config_dir().join(RT_DIR);
+ rt_dirs.push(conf_rt_dir);
+
+ if let Ok(dir) = std::env::var("HELIX_RUNTIME") {
+ rt_dirs.push(dir.into());
}
// fallback to location of the executable being run
// canonicalize the path in case the executable is symlinked
- std::env::current_exe()
+ let exe_rt_dir = std::env::current_exe()
.ok()
.and_then(|path| std::fs::canonicalize(path).ok())
.and_then(|path| path.parent().map(|path| path.to_path_buf().join(RT_DIR)))
- .unwrap()
+ .unwrap();
+ rt_dirs.push(exe_rt_dir);
+ rt_dirs
+}
+
+/// Runtime directories ordered from highest to lowest priority
+///
+/// All directories should be checked when looking for files.
+///
+/// Postcondition: returns at least one path (it might not exist).
+pub fn runtime_dirs() -> &'static [PathBuf] {
+ &RUNTIME_DIRS
+}
+
+/// Find file with path relative to runtime directory
+///
+/// `rel_path` should be the relative path from within the `runtime/` directory.
+/// The valid runtime directories are searched in priority order and the first
+/// file found to exist is returned, otherwise None.
+fn find_runtime_file(rel_path: &Path) -> Option<PathBuf> {
+ RUNTIME_DIRS.iter().find_map(|rt_dir| {
+ let path = rt_dir.join(rel_path);
+ if path.exists() {
+ Some(path)
+ } else {
+ None
+ }
+ })
+}
+
+/// Find file with path relative to runtime directory
+///
+/// `rel_path` should be the relative path from within the `runtime/` directory.
+/// The valid runtime directories are searched in priority order and the first
+/// file found to exist is returned, otherwise the path to the final attempt
+/// that failed.
+pub fn runtime_file(rel_path: &Path) -> PathBuf {
+ find_runtime_file(rel_path).unwrap_or_else(|| {
+ RUNTIME_DIRS
+ .last()
+ .map(|dir| dir.join(rel_path))
+ .unwrap_or_default()
+ })
}
pub fn config_dir() -> PathBuf {