code-blocks 0.3.0

A library to re-order your code
Documentation
use anyhow::{ensure, Result};
use tree_sitter::Query;

use code_blocks::{get_query_subtrees, Block};

#[path = "../test_utils.rs"]
mod test_utils;
use test_utils::{build_tree, copy_item_above};

fn preserve_scope(s: &Block, d: &Block) -> Result<()> {
    ensure!(
        s.head().parent() == d.head().parent(),
        "Blocks have different parents"
    );

    Ok(())
}

fn rust_queries() -> [Query; 4] {
    [
        Query::new(
            tree_sitter_rust::language(),
            "(([(attribute_item) (line_comment)] @header . [(attribute_item) (line_comment)]* @header)? . (function_item) @item)",
        )
        .unwrap(),
        Query::new(
            tree_sitter_rust::language(),
            "(([(attribute_item) (line_comment)] @header . [(attribute_item) (line_comment)]* @header)? . (mod_item) @item)",
        )
        .unwrap(),
        Query::new(
            tree_sitter_rust::language(),
            "(([(attribute_item) (line_comment)] @header . [(attribute_item) (line_comment)]* @header)? . (struct_item) @item)",
        )
        .unwrap(),
        Query::new(
            tree_sitter_rust::language(),
            "(([(attribute_item) (line_comment)] @header . [(attribute_item) (line_comment)]* @header)? . (impl_item) @item)",
        )
        .unwrap(),
    ]
}

#[test]
fn test_get_query_subtrees() {
    let text = r#"
mod stuff {
    #[derive(Debug)]
    /// struct doc
    struct A {

    }

    /// docs
    pub fn foo() { }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// test foo
    #[test]
    /// very long test
    #[ignore]
    fn test_foo() {
        stuff::foo();
    }
}
"#;
    let tree = build_tree(text, tree_sitter_rust::language());
    let subtrees = get_query_subtrees(&rust_queries(), &tree, text);

    for t in &subtrees {
        dbg!(text[t.block.byte_range()].to_string());
    }

    insta::assert_debug_snapshot!(subtrees);
}

snapshot! {
    test_move_block,
    tree_sitter_rust::language(),
    rust_queries(),
        r#"
    fn foo() {
 /* ^src */
        fn in_foo() {
            bar();
        }
    }

    fn bar() {}
 /* ^dst */
"#
}

snapshot!(
    test_move_block_in_module,
    tree_sitter_rust::language(),
    rust_queries(),
    r#"
mod m {
    fn foo() {
 /* ^src */
        fn in_foo() {
            bar();
        }
    }

    fn bar() {}
 /* ^dst */
}

fn baz() {}
"#
);

snapshot!(
    test_move_block_in_module2,
    tree_sitter_rust::language(),
    rust_queries(),
    r#"
mod m {
    fn foo() {}
 /* ^src */

    fn bar() {}}
 /* ^dst */

fn baz() {}
"#
);

snapshot!(
    test_move_block_outside_scope_fails,
    tree_sitter_rust::language(),
    rust_queries(),
    preserve_scope,
    r#"
    mod m {
        fn foo() {}
     /* ^src */
    }

    fn baz() {}
/*  ^fail */
"#
);

snapshot!(
    test_move_block_outside_scope_fails2,
    tree_sitter_rust::language(),
    rust_queries(),
    preserve_scope,
    r#"
    mod m {
/*  ^fail */
        fn foo() {}
     /* ^src */
    }

    fn baz() {}
"#
);

snapshot!(
    test_move_block_up,
    tree_sitter_rust::language(),
    rust_queries(),
    r#"
    fn foo() {}
 /* ^dst */

    fn bar() {}

    fn baz() {}
 /* ^src */
"#
);

snapshot!(
    test_move_block_down,
    tree_sitter_rust::language(),
    rust_queries(),
    r#"
    mod m1 {
/*  ^src */
        fn foo() {}
    }

    mod m2 {
        fn bar() {}
    }

    mod m3 {
/*  ^dst */
        fn baz() {}
    }
"#
);

snapshot!(
    test_move_block_up2,
    tree_sitter_rust::language(),
    rust_queries(),
    r#"
    mod m1 {
/*  ^dst */
        fn foo() {}
    }

    mod m2 {
        fn bar() {}
    }

    mod m3 {
/*  ^src */
        fn baz() {}
    }
"#
);

snapshot!(
    test_move_block_into_scope_fails,
    tree_sitter_rust::language(),
    rust_queries(),
    preserve_scope,
    r#"
    mod m1 {
        fn foo() {}
    }

    mod m2 {
        fn bar() {}
    /*  ^fail */
    }

    mod m3 {
/*  ^src */
        fn baz() {}
    }
"#
);

snapshot!(
    test_move_block_with_attributes,
    tree_sitter_rust::language(),
    rust_queries(),
    r#"
    #[test]
    fn foo() {}
/*  ^src */

    fn bar() {}
/*  ^dst */
"#
);