use serde::Deserialize;
const DEFAULT_INDENT_WIDTH: usize = 2;
const DEFAULT_TAB_WIDTH: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
pub enum IndentGuideStyle {
#[serde(rename = "line")]
Line,
#[serde(rename = "p10k")]
P10k,
}
#[derive(Debug, Default, Clone, Deserialize)]
pub struct EditorToml {
pub indent_width: Option<usize>,
pub tab_width: Option<usize>,
pub use_tabs: Option<bool>,
pub show_whitespace: Option<bool>,
pub format_on_save: Option<bool>,
pub indent_guides: Option<bool>,
pub indent_guides_skip_levels: Option<usize>,
pub indent_guide_style: Option<IndentGuideStyle>,
pub indent_animation: Option<bool>,
pub indent_animation_ms: Option<u64>,
pub compact_folders: Option<bool>,
}
#[derive(Debug, Clone, Copy)]
pub struct EditorConfig {
pub indent_width: usize,
pub tab_width: usize,
pub use_tabs: bool,
pub show_whitespace: bool,
pub format_on_save: bool,
pub indent_guides: bool,
pub indent_guides_skip_levels: usize,
pub indent_guide_style: IndentGuideStyle,
pub indent_animation: bool,
pub indent_animation_ms: u64,
pub compact_folders: bool,
}
impl Default for EditorConfig {
fn default() -> Self {
Self {
indent_width: DEFAULT_INDENT_WIDTH,
tab_width: DEFAULT_TAB_WIDTH,
use_tabs: false,
show_whitespace: false,
format_on_save: true,
indent_guides: true,
indent_guides_skip_levels: 0,
indent_guide_style: IndentGuideStyle::Line,
indent_animation: false,
indent_animation_ms: 100,
compact_folders: true,
}
}
}
impl EditorConfig {
pub fn overlay(self, user: &EditorToml) -> Self {
Self {
indent_width: user.indent_width.unwrap_or(self.indent_width),
tab_width: user.tab_width.unwrap_or(self.tab_width),
use_tabs: user.use_tabs.unwrap_or(self.use_tabs),
show_whitespace: user.show_whitespace.unwrap_or(self.show_whitespace),
format_on_save: user.format_on_save.unwrap_or(self.format_on_save),
indent_guides: user.indent_guides.unwrap_or(self.indent_guides),
indent_guides_skip_levels: user
.indent_guides_skip_levels
.unwrap_or(self.indent_guides_skip_levels),
indent_guide_style: user.indent_guide_style.unwrap_or(self.indent_guide_style),
indent_animation: user.indent_animation.unwrap_or(self.indent_animation),
indent_animation_ms: user.indent_animation_ms.unwrap_or(self.indent_animation_ms),
compact_folders: user.compact_folders.unwrap_or(self.compact_folders),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_when_user_omits_fields() {
let eff = EditorConfig::default().overlay(&EditorToml::default());
assert_eq!(eff.indent_width, 2);
assert_eq!(eff.tab_width, 4);
}
#[test]
fn overlay_replaces_only_provided_fields() {
let base = EditorConfig {
indent_width: 4,
tab_width: 4,
use_tabs: false,
show_whitespace: false,
format_on_save: true,
indent_guides: true,
indent_guides_skip_levels: 0,
indent_guide_style: IndentGuideStyle::Line,
indent_animation: false,
indent_animation_ms: 150,
compact_folders: true,
};
let eff = base.overlay(&EditorToml {
tab_width: Some(8),
..Default::default()
});
assert_eq!(eff.indent_width, 4);
assert_eq!(eff.tab_width, 8);
}
}