keymap_context.rs

  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}