Part of Tuulbelt — A collection of focused, zero-dependency tools
Semantic diff tool for JSON, text, and binary files with zero dependencies.
When comparing files in tests, builds, or data pipelines, you need to see what changed in a structured, semantic way. Standard diff works for text but doesn't understand JSON structure or binary formats. This tool provides:
- Text diffs with LCS algorithm (line-by-line comparison)
- JSON diffs with structural understanding (field paths, not lines)
- Binary diffs with byte-level comparison (hex output)
All with zero external dependencies.
- Zero runtime dependencies (uses only Rust standard library)
- Multiple diff types: Text (LCS), JSON (structural), Binary (byte-by-byte)
- Multiple output formats: Unified, JSON, side-by-side, compact
- Cross-platform support (Linux, macOS, Windows)
- Both library and CLI interfaces
- Proper exit codes (0=identical, 1=differ, 2=error)
- Composable with other Tuulbelt tools
git clone https://github.com/tuulbelt/output-diffing-utility.git
cd output-diffing-utility
cargo build --releaseThe binary supports both short and long command names:
- Short (recommended):
target/release/odiff - Long:
target/release/output-diff
Recommended setup - install globally for easy access:
cargo install --path .
# Now use `odiff` anywhere
odiff --helpAdd to your Cargo.toml:
[dependencies]
output-diffing-utility = { git = "https://github.com/tuulbelt/output-diffing-utility.git" }# Basic text diff
odiff file1.txt file2.txt
# JSON structural diff
odiff data1.json data2.json
# Binary diff
odiff image1.png image2.png
# With ANSI color codes (works for text, JSON, and binary diffs)
odiff --color always file1.txt file2.txt
odiff --color always data1.json data2.json
odiff --color always image1.png image2.png
# Or use 'auto' to enable color only when outputting to a terminal
odiff --color auto file1.txt file2.txt
# Verbose output
odiff --verbose file1.txt file2.txtColor Support:
- ✅ Text diffs: Green for additions, red for deletions
- ✅ JSON diffs: Cyan for paths, green for added values, red for removed values, yellow for modifications
- ✅ Binary diffs: Cyan for offsets, red for old bytes, green for new bytes
- ❌ JSON/SideBySide/Compact formats: Color not applied (use
--format unifiedfor color)
Output:
--- file1.txt
+++ file2.txt
line 1
- line 2
+ line 2 modified
line 3
+ line 4Exit codes:
0- Files are identical1- Files differ2- Error occurred
use output_diffing_utility::{diff_text, DiffConfig};
let old = "line 1\nline 2";
let new = "line 1\nline 2 modified";
let config = DiffConfig::default();
let result = diff_text(old, new, &config);
if result.has_changes() {
println!("Files differ!");
println!("Additions: {}", result.additions());
println!("Deletions: {}", result.deletions());
}Compare two text strings line-by-line using the LCS algorithm.
Returns: DiffResult with line-by-line changes.
Compare two JSON strings structurally (field paths, not lines).
Returns: Result<JsonDiffResult, JsonError> with structural changes.
Compare two byte arrays byte-by-byte.
Returns: BinaryDiffResult with byte-level comparison.
DiffConfig {
context_lines: 3, // Lines of context around changes
format: OutputFormat::Unified, // Unified, JSON, SideBySide, Compact
color: false, // Enable ANSI color codes
verbose: false, // Show detailed information
}Each result type provides:
has_changes()/is_identical()- Quick checkadditions(),deletions()- Change counts- Iterator over changes for detailed analysis
The text diff uses dynamic programming to find the optimal diff:
- Time complexity: O(m×n) where m, n are line counts
- Space complexity: O(m×n)
- Output: Minimal set of changes (additions/deletions)
See DIFF_ALGORITHMS_RESEARCH.md for detailed algorithm analysis.
This tool demonstrates the power of composability by working seamlessly with other Tuulbelt tools. When in the monorepo, you can chain tools together via CLI interfaces:
CLI Progress Reporting - Track progress for large file diffs:
./scripts/dogfood-progress.sh
# Shows: TypeScript (progress) ↔ Rust (diff) compositionCross-Platform Path Normalizer - Handle Windows/Unix/mixed path formats:
./scripts/dogfood-paths.sh
# Shows: Path normalization → Rust diff pipelineFile-Based Semaphore - Protect concurrent diff cache access:
./scripts/dogfood-semaphore.sh
# Shows: Rust (semaphore) → Rust (diff) compositionTest Flakiness Detector - Validate test reliability:
./scripts/dogfood-flaky.sh
# Validates all 99 tests are deterministicRun all 5 Phase 1 tools together in a single workflow:
./scripts/dogfood-pipeline.shThis pipeline demonstrates:
- Cross-language composition (TypeScript ↔ Rust)
- Tools communicating via CLI interfaces only
- No runtime dependencies between tools
- Real-world use case (API version comparison)
- Graceful degradation if tools missing
See DOGFOODING_STRATEGY.md for implementation details.
# Run tests
cargo test
# Run with zero warnings
cargo clippy -- -D warnings
# Format code
cargo fmt
# Build optimized release
cargo build --releaseWe dogfood this tool by composing it with other Tuulbelt tools:
# Validate test reliability (Test Flakiness Detector)
./scripts/dogfood-flaky.sh 20
# Show progress tracking (CLI Progress Reporting)
./scripts/dogfood-progress.sh
# Handle cross-platform paths (Path Normalizer)
./scripts/dogfood-paths.sh
# Protect concurrent access (File-Based Semaphore)
./scripts/dogfood-semaphore.sh
# Run complete multi-tool pipeline (all 5 tools)
./scripts/dogfood-pipeline.shThese scripts demonstrate real-world tool composition and validate that all 99 tests are deterministic.
See examples/ directory for real-world usage patterns.
▶ View interactive recording on asciinema.org
MIT — see LICENSE
