aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/config.rs')
-rw-r--r--helix-term/src/config.rs136
1 files changed, 108 insertions, 28 deletions
diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs
index 4407a882..9776ef7a 100644
--- a/helix-term/src/config.rs
+++ b/helix-term/src/config.rs
@@ -1,27 +1,34 @@
-use crate::keymap::{default::default, merge_keys, Keymap};
+use crate::keymap;
+use crate::keymap::{merge_keys, Keymap};
+use helix_loader::merge_toml_values;
use helix_view::document::Mode;
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt::Display;
+use std::fs;
use std::io::Error as IOError;
-use std::path::PathBuf;
use toml::de::Error as TomlError;
-#[derive(Debug, Clone, PartialEq, Deserialize)]
-#[serde(deny_unknown_fields)]
+#[derive(Debug, Clone, PartialEq)]
pub struct Config {
pub theme: Option<String>,
- #[serde(default = "default")]
pub keys: HashMap<Mode, Keymap>,
- #[serde(default)]
pub editor: helix_view::editor::Config,
}
+#[derive(Debug, Clone, PartialEq, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct ConfigRaw {
+ pub theme: Option<String>,
+ pub keys: Option<HashMap<Mode, Keymap>>,
+ pub editor: Option<toml::Value>,
+}
+
impl Default for Config {
fn default() -> Config {
Config {
theme: None,
- keys: default(),
+ keys: keymap::default(),
editor: helix_view::editor::Config::default(),
}
}
@@ -33,6 +40,12 @@ pub enum ConfigLoadError {
Error(IOError),
}
+impl Default for ConfigLoadError {
+ fn default() -> Self {
+ ConfigLoadError::Error(IOError::new(std::io::ErrorKind::NotFound, "place holder"))
+ }
+}
+
impl Display for ConfigLoadError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@@ -43,17 +56,72 @@ impl Display for ConfigLoadError {
}
impl Config {
- pub fn load(config_path: PathBuf) -> Result<Config, ConfigLoadError> {
- match std::fs::read_to_string(config_path) {
- Ok(config) => toml::from_str(&config)
- .map(merge_keys)
- .map_err(ConfigLoadError::BadConfig),
- Err(err) => Err(ConfigLoadError::Error(err)),
- }
+ pub fn load(
+ global: Result<String, ConfigLoadError>,
+ local: Result<String, ConfigLoadError>,
+ ) -> Result<Config, ConfigLoadError> {
+ let global_config: Result<ConfigRaw, ConfigLoadError> =
+ global.and_then(|file| toml::from_str(&file).map_err(ConfigLoadError::BadConfig));
+ let local_config: Result<ConfigRaw, ConfigLoadError> =
+ local.and_then(|file| toml::from_str(&file).map_err(ConfigLoadError::BadConfig));
+ let res = match (global_config, local_config) {
+ (Ok(global), Ok(local)) => {
+ let mut keys = keymap::default();
+ if let Some(global_keys) = global.keys {
+ merge_keys(&mut keys, global_keys)
+ }
+ if let Some(local_keys) = local.keys {
+ merge_keys(&mut keys, local_keys)
+ }
+
+ let editor = match (global.editor, local.editor) {
+ (None, None) => helix_view::editor::Config::default(),
+ (None, Some(val)) | (Some(val), None) => {
+ val.try_into().map_err(ConfigLoadError::BadConfig)?
+ }
+ (Some(global), Some(local)) => merge_toml_values(global, local, 3)
+ .try_into()
+ .map_err(ConfigLoadError::BadConfig)?,
+ };
+
+ Config {
+ theme: local.theme.or(global.theme),
+ keys,
+ editor,
+ }
+ }
+ // if any configs are invalid return that first
+ (_, Err(ConfigLoadError::BadConfig(err)))
+ | (Err(ConfigLoadError::BadConfig(err)), _) => {
+ return Err(ConfigLoadError::BadConfig(err))
+ }
+ (Ok(config), Err(_)) | (Err(_), Ok(config)) => {
+ let mut keys = keymap::default();
+ if let Some(keymap) = config.keys {
+ merge_keys(&mut keys, keymap);
+ }
+ Config {
+ theme: config.theme,
+ keys,
+ editor: config.editor.map_or_else(
+ || Ok(helix_view::editor::Config::default()),
+ |val| val.try_into().map_err(ConfigLoadError::BadConfig),
+ )?,
+ }
+ }
+ // these are just two io errors return the one for the global config
+ (Err(err), Err(_)) => return Err(err),
+ };
+
+ Ok(res)
}
pub fn load_default() -> Result<Config, ConfigLoadError> {
- Config::load(helix_loader::config_file())
+ let global_config =
+ fs::read_to_string(helix_loader::config_file()).map_err(ConfigLoadError::Error);
+ let local_config = fs::read_to_string(helix_loader::workspace_config_file())
+ .map_err(ConfigLoadError::Error);
+ Config::load(global_config, local_config)
}
}
@@ -61,6 +129,12 @@ impl Config {
mod tests {
use super::*;
+ impl Config {
+ fn load_test(config: &str) -> Config {
+ Config::load(Ok(config.to_owned()), Err(ConfigLoadError::default())).unwrap()
+ }
+ }
+
#[test]
fn parsing_keymaps_config_file() {
use crate::keymap;
@@ -77,18 +151,24 @@ mod tests {
A-F12 = "move_next_word_end"
"#;
+ let mut keys = keymap::default();
+ merge_keys(
+ &mut keys,
+ hashmap! {
+ Mode::Insert => Keymap::new(keymap!({ "Insert mode"
+ "y" => move_line_down,
+ "S-C-a" => delete_selection,
+ })),
+ Mode::Normal => Keymap::new(keymap!({ "Normal mode"
+ "A-F12" => move_next_word_end,
+ })),
+ },
+ );
+
assert_eq!(
- toml::from_str::<Config>(sample_keymaps).unwrap(),
+ Config::load_test(sample_keymaps),
Config {
- keys: hashmap! {
- Mode::Insert => Keymap::new(keymap!({ "Insert mode"
- "y" => move_line_down,
- "S-C-a" => delete_selection,
- })),
- Mode::Normal => Keymap::new(keymap!({ "Normal mode"
- "A-F12" => move_next_word_end,
- })),
- },
+ keys,
..Default::default()
}
);
@@ -97,11 +177,11 @@ mod tests {
#[test]
fn keys_resolve_to_correct_defaults() {
// From serde default
- let default_keys = toml::from_str::<Config>("").unwrap().keys;
- assert_eq!(default_keys, default());
+ let default_keys = Config::load_test("").keys;
+ assert_eq!(default_keys, keymap::default());
// From the Default trait
let default_keys = Config::default().keys;
- assert_eq!(default_keys, default());
+ assert_eq!(default_keys, keymap::default());
}
}