1use anyhow::anyhow;
2
3use collections::{HashMap, HashSet};
4use tree_sitter::{Language, Node, Parser};
5
6extern "C" {
7 fn tree_sitter_context_predicate() -> Language;
8}
9
10#[derive(Clone, Debug, Default, Eq, PartialEq)]
11pub struct KeymapContext {
12 pub set: HashSet<String>,
13 pub map: HashMap<String, String>,
14}
15
16impl KeymapContext {
17 pub fn extend(&mut self, other: &Self) {
18 for v in &other.set {
19 self.set.insert(v.clone());
20 }
21 for (k, v) in &other.map {
22 self.map.insert(k.clone(), v.clone());
23 }
24 }
25}
26
27#[derive(Debug, Eq, PartialEq)]
28pub enum KeymapContextPredicate {
29 Identifier(String),
30 Equal(String, String),
31 NotEqual(String, String),
32 Not(Box<KeymapContextPredicate>),
33 And(Box<KeymapContextPredicate>, Box<KeymapContextPredicate>),
34 Or(Box<KeymapContextPredicate>, Box<KeymapContextPredicate>),
35}
36
37impl KeymapContextPredicate {
38 pub fn parse(source: &str) -> anyhow::Result<Self> {
39 let mut parser = Parser::new();
40 let language = unsafe { tree_sitter_context_predicate() };
41 parser.set_language(language).unwrap();
42 let source = source.as_bytes();
43 let tree = parser.parse(source, None).unwrap();
44 Self::from_node(tree.root_node(), source)
45 }
46
47 fn from_node(node: Node, source: &[u8]) -> anyhow::Result<Self> {
48 let parse_error = "error parsing context predicate";
49 let kind = node.kind();
50
51 match kind {
52 "source" => Self::from_node(node.child(0).ok_or_else(|| anyhow!(parse_error))?, source),
53 "identifier" => Ok(Self::Identifier(node.utf8_text(source)?.into())),
54 "not" => {
55 let child = Self::from_node(
56 node.child_by_field_name("expression")
57 .ok_or_else(|| anyhow!(parse_error))?,
58 source,
59 )?;
60 Ok(Self::Not(Box::new(child)))
61 }
62 "and" | "or" => {
63 let left = Box::new(Self::from_node(
64 node.child_by_field_name("left")
65 .ok_or_else(|| anyhow!(parse_error))?,
66 source,
67 )?);
68 let right = Box::new(Self::from_node(
69 node.child_by_field_name("right")
70 .ok_or_else(|| anyhow!(parse_error))?,
71 source,
72 )?);
73 if kind == "and" {
74 Ok(Self::And(left, right))
75 } else {
76 Ok(Self::Or(left, right))
77 }
78 }
79 "equal" | "not_equal" => {
80 let left = node
81 .child_by_field_name("left")
82 .ok_or_else(|| anyhow!(parse_error))?
83 .utf8_text(source)?
84 .into();
85 let right = node
86 .child_by_field_name("right")
87 .ok_or_else(|| anyhow!(parse_error))?
88 .utf8_text(source)?
89 .into();
90 if kind == "equal" {
91 Ok(Self::Equal(left, right))
92 } else {
93 Ok(Self::NotEqual(left, right))
94 }
95 }
96 "parenthesized" => Self::from_node(
97 node.child_by_field_name("expression")
98 .ok_or_else(|| anyhow!(parse_error))?,
99 source,
100 ),
101 _ => Err(anyhow!(parse_error)),
102 }
103 }
104
105 pub fn eval(&self, context: &KeymapContext) -> bool {
106 match self {
107 Self::Identifier(name) => context.set.contains(name.as_str()),
108 Self::Equal(left, right) => context
109 .map
110 .get(left)
111 .map(|value| value == right)
112 .unwrap_or(false),
113 Self::NotEqual(left, right) => context
114 .map
115 .get(left)
116 .map(|value| value != right)
117 .unwrap_or(true),
118 Self::Not(pred) => !pred.eval(context),
119 Self::And(left, right) => left.eval(context) && right.eval(context),
120 Self::Or(left, right) => left.eval(context) || right.eval(context),
121 }
122 }
123}