1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
use std::{fmt, num::NonZeroU8}; pub enum ParseConfigError { NotFound, InvalidValue, } macro_rules! config_values { ($($name:ident: $type:ty = $default:expr,)*) => { pub const CONFIG_NAMES: &[&str] = &[$(stringify!($name),)*]; pub struct Config { $(pub $name: $type,)* } impl Config { pub fn parse_config(&mut self, key: &str, value: &str) -> Result<(), ParseConfigError> { match key { $(stringify!($name) => match value.parse() { Ok(value) => self.$name = value, Err(_) => return Err(ParseConfigError::InvalidValue), },)* _ => return Err(ParseConfigError::NotFound), } Ok(()) } pub fn display_config(&self, key: &str) -> Option<DisplayConfig> { match key { $(stringify!($name) => Some(DisplayConfig { config: self, writter: |c, f| fmt::Display::fmt(&c.$name, f), }),)* _ => None, } } } impl Default for Config { fn default() -> Self { Self { $($name: $default,)* } } } pub struct DisplayConfig<'a> { config: &'a Config, writter: fn(&Config, &mut fmt::Formatter) -> fmt::Result } impl<'a> fmt::Display for DisplayConfig<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (self.writter)(self.config, f) } } } } config_values! { tab_size: NonZeroU8 = NonZeroU8::new(4).unwrap(), indent_with_tabs: bool = true, visual_empty: u8 = b'~', visual_space: u8 = b'.', visual_tab_first: u8 = b'|', visual_tab_repeat: u8 = b' ', completion_min_len: u8 = 3, picker_max_height: u8 = 8, }