### Diff JSON Files with Syndiff in Rust Source: https://context7.com/marcocondrache/syndiff/llms.txt This example demonstrates how to diff JSON files using the syndiff library in Rust. It involves parsing JSON strings into syntax trees and then comparing these trees to identify differences. The output shows the byte ranges and content of removed and added sections. ```rust use syndiff::{build_tree, diff_trees, SyntaxDiffOptions}; fn parse_json(source: &str) -> syndiff::SyntaxTree<'_> { let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_json::LANGUAGE.into()).unwrap(); let tree = parser.parse(source, None).unwrap(); build_tree(tree.walk(), source) } let old_json = r#"{ "foo": [1, 2, 3, 4], "bar": "testing" }"#; let new_json = r#"{ "foo": [2, 3, 4, 5], "zab": "testing", "woo": ["foobar"] }"#; let old_tree = parse_json(old_json); let new_tree = parse_json(new_json); let (old_ranges, new_ranges) = diff_trees( &old_tree, &new_tree, None, None, Some(SyntaxDiffOptions::default()), ).expect("diff succeeded"); println!("=== Removed from old ==="); for range in &old_ranges { println!("{:?}: {:?}", range, &old_json[range.clone()]); } println!("=== Added in new ==="); for range in &new_ranges { println!("{:?}: {:?}", range, &new_json[range.clone()]); } ``` -------------------------------- ### Navigate Syntax Trees with Cursors in Rust Source: https://context7.com/marcocondrache/syndiff/llms.txt Demonstrates how to use cursors for navigating the `SyntaxTree` structure. It covers creating a cursor, moving between nodes (first child, next sibling, parent), and accessing node properties like depth, byte range, and delimiters. ```rust use syndiff::build_tree; let source = "{ \"name\": \"test\", \"value\": 42 }"; let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_json::LANGUAGE.into()).unwrap(); let tree = build_tree(parser.parse(source, None).unwrap().walk(), source); // Create cursor starting at root let mut cursor = tree.cursor(); // Navigate the tree if let Some(node) = cursor.node() { println!("Current depth: {}", node.depth); println!("Byte range: {:?}", node.byte_range); println!("Is list node: {}", node.is_list()); println!("Is atom node: {}", node.is_atom()); // Check for delimiters (brackets, braces, etc.) if let Some(open) = node.open_delimiter() { println!("Open delimiter: {}", open); } if let Some(close) = node.close_delimiter() { println!("Close delimiter: {}", close); } } // Move to first child if cursor.goto_first_child() { println!("Moved to first child"); // Move to next sibling while cursor.goto_next_sibling() { if let Some(node) = cursor.node() { println!("Sibling at byte range: {:?}", node.byte_range); } } // Return to parent cursor.goto_parent(); } // Iterate all nodes in preorder for node_id in tree.preorder() { let node = tree.get(node_id); println!("Node at {:?}, descendants: {}", node.byte_range, node.descendant_count); } ``` -------------------------------- ### Configure SyntaxDiffOptions in Rust Source: https://context7.com/marcocondrache/syndiff/llms.txt Demonstrates how to configure the `SyntaxDiffOptions` struct to control the diff algorithm's behavior, specifically the `graph_limit` parameter to prevent excessive memory usage. It shows both default and custom configurations and how to use them with `diff_trees`. ```rust use syndiff::{build_tree, diff_trees, SyntaxDiffOptions}; let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap(); let old_source = "fn a() { 1 }"; let new_source = "fn b() { 2 }"; let old_tree = build_tree(parser.parse(old_source, None).unwrap().walk(), old_source); parser.reset(); let new_tree = build_tree(parser.parse(new_source, None).unwrap().walk(), new_source); // Default configuration (graph_limit: 1_000_000) let default_options = SyntaxDiffOptions::default(); // Custom configuration for resource-constrained environments let strict_options = SyntaxDiffOptions { graph_limit: 100_000, // Lower limit for faster failure on very different files }; // Use strict options - returns None if files too different match diff_trees(&old_tree, &new_tree, None, None, Some(strict_options)) { Some((old_ranges, new_ranges)) => { println!("Diff computed: {} old ranges, {} new ranges", old_ranges.len(), new_ranges.len()); } None => { println!("Files too different, exceeded graph limit of 100,000 vertices"); } } ``` -------------------------------- ### Perform Partial Diffs with Range Bounds in Rust Source: https://context7.com/marcocondrache/syndiff/llms.txt Illustrates how to perform diff operations on specific regions of files by providing byte range bounds to the `diff_trees` function. The returned ranges are clipped and made relative to the provided bounds, useful for diffing code blocks. ```rust use syndiff::{build_tree, diff_trees}; let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap(); let old_source = "fn foo() { 1 }\nfn bar() { 2 }"; let new_source = "fn foo() { 1 }\nfn bar() { 3 }"; let old_tree = build_tree(parser.parse(old_source, None).unwrap().walk(), old_source); parser.reset(); let new_tree = build_tree(parser.parse(new_source, None).unwrap().walk(), new_source); // Only diff the second function (starting at byte 15) let start_offset = 15; let (old_ranges, new_ranges) = diff_trees( &old_tree, &new_tree, Some(start_offset..old_source.len()), // Bounds for old file Some(start_offset..new_source.len()), // Bounds for new file None, ).expect("diff succeeded"); // Ranges are relative to bounds (starting from 0) for range in &old_ranges { // Convert relative range back to absolute for extraction let absolute_range = (range.start + start_offset)..(range.end + start_offset); println!("Changed in old: {:?}", &old_source[absolute_range]); } // Output: Changed in old: "2" for range in &new_ranges { let absolute_range = (range.start + start_offset)..(range.end + start_offset); println!("Changed in new: {:?}", &new_source[absolute_range]); } // Output: Changed in new: "3" ``` -------------------------------- ### Build SyntaxTree from tree-sitter Parse Tree (Rust) Source: https://context7.com/marcocondrache/syndiff/llms.txt Converts a tree-sitter parse tree and source text into a `SyntaxTree` for diffing. It computes structural hashes and stores nodes in preorder traversal. Dependencies include `syndiff` and `tree_sitter`. ```rust use syndiff::build_tree; let source = "fn add(a: i32, b: i32) -> i32 { a + b }"; // Parse with tree-sitter let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap(); let ts_tree = parser.parse(source, None).unwrap(); // Convert to syndiff tree let syntax_tree = build_tree(ts_tree.walk(), source); // Inspect tree properties println!("Node count: {}", syntax_tree.len()); // Number of nodes println!("Is empty: {}", syntax_tree.is_empty()); // false println!("Has root: {}", syntax_tree.root().is_some()); // true // Navigate the tree if let Some(root_id) = syntax_tree.root() { let root_node = syntax_tree.get(root_id); println!("Root byte range: {:?}", root_node.byte_range); println!("Root descendants: {}", root_node.descendant_count); // Tree navigation if let Some(first_child) = syntax_tree.first_child(root_id) { println!("First child exists"); if let Some(sibling) = syntax_tree.next_sibling(first_child) { println!("Sibling exists"); } } } ``` -------------------------------- ### Compute Structural Diff Between Trees (Rust) Source: https://context7.com/marcocondrache/syndiff/llms.txt Computes a structural diff between two syntax trees, returning byte ranges of changed regions. It uses Dijkstra's algorithm and returns `None` if the graph limit is exceeded. Dependencies include `syndiff` and `tree_sitter`. ```rust use syndiff::{build_tree, diff_trees}; let old_source = "fn add(a: i32, b: i32) -> i32 { a + b }"; let new_source = "fn add(x: i32, y: i32) -> i32 { x + y }"; // Parse both versions with tree-sitter let mut parser = tree_sitter::Parser::new(); parser.set_language(&tree_sitter_rust::LANGUAGE.into()).unwrap(); let old_ts_tree = parser.parse(old_source, None).unwrap(); let new_ts_tree = parser.parse(new_source, None).unwrap(); // Convert to syndiff trees let old_tree = build_tree(old_ts_tree.walk(), old_source); let new_tree = build_tree(new_ts_tree.walk(), new_source); // Compute the diff (returns Option for graph limit handling) let result = diff_trees(&old_tree, &new_tree, None, None, None); match result { Some((old_ranges, new_ranges)) => { // Extract removed text from old source for range in &old_ranges { println!("Removed: {:?}", &old_source[range.clone()]); } // Output: Removed: "a", Removed: "b", Removed: "a", Removed: "b" // Extract added text from new source for range in &new_ranges { println!("Added: {:?}", &new_source[range.clone()]); } // Output: Added: "x", Added: "y", Added: "x", Added: "y" } None => { println!("Diff exceeded graph limit"); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.