tree_sitter_edit/
print.rs

1use std::io;
2use std::io::Write;
3
4use tree_sitter::Tree;
5
6use crate::editor::Editor;
7
8/// Render edits from [`Editor::in_order_edits`].
9///
10/// If an edit begins inside of a previous edit, then skip it.
11///
12/// # Errors
13///
14/// Errors if [`write!`] returns an error.
15pub fn render(
16    w: &mut impl Write,
17    tree: &Tree,
18    source: &[u8],
19    editor: &impl Editor,
20) -> Result<bool, io::Error> {
21    let mut changed = false;
22    let mut start = 0;
23    for edit in editor.in_order_edits(source, tree) {
24        if edit.position < start {
25            continue;
26        }
27        changed = true;
28        // Write everything up to the start of this edit
29        w.write_all(&source[start..edit.position])?;
30        w.write_all(&edit.insert)?;
31        start = edit.position + edit.delete;
32    }
33    w.write_all(&source[start..source.len()])?;
34    Ok(changed)
35}
36
37#[cfg(test)]
38mod tests {
39    use tree_sitter::Node;
40
41    use super::*;
42    use crate::editors::{Delete, Id, Replace};
43    use crate::id::NodeId;
44
45    fn vec_str(v: &[u8]) -> &str {
46        std::str::from_utf8(v).unwrap()
47    }
48
49    fn parse(src: &str) -> Tree {
50        let mut parser = tree_sitter::Parser::new();
51        parser
52            .set_language(&tree_sitter_c::LANGUAGE.into())
53            .expect("Error loading C grammar");
54        parser.parse(src, None).expect("Failed to parse test")
55    }
56
57    fn do_render(tree: &Tree, src: &str, editor: &impl Editor) -> Vec<u8> {
58        let mut v: Vec<u8> = Vec::new();
59        render(&mut v, tree, src.as_bytes(), editor).expect("I/O error on a vector?");
60        v
61    }
62
63    fn parse_then_render(src: &str, editor: &impl Editor) -> Vec<u8> {
64        do_render(&parse(src), src, editor)
65    }
66
67    #[test]
68    fn parse_then_render_nil() {
69        let src = r#""#;
70        let r = parse_then_render(src, &Id {});
71        assert_eq!(src, vec_str(&r));
72    }
73
74    #[test]
75    fn parse_then_render_main_id() {
76        let src = r#"int main(int argc, char *argv[]) { return 0; }"#;
77        let r = parse_then_render(src, &Id::new());
78        assert_eq!(src, vec_str(&r));
79    }
80
81    #[test]
82    fn parse_then_render_main_omit() {
83        let src = r#"int main(int argc, char *argv[]) { return 0; }"#;
84        let tree = parse(src);
85        let editor = Delete::new(NodeId::new(&tree.root_node()));
86        let r = do_render(&tree, src, &editor);
87        assert_eq!("", vec_str(&r));
88    }
89
90    fn find_kind(tree: &Tree, node: &Node<'_>, kind: &str) -> Option<NodeId> {
91        if node.kind() == kind {
92            return Some(NodeId::new(node));
93        }
94        for child in node.children(&mut tree.walk()) {
95            if let Some(n) = find_kind(tree, &child, kind) {
96                return Some(n);
97            }
98        }
99        None
100    }
101
102    #[test]
103    fn parse_then_render_replace_binary_expr() {
104        let src = r#"int main(int argc, char *argv[]) { return 0 + 0; }"#;
105        let tree = parse(src);
106        let binop = find_kind(&tree, &tree.root_node(), "binary_expression").unwrap();
107        let editor = Replace {
108            id: binop,
109            bytes: "1".as_bytes().to_vec(),
110        };
111        let edited = r#"int main(int argc, char *argv[]) { return 1; }"#;
112        let r = do_render(&tree, src, &editor);
113        assert_eq!(edited, vec_str(&r));
114    }
115
116    #[test]
117    fn parse_then_render_replace_binary_expr_bigger() {
118        let src = r#"int main(int argc, char *argv[]) { return 0 + 0; }"#;
119        let tree = parse(src);
120        let binop = find_kind(&tree, &tree.root_node(), "binary_expression").unwrap();
121        let editor = Replace {
122            id: binop,
123            bytes: "100 + 100000".as_bytes().to_vec(),
124        };
125        let edited = r#"int main(int argc, char *argv[]) { return 100 + 100000; }"#;
126        let r = do_render(&tree, src, &editor);
127        assert_eq!(edited, vec_str(&r));
128    }
129}