diff --git a/book/src/configuration.md b/book/src/configuration.md index 3fa9b307ab385..9bc9a345228ba 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -25,6 +25,9 @@ select = "underline" 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 6371bedb67bb6..b6b09e5c29c81 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" -- $2)) + COMPREPLY=($(compgen -fd -W "-h --help --tutor -V --version -v -vv -vvv --health -g --grammar -c --config" -- $2)) ;; esac } && complete -F _hx hx diff --git a/contrib/completion/hx.fish b/contrib/completion/hx.fish index 4ec690d8b0b85..e62c97a6c4ce2 100644 --- a/contrib/completion/hx.fish +++ b/contrib/completion/hx.fish @@ -9,4 +9,5 @@ complete -c hx -l health -x -a "$langs" -d "Checks for errors in editor setup" complete -c hx -s g -l grammar -x -a "fetch build" -d "Fetches or builds tree-sitter grammars" 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 -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 16631519bc461..c26328f62df1a 100644 --- a/contrib/completion/hx.zsh +++ b/contrib/completion/hx.zsh @@ -14,6 +14,8 @@ _hx() { "--health[Checks for errors in editor setup]:language:->health" \ "-g[Fetches or builds tree-sitter grammars]:action:->grammar" \ "--grammar[Fetches or builds tree-sitter grammars]:action:->grammar" \ + "-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 ff4414b2647d2..822d933a0d98f 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -2,11 +2,28 @@ pub mod config; 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 48e9c2758737c..fc7710b0bf8ba 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -88,9 +88,8 @@ impl Application { 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 b99c7d1a27687..9b0dc421c3a47 100644 --- a/helix-term/src/args.rs +++ b/helix-term/src/args.rs @@ -12,6 +12,7 @@ pub struct Args { pub fetch_grammars: bool, pub build_grammars: bool, pub verbosity: u64, + pub config_file: Option, pub files: Vec<(PathBuf, Position)>, } @@ -39,6 +40,10 @@ impl Args { 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 7b26fb119457c..bf9a40cc2c653 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -64,6 +64,7 @@ FLAGS: --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 @@ -117,14 +118,15 @@ FLAGS: 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() }),