Skip to main content

tldr_cli/commands/remaining/difftastic/
changes.rs

1//! Data types that track the change state for syntax nodes.
2
3use super::{
4    hash::DftHashMap,
5    syntax::{Syntax, SyntaxId},
6};
7
8#[derive(PartialEq, Eq, Clone, Copy)]
9pub enum ChangeKind<'a> {
10    /// This node is shallowly unchanged. For lists, this means that
11    /// the delimiters match, but there may still be some differences
12    /// in the children between LHS and RHS.
13    Unchanged(&'a Syntax<'a>),
14    ReplacedComment(&'a Syntax<'a>, &'a Syntax<'a>),
15    ReplacedString(&'a Syntax<'a>, &'a Syntax<'a>),
16    Novel,
17}
18
19#[derive(Debug, Default)]
20pub struct ChangeMap<'a> {
21    changes: DftHashMap<SyntaxId, ChangeKind<'a>>,
22}
23
24impl<'a> ChangeMap<'a> {
25    pub fn insert(&mut self, node: &'a Syntax<'a>, ck: ChangeKind<'a>) {
26        self.changes.insert(node.id(), ck);
27    }
28
29    pub fn get(&self, node: &Syntax<'a>) -> Option<ChangeKind<'a>> {
30        self.changes.get(&node.id()).copied()
31    }
32}
33
34pub fn insert_deep_unchanged<'a>(
35    node: &'a Syntax<'a>,
36    opposite_node: &'a Syntax<'a>,
37    change_map: &mut ChangeMap<'a>,
38) {
39    change_map.insert(node, ChangeKind::Unchanged(opposite_node));
40
41    match (node, opposite_node) {
42        (
43            Syntax::List {
44                children: node_children,
45                ..
46            },
47            Syntax::List {
48                children: opposite_children,
49                ..
50            },
51        ) => {
52            for (child, opposite_child) in node_children.iter().zip(opposite_children) {
53                insert_deep_unchanged(child, opposite_child, change_map);
54            }
55        }
56        (Syntax::Atom { .. }, Syntax::Atom { .. }) => {}
57        _ => unreachable!("Unchanged nodes should be both lists, or both atoms"),
58    }
59}
60
61pub fn insert_deep_novel<'a>(node: &'a Syntax<'a>, change_map: &mut ChangeMap<'a>) {
62    change_map.insert(node, ChangeKind::Novel);
63
64    if let Syntax::List { children, .. } = node {
65        for child in children.iter() {
66            insert_deep_novel(child, change_map);
67        }
68    }
69}