From 5d33dbacac3564c50b9f3a74cfef6a956c35dd80 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Wed, 3 Aug 2022 23:05:52 -0500 Subject: [PATCH] add a CLI flag for specifying config file location (#2666) --- book/src/configuration.md | 3 +++ contrib/completion/hx.bash | 2 +- contrib/completion/hx.fish | 1 + contrib/completion/hx.zsh | 2 ++ helix-loader/src/lib.rs | 42 ++++++++++++++++++++++++++--------- helix-term/src/application.rs | 3 +-- helix-term/src/args.rs | 5 +++++ helix-term/src/main.rs | 6 +++-- 8 files changed, 48 insertions(+), 16 deletions(-) diff --git a/book/src/configuration.md b/book/src/configuration.md index 5eb94c4e9..e418869fc 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -25,6 +25,9 @@ # Configuration hidden = false ``` +You may also specify a file to use for configuration with the `-c` or +`--config` CLI argument: `hx -c path/to/custom-config.toml`. + ## Editor ### `[editor]` Section diff --git a/contrib/completion/hx.bash b/contrib/completion/hx.bash index 87c340284..8a2d9777b 100644 --- a/contrib/completion/hx.bash +++ b/contrib/completion/hx.bash @@ -16,7 +16,7 @@ _hx() { COMPREPLY=($(compgen -W "$languages" -- $2)) ;; *) - COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit" -- $2)) + COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar --vsplit --hsplit -c --config" -- $2)) ;; esac } && complete -F _hx hx diff --git a/contrib/completion/hx.fish b/contrib/completion/hx.fish index df2fb500c..65f248d42 100644 --- a/contrib/completion/hx.fish +++ b/contrib/completion/hx.fish @@ -11,3 +11,4 @@ complete -c hx -s v -o vv -o vvv -d "Increases logging verbosity" complete -c hx -s V -l version -d "Prints version information" complete -c hx -l vsplit -d "Splits all given files vertically into different windows" complete -c hx -l hsplit -d "Splits all given files horizontally into different windows" +complete -c hx -s c -l config -d "Specifies a file to use for completion" diff --git a/contrib/completion/hx.zsh b/contrib/completion/hx.zsh index f9d58d3c6..e3375656d 100644 --- a/contrib/completion/hx.zsh +++ b/contrib/completion/hx.zsh @@ -16,6 +16,8 @@ _hx() { "--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \ "--vsplit[Splits all given files vertically into different windows]" \ "--hsplit[Splits all given files horizontally into different windows]" \ + "-c[Specifies a file to use for configuration]" \ + "--config[Specifies a file to use for configuration]" \ "*:file:_files" case "$state" in diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 1ba48e7b2..015b39a59 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -2,11 +2,28 @@ pub mod grammar; use etcetera::base_strategy::{choose_base_strategy, BaseStrategy}; +use std::path::PathBuf; -pub static RUNTIME_DIR: once_cell::sync::Lazy = - once_cell::sync::Lazy::new(runtime_dir); +pub static RUNTIME_DIR: once_cell::sync::Lazy = once_cell::sync::Lazy::new(runtime_dir); -pub fn runtime_dir() -> std::path::PathBuf { +static CONFIG_FILE: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); + +pub fn initialize_config_file(specified_file: Option) { + let config_file = specified_file.unwrap_or_else(|| { + let config_dir = config_dir(); + + if !config_dir.exists() { + std::fs::create_dir_all(&config_dir).ok(); + } + + config_dir.join("config.toml") + }); + + // We should only initialize this value once. + CONFIG_FILE.set(config_file).ok(); +} + +pub fn runtime_dir() -> PathBuf { if let Ok(dir) = std::env::var("HELIX_RUNTIME") { return dir.into(); } @@ -31,7 +48,7 @@ pub fn runtime_dir() -> std::path::PathBuf { .unwrap() } -pub fn config_dir() -> std::path::PathBuf { +pub fn config_dir() -> PathBuf { // TODO: allow env var override let strategy = choose_base_strategy().expect("Unable to find the config directory!"); let mut path = strategy.config_dir(); @@ -39,7 +56,7 @@ pub fn config_dir() -> std::path::PathBuf { path } -pub fn local_config_dirs() -> Vec { +pub fn local_config_dirs() -> Vec { let directories = find_root_impl(None, &[".helix".to_string()]) .into_iter() .map(|path| path.join(".helix")) @@ -48,7 +65,7 @@ pub fn local_config_dirs() -> Vec { directories } -pub fn cache_dir() -> std::path::PathBuf { +pub fn cache_dir() -> PathBuf { // TODO: allow env var override let strategy = choose_base_strategy().expect("Unable to find the config directory!"); let mut path = strategy.cache_dir(); @@ -56,19 +73,22 @@ pub fn cache_dir() -> std::path::PathBuf { path } -pub fn config_file() -> std::path::PathBuf { - config_dir().join("config.toml") +pub fn config_file() -> PathBuf { + CONFIG_FILE + .get() + .map(|path| path.to_path_buf()) + .unwrap_or_else(|| config_dir().join("config.toml")) } -pub fn lang_config_file() -> std::path::PathBuf { +pub fn lang_config_file() -> PathBuf { config_dir().join("languages.toml") } -pub fn log_file() -> std::path::PathBuf { +pub fn log_file() -> PathBuf { cache_dir().join("helix.log") } -pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec { +pub fn find_root_impl(root: Option<&str>, root_markers: &[String]) -> Vec { let current_dir = std::env::current_dir().expect("unable to determine current directory"); let mut directories = Vec::new(); diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 50e72cf71..527ca1c79 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -89,9 +89,8 @@ pub fn new(args: Args, config: Config) -> Result { use helix_view::editor::Action; - let config_dir = helix_loader::config_dir(); let theme_loader = std::sync::Arc::new(theme::Loader::new( - &config_dir, + &helix_loader::config_dir(), &helix_loader::runtime_dir(), )); diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs index c3019ea7c..d16d7dfdf 100644 --- a/helix-term/src/args.rs +++ b/helix-term/src/args.rs @@ -14,6 +14,7 @@ pub struct Args { pub build_grammars: bool, pub split: Option, pub verbosity: u64, + pub config_file: Option, pub files: Vec<(PathBuf, Position)>, } @@ -43,6 +44,10 @@ pub fn parse_args() -> Result { anyhow::bail!("--grammar must be followed by either 'fetch' or 'build'") } }, + "-c" | "--config" => match argv.next().as_deref() { + Some(path) => args.config_file = Some(path.into()), + None => anyhow::bail!("--config must specify a path to read"), + }, arg if arg.starts_with("--") => { anyhow::bail!("unexpected double dash argument: {}", arg) } diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 83af75882..7f04f2014 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -64,6 +64,7 @@ async fn main_impl() -> Result { --health [LANG] Checks for potential errors in editor setup If given, checks for config errors in language LANG -g, --grammar {{fetch|build}} Fetches or builds tree-sitter grammars listed in languages.toml + -c, --config Specifies a file to use for configuration -v Increases logging verbosity each use for up to 3 times (default file: {}) -V, --version Prints version information @@ -119,14 +120,15 @@ async fn main_impl() -> Result { std::fs::create_dir_all(&config_dir).ok(); } - let config = match std::fs::read_to_string(config_dir.join("config.toml")) { + helix_loader::initialize_config_file(args.config_file.clone()); + + let config = match std::fs::read_to_string(helix_loader::config_file()) { Ok(config) => toml::from_str(&config) .map(helix_term::keymap::merge_keys) .unwrap_or_else(|err| { eprintln!("Bad config: {}", err); eprintln!("Press to continue with default config"); use std::io::Read; - // This waits for an enter press. let _ = std::io::stdin().read(&mut []); Config::default() }),