1use ini::Ini;
2use std::collections::HashMap;
3use std::fs;
4use std::str::FromStr;
5
6pub struct EditorConfig {
7 pub config: HashMap<String, HashMap<String, String>>,
8}
9
10impl EditorConfig {
11 pub fn from_file(file_path: &str) -> Result<Self, String> {
12 let contents: String = fs::read_to_string(file_path).map_err(|e| e.to_string())?;
13 EditorConfig::from_str(&contents)
14 }
15 pub fn get_property(&self, section: &str, property: &str) -> Option<&String> {
16 self.config
17 .get(section)
18 .and_then(|props| props.get(property))
19 .and_then(|value| validate_property(property, value))
20 }
21}
22
23fn validate_property<'a>(property: &str, value: &'a String) -> Option<&'a String> {
26 match property {
27 "indent_style" => match value.as_str() {
28 "tab" | "space" => Some(value),
29 _ => None,
30 },
31 "indent_size" => match value.as_str() {
32 "tab" => Some(value),
33 _ => value.parse::<u32>().ok().map(|_| value),
34 },
35 "tab_width" => value.parse::<u32>().ok().map(|_| value),
36 "end_of_line" => match value.as_str() {
37 "lf" | "cr" | "crlf" => Some(value),
38 _ => None,
39 },
40 "charset" => match value.as_str() {
41 "latin1" | "utf-8" | "utf-8-bom" | "utf-16be" | "utf-16le" => Some(value),
42 _ => None,
43 },
44 "trim_trailing_whitespace" | "insert_final_newline" | "root" => {
45 value.parse::<bool>().ok().map(|_| value)
46 }
47 "max_line_length" => match value.as_str() {
48 "off" => Some(value),
49 _ => value.parse::<u32>().ok().map(|_| value),
50 },
51 _ => Some(value),
52 }
53}
54
55impl FromStr for EditorConfig {
56 type Err = String;
57
58 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 let parsed = Ini::load_from_str(s).map_err(|e| e.to_string())?;
60 let mut config = HashMap::new();
61 for (section, properties) in parsed.iter() {
62 let section_name = section.as_ref().map_or("*".to_string(), |s| s.to_string());
63 let section_props = properties
64 .iter()
65 .map(|(key, value)| (key.to_string(), value.to_string()))
66 .collect();
67 config.insert(section_name, section_props);
68 }
69
70 Ok(EditorConfig { config })
71 }
72}