diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs index 8806d4602154f..c1dfe8b8ba1b6 100644 --- a/helix-term/src/config.rs +++ b/helix-term/src/config.rs @@ -56,70 +56,93 @@ impl Config { Config::load(helix_loader::config_file()) } - // Load a merged config from configuration and repo/.helix/config.toml - pub fn load_merged_config() -> Result { + // Load a merged config from configuration and $PWD/.helix/config.toml + pub fn load_merged_config() -> Config { let root_config: Config = std::fs::read_to_string(helix_loader::config_file()) - .map(|config| toml::from_str(&config))? - .unwrap_or_default(); + .ok() + .and_then(|config| toml::from_str(&config).ok()) + .unwrap_or_else(|| { + eprintln!("Bad config: {:?}", helix_loader::config_file()); + Config::halt_and_confirm("default"); + Config::default() + }); // Load each config file let local_config_values = helix_loader::local_config_dirs() .into_iter() .map(|path| path.join("config.toml")) .chain([helix_loader::config_file()]) - .filter_map(|file| Config::load_config_toml_values(&root_config, file).ok()) - .collect::, _>>(); + .filter_map(|file| Config::load_config_toml_values(&root_config, file)); // Merge configs and return, or alert user of error and load default - let config = match local_config_values { - Ok(values) => values - .into_iter() - .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { - helix_loader::merge_toml_values(b, a, 3) - }) - .try_into()?, - Err(err) => { - eprintln!("Bad configs: {:#?}", 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() - } - }; - Ok(config) + match local_config_values + .fold(toml::Value::Table(toml::value::Table::default()), |a, b| { + helix_loader::merge_toml_values(b, a, 3) + }) + .try_into() + { + Ok(conf) => conf, + Err(_) => root_config, + } } + // Load a specific config file if allowed by config + // Stay with toml::Values as they can be merged pub fn load_config_toml_values( root_config: &Config, config_path: std::path::PathBuf, - ) -> Result, std::io::Error> { + ) -> Option { if config_path.exists() { let mut confirmed = true; if config_path != helix_loader::config_file() { if root_config.editor.security.load_local_config { if root_config.editor.security.confirm_local_config { eprintln!( - "Type yes to continue with loading config: {:#?}", + "Type yes to continue with loading config: {:#?}", config_path ); let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap_or_default(); confirmed = input.contains("yes"); - } + } //else we still presume confirmed = true } else { + // User denies local configs, do not load confirmed = false; } } if confirmed { log::debug!("Load config: {:?}", config_path); - return std::fs::read(config_path).map(|config| toml::from_slice(&config)); + let bytes = std::fs::read(&config_path); + let cfg: Option = match bytes { + Ok(bytes) => { + let cfg = toml::from_slice(&bytes); + match cfg { + Ok(cfg) => Some(cfg), + Err(e) => { + eprintln!("Toml parse error for {:?}: {}", &config_path, e); + Config::halt_and_confirm("loaded"); + None + } + } + } + Err(e) => { + eprintln!("Could not read {:?}: {}", &config_path, e); + Config::halt_and_confirm("loaded"); + None + } + }; + return cfg; + } else { + return None; } } - Err(std::io::Error::new( - std::io::ErrorKind::NotFound, - format!("{:?} not found", config_path.to_str()), - )) + None + } + + fn halt_and_confirm(config_type: &'static str) { + eprintln!("Press to continue with {} config", config_type); + let mut tmp = String::new(); + let _ = std::io::stdin().read_line(&mut tmp); } } diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index 3347bcb59909b..9e0df716e7202 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -115,9 +115,14 @@ FLAGS: setup_logging(logpath, args.verbosity).context("failed to initialize logging")?; + let config_dir = helix_loader::config_dir(); + if !config_dir.exists() { + std::fs::create_dir_all(&config_dir).ok(); + } + helix_loader::initialize_config_file(args.config_file.clone()); - let config = Config::load_merged_config().unwrap_or_default(); + let config: Config = Config::load_merged_config(); // TODO: use the thread local executor to spawn the application task separately from the work pool let mut app = Application::new(args, config).context("unable to create new application")?;