* fix(layouts): point to layout documentation * adjust shell completions * comment about clear-defaults in the config
672 lines
24 KiB
Rust
672 lines
24 KiB
Rust
use crate::data::Palette;
|
|
use miette::{Diagnostic, LabeledSpan, NamedSource, SourceCode};
|
|
use std::fs::File;
|
|
use std::io::{self, Read};
|
|
use std::path::PathBuf;
|
|
use thiserror::Error;
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
use super::keybinds::Keybinds;
|
|
use super::options::Options;
|
|
use super::plugins::{PluginsConfig, PluginsConfigError};
|
|
use super::theme::{Themes, UiConfig};
|
|
use crate::cli::{CliArgs, Command};
|
|
use crate::envs::EnvironmentVariables;
|
|
use crate::setup;
|
|
|
|
const DEFAULT_CONFIG_FILE_NAME: &str = "config.kdl";
|
|
|
|
type ConfigResult = Result<Config, ConfigError>;
|
|
|
|
/// Main configuration.
|
|
#[derive(Debug, Clone, PartialEq, Default)]
|
|
pub struct Config {
|
|
pub keybinds: Keybinds,
|
|
pub options: Options,
|
|
pub themes: Themes,
|
|
pub plugins: PluginsConfig,
|
|
pub ui: UiConfig,
|
|
pub env: EnvironmentVariables,
|
|
}
|
|
|
|
#[derive(Error, Debug)]
|
|
pub struct KdlError {
|
|
pub error_message: String,
|
|
pub src: Option<NamedSource>,
|
|
pub offset: Option<usize>,
|
|
pub len: Option<usize>,
|
|
pub help_message: Option<String>,
|
|
}
|
|
|
|
impl KdlError {
|
|
pub fn add_src(mut self, src_name: String, src_input: String) -> Self {
|
|
self.src = Some(NamedSource::new(src_name, src_input));
|
|
self
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for KdlError {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
write!(f, "Failed to parse Zellij configuration")
|
|
}
|
|
}
|
|
use std::fmt::Display;
|
|
|
|
impl Diagnostic for KdlError {
|
|
fn source_code(&self) -> Option<&dyn SourceCode> {
|
|
match self.src.as_ref() {
|
|
Some(src) => Some(src),
|
|
None => None,
|
|
}
|
|
}
|
|
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
|
match &self.help_message {
|
|
Some(help_message) => Some(Box::new(help_message)),
|
|
None => Some(Box::new(format!("For more information, please see our configuration guide: https://zellij.dev/documentation/configuration.html")))
|
|
}
|
|
}
|
|
fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
|
|
if let (Some(offset), Some(len)) = (self.offset, self.len) {
|
|
let label = LabeledSpan::new(Some(self.error_message.clone()), offset, len);
|
|
Some(Box::new(std::iter::once(label)))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Error, Debug, Diagnostic)]
|
|
pub enum ConfigError {
|
|
// Deserialization error
|
|
#[error("Deserialization error: {0}")]
|
|
KdlDeserializationError(#[from] kdl::KdlError),
|
|
#[error("KdlDeserialization error: {0}")]
|
|
KdlError(KdlError), // TODO: consolidate these
|
|
// Io error
|
|
#[error("IoError: {0}")]
|
|
Io(#[from] io::Error),
|
|
#[error("Config error: {0}")]
|
|
Std(#[from] Box<dyn std::error::Error>),
|
|
// Io error with path context
|
|
#[error("IoError: {0}, File: {1}")]
|
|
IoPath(io::Error, PathBuf),
|
|
// Internal Deserialization Error
|
|
#[error("FromUtf8Error: {0}")]
|
|
FromUtf8(#[from] std::string::FromUtf8Error),
|
|
// Plugins have a semantic error, usually trying to parse two of the same tag
|
|
#[error("PluginsError: {0}")]
|
|
PluginsError(#[from] PluginsConfigError),
|
|
#[error("{0}")]
|
|
ConversionError(#[from] ConversionError),
|
|
}
|
|
|
|
impl ConfigError {
|
|
pub fn new_kdl_error(error_message: String, offset: usize, len: usize) -> Self {
|
|
ConfigError::KdlError(KdlError {
|
|
error_message,
|
|
src: None,
|
|
offset: Some(offset),
|
|
len: Some(len),
|
|
help_message: None,
|
|
})
|
|
}
|
|
pub fn new_layout_kdl_error(error_message: String, offset: usize, len: usize) -> Self {
|
|
ConfigError::KdlError(KdlError {
|
|
error_message,
|
|
src: None,
|
|
offset: Some(offset),
|
|
len: Some(len),
|
|
help_message: Some(format!("For more information, please see our layout guide: https://zellij.dev/documentation/creating-a-layout.html")),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum ConversionError {
|
|
#[error("{0}")]
|
|
UnknownInputMode(String),
|
|
}
|
|
|
|
impl TryFrom<&CliArgs> for Config {
|
|
type Error = ConfigError;
|
|
|
|
fn try_from(opts: &CliArgs) -> ConfigResult {
|
|
if let Some(ref path) = opts.config {
|
|
let default_config = Config::from_default_assets()?;
|
|
return Config::from_path(path, Some(default_config));
|
|
}
|
|
|
|
if let Some(Command::Setup(ref setup)) = opts.command {
|
|
if setup.clean {
|
|
return Config::from_default_assets();
|
|
}
|
|
}
|
|
|
|
let config_dir = opts
|
|
.config_dir
|
|
.clone()
|
|
.or_else(setup::find_default_config_dir);
|
|
|
|
if let Some(ref config) = config_dir {
|
|
let path = config.join(DEFAULT_CONFIG_FILE_NAME);
|
|
if path.exists() {
|
|
let default_config = Config::from_default_assets()?;
|
|
Config::from_path(&path, Some(default_config))
|
|
} else {
|
|
Config::from_default_assets()
|
|
}
|
|
} else {
|
|
Config::from_default_assets()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Config {
|
|
pub fn theme_config(&self, opts: &Options) -> Option<Palette> {
|
|
match &opts.theme {
|
|
Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette),
|
|
None => self.themes.get_theme("default").map(|theme| theme.palette),
|
|
}
|
|
}
|
|
/// Gets default configuration from assets
|
|
pub fn from_default_assets() -> ConfigResult {
|
|
let cfg = String::from_utf8(setup::DEFAULT_CONFIG.to_vec())?;
|
|
match Self::from_kdl(&cfg, None) {
|
|
Ok(config) => Ok(config),
|
|
Err(ConfigError::KdlError(kdl_error)) => Err(ConfigError::KdlError(
|
|
kdl_error.add_src("Default built-in-configuration".into(), cfg),
|
|
)),
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
pub fn from_path(path: &PathBuf, default_config: Option<Config>) -> ConfigResult {
|
|
match File::open(path) {
|
|
Ok(mut file) => {
|
|
let mut kdl_config = String::new();
|
|
file.read_to_string(&mut kdl_config)
|
|
.map_err(|e| ConfigError::IoPath(e, path.to_path_buf()))?;
|
|
match Config::from_kdl(&kdl_config, default_config) {
|
|
Ok(config) => Ok(config),
|
|
Err(ConfigError::KdlDeserializationError(kdl_error)) => {
|
|
let error_message = match kdl_error.kind {
|
|
kdl::KdlErrorKind::Context("valid node terminator") => {
|
|
format!("Failed to deserialize KDL node. \nPossible reasons:\n{}\n{}\n{}\n{}",
|
|
"- Missing `;` after a node name, eg. { node; another_node; }",
|
|
"- Missing quotations (\") around an argument node eg. { first_node \"argument_node\"; }",
|
|
"- Missing an equal sign (=) between node arguments on a title line. eg. argument=\"value\"",
|
|
"- Found an extraneous equal sign (=) between node child arguments and their values. eg. { argument=\"value\" }")
|
|
},
|
|
_ => {
|
|
String::from(kdl_error.help.unwrap_or("Kdl Deserialization Error"))
|
|
},
|
|
};
|
|
let kdl_error = KdlError {
|
|
error_message,
|
|
src: Some(NamedSource::new(
|
|
path.as_path().as_os_str().to_string_lossy(),
|
|
kdl_config,
|
|
)),
|
|
offset: Some(kdl_error.span.offset()),
|
|
len: Some(kdl_error.span.len()),
|
|
help_message: None,
|
|
};
|
|
Err(ConfigError::KdlError(kdl_error))
|
|
},
|
|
Err(ConfigError::KdlError(kdl_error)) => {
|
|
Err(ConfigError::KdlError(kdl_error.add_src(
|
|
path.as_path().as_os_str().to_string_lossy().to_string(),
|
|
kdl_config,
|
|
)))
|
|
},
|
|
Err(e) => Err(e),
|
|
}
|
|
},
|
|
Err(e) => Err(ConfigError::IoPath(e, path.into())),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod config_test {
|
|
use super::*;
|
|
use crate::data::{InputMode, Palette, PaletteColor, PluginTag};
|
|
use crate::input::layout::RunPluginLocation;
|
|
use crate::input::options::{Clipboard, OnForceClose};
|
|
use crate::input::plugins::{PluginConfig, PluginType, PluginsConfig};
|
|
use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig};
|
|
use std::collections::HashMap;
|
|
use std::io::Write;
|
|
use tempfile::tempdir;
|
|
|
|
#[test]
|
|
fn try_from_cli_args_with_config() {
|
|
// makes sure loading a config file with --config tries to load the config
|
|
let arbitrary_config = PathBuf::from("nonexistent.yaml");
|
|
let opts = CliArgs {
|
|
config: Some(arbitrary_config),
|
|
..Default::default()
|
|
};
|
|
println!("OPTS= {:?}", opts);
|
|
let result = Config::try_from(&opts);
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn try_from_cli_args_with_option_clean() {
|
|
// makes sure --clean works... TODO: how can this actually fail now?
|
|
use crate::setup::Setup;
|
|
let opts = CliArgs {
|
|
command: Some(Command::Setup(Setup {
|
|
clean: true,
|
|
..Setup::default()
|
|
})),
|
|
..Default::default()
|
|
};
|
|
let result = Config::try_from(&opts);
|
|
assert!(result.is_ok());
|
|
}
|
|
|
|
#[test]
|
|
fn try_from_cli_args_with_config_dir() {
|
|
let mut opts = CliArgs::default();
|
|
let tmp = tempdir().unwrap();
|
|
File::create(tmp.path().join(DEFAULT_CONFIG_FILE_NAME))
|
|
.unwrap()
|
|
.write_all(b"keybinds: invalid\n")
|
|
.unwrap();
|
|
opts.config_dir = Some(tmp.path().to_path_buf());
|
|
let result = Config::try_from(&opts);
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn try_from_cli_args_with_config_dir_without_config() {
|
|
let mut opts = CliArgs::default();
|
|
let tmp = tempdir().unwrap();
|
|
opts.config_dir = Some(tmp.path().to_path_buf());
|
|
let result = Config::try_from(&opts);
|
|
assert_eq!(result.unwrap(), Config::from_default_assets().unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn try_from_cli_args_default() {
|
|
let opts = CliArgs::default();
|
|
let result = Config::try_from(&opts);
|
|
assert_eq!(result.unwrap(), Config::from_default_assets().unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_options_in_configfile() {
|
|
let config_contents = r#"
|
|
simplified_ui true
|
|
theme "my cool theme"
|
|
default_mode "locked"
|
|
default_shell "/path/to/my/shell"
|
|
default_layout "/path/to/my/layout.kdl"
|
|
layout_dir "/path/to/my/layout-dir"
|
|
theme_dir "/path/to/my/theme-dir"
|
|
mouse_mode false
|
|
pane_frames false
|
|
mirror_session true
|
|
on_force_close "quit"
|
|
scroll_buffer_size 100000
|
|
copy_command "/path/to/my/copy-command"
|
|
copy_clipboard "primary"
|
|
copy_on_select false
|
|
scrollback_editor "/path/to/my/scrollback-editor"
|
|
session_name "my awesome session"
|
|
attach_to_session true
|
|
"#;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
assert_eq!(
|
|
config.options.simplified_ui,
|
|
Some(true),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.theme,
|
|
Some(String::from("my cool theme")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.default_mode,
|
|
Some(InputMode::Locked),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.default_shell,
|
|
Some(PathBuf::from("/path/to/my/shell")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.default_layout,
|
|
Some(PathBuf::from("/path/to/my/layout.kdl")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.layout_dir,
|
|
Some(PathBuf::from("/path/to/my/layout-dir")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.theme_dir,
|
|
Some(PathBuf::from("/path/to/my/theme-dir")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.mouse_mode,
|
|
Some(false),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.pane_frames,
|
|
Some(false),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.mirror_session,
|
|
Some(true),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.on_force_close,
|
|
Some(OnForceClose::Quit),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.scroll_buffer_size,
|
|
Some(100000),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.copy_command,
|
|
Some(String::from("/path/to/my/copy-command")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.copy_clipboard,
|
|
Some(Clipboard::Primary),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.copy_on_select,
|
|
Some(false),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.scrollback_editor,
|
|
Some(PathBuf::from("/path/to/my/scrollback-editor")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.session_name,
|
|
Some(String::from("my awesome session")),
|
|
"Option set in config"
|
|
);
|
|
assert_eq!(
|
|
config.options.attach_to_session,
|
|
Some(true),
|
|
"Option set in config"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_themes_in_configfile() {
|
|
let config_contents = r#"
|
|
themes {
|
|
dracula {
|
|
fg 248 248 242
|
|
bg 40 42 54
|
|
red 255 85 85
|
|
green 80 250 123
|
|
yellow 241 250 140
|
|
blue 98 114 164
|
|
magenta 255 121 198
|
|
orange 255 184 108
|
|
cyan 139 233 253
|
|
black 0 0 0
|
|
white 255 255 255
|
|
}
|
|
}
|
|
"#;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
let mut expected_themes = HashMap::new();
|
|
expected_themes.insert(
|
|
"dracula".into(),
|
|
Theme {
|
|
palette: Palette {
|
|
fg: PaletteColor::Rgb((248, 248, 242)),
|
|
bg: PaletteColor::Rgb((40, 42, 54)),
|
|
red: PaletteColor::Rgb((255, 85, 85)),
|
|
green: PaletteColor::Rgb((80, 250, 123)),
|
|
yellow: PaletteColor::Rgb((241, 250, 140)),
|
|
blue: PaletteColor::Rgb((98, 114, 164)),
|
|
magenta: PaletteColor::Rgb((255, 121, 198)),
|
|
orange: PaletteColor::Rgb((255, 184, 108)),
|
|
cyan: PaletteColor::Rgb((139, 233, 253)),
|
|
black: PaletteColor::Rgb((0, 0, 0)),
|
|
white: PaletteColor::Rgb((255, 255, 255)),
|
|
..Default::default()
|
|
},
|
|
},
|
|
);
|
|
let expected_themes = Themes::from_data(expected_themes);
|
|
assert_eq!(config.themes, expected_themes, "Theme defined in config");
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_multiple_themes_including_hex_themes_in_configfile() {
|
|
let config_contents = r##"
|
|
themes {
|
|
dracula {
|
|
fg 248 248 242
|
|
bg 40 42 54
|
|
red 255 85 85
|
|
green 80 250 123
|
|
yellow 241 250 140
|
|
blue 98 114 164
|
|
magenta 255 121 198
|
|
orange 255 184 108
|
|
cyan 139 233 253
|
|
black 0 0 0
|
|
white 255 255 255
|
|
}
|
|
nord {
|
|
fg "#D8DEE9"
|
|
bg "#2E3440"
|
|
black "#3B4252"
|
|
red "#BF616A"
|
|
green "#A3BE8C"
|
|
yellow "#EBCB8B"
|
|
blue "#81A1C1"
|
|
magenta "#B48EAD"
|
|
cyan "#88C0D0"
|
|
white "#E5E9F0"
|
|
orange "#D08770"
|
|
}
|
|
}
|
|
"##;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
let mut expected_themes = HashMap::new();
|
|
expected_themes.insert(
|
|
"dracula".into(),
|
|
Theme {
|
|
palette: Palette {
|
|
fg: PaletteColor::Rgb((248, 248, 242)),
|
|
bg: PaletteColor::Rgb((40, 42, 54)),
|
|
red: PaletteColor::Rgb((255, 85, 85)),
|
|
green: PaletteColor::Rgb((80, 250, 123)),
|
|
yellow: PaletteColor::Rgb((241, 250, 140)),
|
|
blue: PaletteColor::Rgb((98, 114, 164)),
|
|
magenta: PaletteColor::Rgb((255, 121, 198)),
|
|
orange: PaletteColor::Rgb((255, 184, 108)),
|
|
cyan: PaletteColor::Rgb((139, 233, 253)),
|
|
black: PaletteColor::Rgb((0, 0, 0)),
|
|
white: PaletteColor::Rgb((255, 255, 255)),
|
|
..Default::default()
|
|
},
|
|
},
|
|
);
|
|
expected_themes.insert(
|
|
"nord".into(),
|
|
Theme {
|
|
palette: Palette {
|
|
fg: PaletteColor::Rgb((216, 222, 233)),
|
|
bg: PaletteColor::Rgb((46, 52, 64)),
|
|
black: PaletteColor::Rgb((59, 66, 82)),
|
|
red: PaletteColor::Rgb((191, 97, 106)),
|
|
green: PaletteColor::Rgb((163, 190, 140)),
|
|
yellow: PaletteColor::Rgb((235, 203, 139)),
|
|
blue: PaletteColor::Rgb((129, 161, 193)),
|
|
magenta: PaletteColor::Rgb((180, 142, 173)),
|
|
cyan: PaletteColor::Rgb((136, 192, 208)),
|
|
white: PaletteColor::Rgb((229, 233, 240)),
|
|
orange: PaletteColor::Rgb((208, 135, 112)),
|
|
..Default::default()
|
|
},
|
|
},
|
|
);
|
|
let expected_themes = Themes::from_data(expected_themes);
|
|
assert_eq!(config.themes, expected_themes, "Theme defined in config");
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_eight_bit_themes() {
|
|
let config_contents = r#"
|
|
themes {
|
|
eight_bit_theme {
|
|
fg 248
|
|
bg 40
|
|
red 255
|
|
green 80
|
|
yellow 241
|
|
blue 98
|
|
magenta 255
|
|
orange 255
|
|
cyan 139
|
|
black 1
|
|
white 255
|
|
}
|
|
}
|
|
"#;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
let mut expected_themes = HashMap::new();
|
|
expected_themes.insert(
|
|
"eight_bit_theme".into(),
|
|
Theme {
|
|
palette: Palette {
|
|
fg: PaletteColor::EightBit(248),
|
|
bg: PaletteColor::EightBit(40),
|
|
red: PaletteColor::EightBit(255),
|
|
green: PaletteColor::EightBit(80),
|
|
yellow: PaletteColor::EightBit(241),
|
|
blue: PaletteColor::EightBit(98),
|
|
magenta: PaletteColor::EightBit(255),
|
|
orange: PaletteColor::EightBit(255),
|
|
cyan: PaletteColor::EightBit(139),
|
|
black: PaletteColor::EightBit(1),
|
|
white: PaletteColor::EightBit(255),
|
|
..Default::default()
|
|
},
|
|
},
|
|
);
|
|
let expected_themes = Themes::from_data(expected_themes);
|
|
assert_eq!(config.themes, expected_themes, "Theme defined in config");
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_plugin_configuration_in_configfile() {
|
|
let config_contents = r#"
|
|
plugins {
|
|
tab-bar { path "tab-bar"; }
|
|
status-bar { path "status-bar"; }
|
|
strider {
|
|
path "strider"
|
|
_allow_exec_host_cmd true
|
|
}
|
|
compact-bar { path "compact-bar"; }
|
|
}
|
|
"#;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
let mut expected_plugin_configuration = HashMap::new();
|
|
expected_plugin_configuration.insert(
|
|
PluginTag::new("tab-bar"),
|
|
PluginConfig {
|
|
path: PathBuf::from("tab-bar"),
|
|
run: PluginType::Pane(None),
|
|
location: RunPluginLocation::Zellij(PluginTag::new("tab-bar")),
|
|
_allow_exec_host_cmd: false,
|
|
},
|
|
);
|
|
expected_plugin_configuration.insert(
|
|
PluginTag::new("status-bar"),
|
|
PluginConfig {
|
|
path: PathBuf::from("status-bar"),
|
|
run: PluginType::Pane(None),
|
|
location: RunPluginLocation::Zellij(PluginTag::new("status-bar")),
|
|
_allow_exec_host_cmd: false,
|
|
},
|
|
);
|
|
expected_plugin_configuration.insert(
|
|
PluginTag::new("strider"),
|
|
PluginConfig {
|
|
path: PathBuf::from("strider"),
|
|
run: PluginType::Pane(None),
|
|
location: RunPluginLocation::Zellij(PluginTag::new("strider")),
|
|
_allow_exec_host_cmd: true,
|
|
},
|
|
);
|
|
expected_plugin_configuration.insert(
|
|
PluginTag::new("compact-bar"),
|
|
PluginConfig {
|
|
path: PathBuf::from("compact-bar"),
|
|
run: PluginType::Pane(None),
|
|
location: RunPluginLocation::Zellij(PluginTag::new("compact-bar")),
|
|
_allow_exec_host_cmd: false,
|
|
},
|
|
);
|
|
assert_eq!(
|
|
config.plugins,
|
|
PluginsConfig::from_data(expected_plugin_configuration),
|
|
"Plugins defined in config"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_ui_configuration_in_configfile() {
|
|
let config_contents = r#"
|
|
ui {
|
|
pane_frames {
|
|
rounded_corners true
|
|
}
|
|
}
|
|
"#;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
let expected_ui_config = UiConfig {
|
|
pane_frames: FrameConfig {
|
|
rounded_corners: true,
|
|
},
|
|
};
|
|
assert_eq!(config.ui, expected_ui_config, "Ui config defined in config");
|
|
}
|
|
|
|
#[test]
|
|
fn can_define_env_variables_in_config_file() {
|
|
let config_contents = r#"
|
|
env {
|
|
RUST_BACKTRACE 1
|
|
SOME_OTHER_VAR "foo"
|
|
}
|
|
"#;
|
|
let config = Config::from_kdl(config_contents, None).unwrap();
|
|
let mut expected_env_config = HashMap::new();
|
|
expected_env_config.insert("RUST_BACKTRACE".into(), "1".into());
|
|
expected_env_config.insert("SOME_OTHER_VAR".into(), "foo".into());
|
|
assert_eq!(
|
|
config.env,
|
|
EnvironmentVariables::from_data(expected_env_config),
|
|
"Env variables defined in config"
|
|
);
|
|
}
|
|
}
|