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,
}