Skip to main content

just_lsp/
setting.rs

1use super::*;
2
3#[derive(Debug, PartialEq)]
4pub struct Setting {
5  pub kind: SettingKind,
6  pub name: TextNode,
7  pub range: lsp::Range,
8}
9
10impl Setting {
11  #[must_use]
12  pub fn from_node(node: &Node, document: &Document) -> Option<Self> {
13    let range = node.get_range(document);
14
15    let name_node = node.child(1)?;
16
17    let name = TextNode {
18      value: document.get_node_text(&name_node),
19      range: name_node.get_range(document),
20    };
21
22    let mut cursor = node.walk();
23
24    let right_children = node
25      .children_by_field_name("right", &mut cursor)
26      .collect::<Vec<_>>();
27
28    let has_bracket = right_children.iter().any(|child| child.kind() == "[");
29
30    let boolean_child = right_children
31      .iter()
32      .find(|child| child.kind() == "boolean");
33
34    let string_child =
35      right_children.iter().find(|child| child.kind() == "string");
36
37    let expression_child = right_children
38      .iter()
39      .find(|child| child.kind() == "expression");
40
41    let kind = if has_bracket {
42      SettingKind::Array
43    } else if let Some(boolean) = boolean_child {
44      SettingKind::Boolean(document.get_node_text(boolean) == "true")
45    } else if string_child.is_some() || expression_child.is_some() {
46      SettingKind::String
47    } else if right_children.is_empty() {
48      SettingKind::Boolean(true)
49    } else {
50      return None;
51    };
52
53    Some(Setting { kind, name, range })
54  }
55}
56
57#[cfg(test)]
58mod tests {
59  use {super::*, indoc::indoc, pretty_assertions::assert_eq};
60
61  #[test]
62  fn parse_boolean_with_value() {
63    assert_eq!(
64      Document::from("set foo := true\n").settings(),
65      vec![Setting {
66        name: TextNode {
67          value: "foo".into(),
68          range: lsp::Range::at(0, 4, 0, 7),
69        },
70        kind: SettingKind::Boolean(true),
71        range: lsp::Range::at(0, 0, 1, 0),
72      }],
73    );
74  }
75
76  #[test]
77  fn parse_boolean_false() {
78    assert_eq!(
79      Document::from("set foo := false\n").settings(),
80      vec![Setting {
81        name: TextNode {
82          value: "foo".into(),
83          range: lsp::Range::at(0, 4, 0, 7),
84        },
85        kind: SettingKind::Boolean(false),
86        range: lsp::Range::at(0, 0, 1, 0),
87      }],
88    );
89  }
90
91  #[test]
92  fn parse_boolean_without_value() {
93    assert_eq!(
94      Document::from("set export\n").settings(),
95      vec![Setting {
96        name: TextNode {
97          value: "export".into(),
98          range: lsp::Range::at(0, 4, 0, 10),
99        },
100        kind: SettingKind::Boolean(true),
101        range: lsp::Range::at(0, 0, 1, 0),
102      }],
103    );
104  }
105
106  #[test]
107  fn parse_array() {
108    assert_eq!(
109      Document::from("set shell := [\"zsh\", \"-cu\"]\n").settings(),
110      vec![Setting {
111        name: TextNode {
112          value: "shell".into(),
113          range: lsp::Range::at(0, 4, 0, 9),
114        },
115        kind: SettingKind::Array,
116        range: lsp::Range::at(0, 0, 1, 0),
117      }],
118    );
119  }
120
121  #[test]
122  fn parse_string() {
123    assert_eq!(
124      Document::from("set foo := \"bar\"\n").settings(),
125      vec![Setting {
126        name: TextNode {
127          value: "foo".into(),
128          range: lsp::Range::at(0, 4, 0, 7),
129        },
130        kind: SettingKind::String,
131        range: lsp::Range::at(0, 0, 1, 0),
132      }],
133    );
134  }
135
136  #[test]
137  fn parse_string_containing_walrus() {
138    assert_eq!(
139      Document::from("set foo := \"bar := baz\"\n").settings(),
140      vec![Setting {
141        name: TextNode {
142          value: "foo".into(),
143          range: lsp::Range::at(0, 4, 0, 7),
144        },
145        kind: SettingKind::String,
146        range: lsp::Range::at(0, 0, 1, 0),
147      }],
148    );
149  }
150
151  #[test]
152  fn parse_expression() {
153    assert_eq!(
154      Document::from("set foo := \"bar\" / baz\n").settings(),
155      vec![Setting {
156        name: TextNode {
157          value: "foo".into(),
158          range: lsp::Range::at(0, 4, 0, 7),
159        },
160        kind: SettingKind::String,
161        range: lsp::Range::at(0, 0, 1, 0),
162      }],
163    );
164  }
165
166  #[test]
167  fn parse_multiple_settings() {
168    assert_eq!(
169      Document::from(indoc! {"
170        set foo := true
171        set bar := \"baz\"
172        set shell := [\"zsh\", \"-cu\"]
173      "})
174      .settings(),
175      vec![
176        Setting {
177          name: TextNode {
178            value: "foo".into(),
179            range: lsp::Range::at(0, 4, 0, 7),
180          },
181          kind: SettingKind::Boolean(true),
182          range: lsp::Range::at(0, 0, 1, 0),
183        },
184        Setting {
185          name: TextNode {
186            value: "bar".into(),
187            range: lsp::Range::at(1, 4, 1, 7),
188          },
189          kind: SettingKind::String,
190          range: lsp::Range::at(1, 0, 2, 0),
191        },
192        Setting {
193          name: TextNode {
194            value: "shell".into(),
195            range: lsp::Range::at(2, 4, 2, 9),
196          },
197          kind: SettingKind::Array,
198          range: lsp::Range::at(2, 0, 3, 0),
199        },
200      ],
201    );
202  }
203}