nix_editor/
parse.rs

1use std::{collections::HashMap, fmt::Write};
2
3use rnix::{self, SyntaxKind, SyntaxNode};
4
5use crate::read::ReadError;
6
7pub fn findattr(configbase: &SyntaxNode, name: &str) -> Option<SyntaxNode> {
8    let mut childvec: Vec<(String, String)> = Vec::new();
9    for child in configbase.children() {
10        if child.kind() == SyntaxKind::NODE_ATTRPATH_VALUE {
11            let qkey = name
12                .split('.')
13                .map(|s| s.to_string())
14                .collect::<Vec<String>>();
15            // Now we have to read all the indent values from the key
16            for subchild in child.children() {
17                if subchild.kind() == SyntaxKind::NODE_ATTRPATH {
18                    // We have a key, now we need to check if it's the one we're looking for
19                    let key = getkey(&subchild);
20                    if qkey == key {
21                        if child
22                            .children()
23                            .any(|x| x.kind() == SyntaxKind::NODE_ATTR_SET)
24                        {
25                            if let Some(x) = child.children().last() {
26                                if x.kind() == SyntaxKind::NODE_ATTR_SET {
27                                    for n in x.children() {
28                                        let i = n.children().count();
29                                        if let (Some(k), Some(v)) =
30                                            (n.children().nth(i - 2), n.last_child())
31                                        {
32                                            let f = n.to_string().find(&k.to_string()).unwrap()
33                                                + k.to_string().len();
34                                            childvec.push((
35                                                n.to_string()[0..f].to_string(),
36                                                v.to_string(),
37                                            ));
38                                        }
39                                    }
40                                }
41                            }
42                        } else {
43                            return Some(child);
44                        }
45                    } else if qkey.len() > key.len() {
46                        // We have a subkey, so we need to recurse
47                        if key == qkey[0..key.len()] {
48                            // We have a subkey, so we need to recurse
49                            let subkey = &qkey[key.len()..].join(".").to_string();
50                            if let Some(newbase) = getcfgbase(&child) {
51                                if let Some(subattr) = findattr(&newbase, subkey) {
52                                    return Some(subattr);
53                                }
54                            }
55                        }
56                    } else if qkey.len() < key.len() && qkey == key[0..qkey.len()] {
57                        if let Some(x) = child.last_child() {
58                            childvec.push((key[qkey.len()..].join("."), x.to_string()));
59                        }
60                    }
61                }
62            }
63        }
64    }
65    if childvec.is_empty() {
66        None
67    } else {
68        let s;
69        if childvec.len() == 1 {
70            s = format!("{{{} = {{ {} = {}; }}; }}", name, childvec[0].0, childvec[0].1);
71        } else {
72            let mut list = String::new();
73            for (k, v) in childvec.iter() {
74                let _ = writeln!(list, "  {} = {};", k, v);
75            }
76            list = list.strip_suffix('\n').unwrap_or(&list).to_string();
77            s = format!("{{ {} = {{\n{}\n}}; }}", name, list);
78        }
79        let ast = rnix::Root::parse(&s);
80        if let Some(x) = ast.syntax().children().next() {
81            if x.kind() == SyntaxKind::NODE_ATTR_SET {
82                if let Some(y) = x.children().next() {
83                    if y.kind() == SyntaxKind::NODE_ATTRPATH_VALUE {
84                        return Some(y);
85                    }
86                }
87            }
88        }
89        None
90    }
91}
92
93pub fn get_collection(f: String) -> Result<HashMap<String, String>, ReadError> {
94    let mut map = HashMap::new();
95    let ast = rnix::Root::parse(&f);
96    let configbase = match getcfgbase(&ast.syntax()) {
97        Some(x) => x,
98        None => {
99            return Err(ReadError::ParseError);
100        }
101    };
102    collectattrs(&configbase, &mut map);
103    Ok(map)
104}
105
106pub fn collectattrs(configbase: &SyntaxNode, map: &mut HashMap<String, String>)
107{
108    for child in configbase.children() {
109        if child.kind() == SyntaxKind::NODE_ATTRPATH_VALUE {
110            let children = child.children().collect::<Vec<SyntaxNode>>();
111            let nodekey = children.get(0).unwrap();
112            let value = children.get(1).unwrap();
113            if nodekey.kind() == SyntaxKind::NODE_ATTRPATH {
114                if value.kind() == SyntaxKind::NODE_ATTR_SET {
115                    let mut childmap = HashMap::new();
116                    collectattrs(value, &mut childmap);
117                    for (nk, v) in &childmap {
118                        map.insert(format!("{}.{}", nodekey, nk), v.clone());
119                    }
120                } else {
121                    map.insert(nodekey.to_string(), value.to_string());
122                }
123            }
124        }
125    }
126}
127
128pub fn getkey(node: &SyntaxNode) -> Vec<String> {
129    let mut key = vec![];
130    for child in node.children() {
131        if child.kind() == SyntaxKind::NODE_IDENT || child.kind() == SyntaxKind::NODE_STRING {
132            key.push(child.text().to_string());
133        }
134    }
135    key
136}
137
138pub fn getcfgbase(node: &SyntaxNode) -> Option<SyntaxNode> {
139    // First check if we're in a set
140    if node.kind() == SyntaxKind::NODE_ATTR_SET {
141        return Some(node.clone());
142    }
143    // Next check if any of our children the set
144    for child in node.children() {
145        if child.kind() == SyntaxKind::NODE_ATTR_SET {
146            return Some(child);
147        }
148    }
149    for child in node.children() {
150        if let Some(x) = getcfgbase(&child) {
151            return Some(x);
152        }
153    }
154    None
155}