Linediff
A lightweight, syntax-aware diff tool for Python with tree-sitter integration. Linediff understands code structure using tree-sitter parsers, providing more meaningful diffs than traditional line-based tools.
Downloads
- Install with PyPI:
pip install linediff - Tracking via pepy
Table of Contents
- Features
- Installation
- Usage
- Git Integration
- Supported Languages
- Examples
- How It Works
- Performance
- Development
- Documentation
- Contributing
- License
Features
- Syntax-aware diffing: Uses tree-sitter parsers to understand code structure
- Multiple display modes: unified, side-by-side, and inline views
- Git integration: Can be used as external diff tool
- Multi-language support: Python, JavaScript, JSON, HTML, CSS, Rust, Go, Java
- Automatic language detection: Based on file extensions
- Robust fallbacks: Falls back to line-based diffing when needed
- Check-only mode: For CI/CD pipelines (exit code indicates if files differ)
- Color output: ANSI color codes for better readability
- Stdin support: Can read diff input from stdin
🚀 Quick Start
Get Linediff in Seconds
From PyPI (Easiest Way):
pip install linediff
From Source (For Contributors):
git clone https://github.com/OthmaneBlial/linediff.git
cd linediff
pip install -e .
Supercharge with Syntax Parsers
Unlock the full power of syntax-aware diffing:
# Get all language parsers
pip install linediff[tree-sitter]
# Or pick your favorites
pip install tree-sitter-python tree-sitter-javascript tree-sitter-json
🎯 Usage
Basic Diff Magic
Compare any two files with intelligent diffing:
linediff file1.py file2.py
See the difference? It's not just lines – it's code structure! 🎉
Git Integration
Linediff can be used as Git's external diff tool:
Global Setup
git config --global diff.external linediff
Per-Language Configuration
git config diff.python.command "linediff --language python"
git config diff.python.binary false
Project Configuration
Add to .gitattributes:
*.py diff=python
*.js diff=javascript
*.json diff=json
Check-Only Mode
For CI/CD pipelines, use --check-only to check if files differ without output:
linediff --check-only file1.py file2.py
echo $? # 0 = identical, 1 = different
Language Override
Override automatic language detection:
linediff --language javascript file1.txt file2.txt
Display Modes
Choose how your diffs are displayed:
Unified (default) - Traditional diff format:
linediff file1.py file2.py
Side-by-side - See changes next to each other with color coding:
linediff --display side-by-side file1.py file2.py
Inline - Changes highlighted with ANSI colors:
linediff --display inline file1.py file2.py
Reading from Stdin
Pipe diff output through linediff:
git diff | linediff
Or provide content via stdin with separator:
cat > /tmp/diff_input << 'EOF'
old content here
---
new content here
EOF
linediff < /tmp/diff_input
🌍 Language Support
Supported Languages:
| Language | Extensions |
|---|---|
| Python | .py, .pyw, .pyi |
| JavaScript | .js, .jsx, .ts, .tsx, .mjs |
| JSON | .json, .jsonc |
| HTML | .html, .htm, .xml |
| CSS | .css, .scss, .sass, .less |
| Rust | .rs |
| Go | .go |
| Java | .java |
For unsupported languages, Linediff falls back to line-based diffing using Python's difflib.
🎨 See Linediff in Action
Python Function Evolution
Before:
def calculate_total(items):
total = 0
for item in items:
total += item.price
return total
After:
def calculate_total(items, tax_rate=0.08):
"""Calculate total with tax."""
subtotal = sum(item.price for item in items)
tax = subtotal * tax_rate
return subtotal + tax
Diff output:
--- old.py
+++ new.py
@@ -1,5 +1,6 @@
-def calculate_total(items):
- total = 0
- for item in items:
- total += item.price
- return total
+def calculate_total(items, tax_rate=0.08):
+ """Calculate total with tax."""
+ subtotal = sum(item.price for item in items)
+ tax = subtotal * tax_rate
+ return subtotal + tax
JavaScript Object Makeover
Before:
const config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
};
After:
const config = {
apiUrl: "https://api.example.com",
timeout: 10000,
retries: 3,
headers: {
"Authorization": "Bearer token"
}
};
Diff output:
--- config.js
+++ config.js
@@ -1,5 +1,8 @@
const config = {
apiUrl: "https://api.example.com",
- timeout: 5000,
+ timeout: 10000,
retries: 3,
+ headers: {
+ "Authorization": "Bearer token"
+ }
};
JSON Config Transformation
Before:
{
"database": {
"host": "localhost",
"port": 5432
},
"features": ["auth", "logging"]
}
After:
{
"database": {
"host": "prod-db.example.com",
"port": 5432,
"ssl": true
},
"features": ["auth", "logging", "metrics"]
}
Diff output:
--- config.json
+++ config.json
@@ -1,6 +1,8 @@
{
"database": {
- "host": "localhost",
+ "host": "prod-db.example.com",
"port": 5432,
+ "ssl": true
},
"features": ["auth", "logging", "metrics"]
}
How It Works
Linediff uses a two-phase approach:
- Syntax Parsing: Tree-sitter parsers convert source code into abstract syntax trees (ASTs)
- Structural Diffing: A graph-based algorithm finds optimal matches between AST nodes
- Fallback: For large files or unsupported languages, falls back to standard difflib
The diff engine implements Dijkstra's algorithm on a graph where nodes represent code elements and edges represent possible matches, insertions, or deletions.
Performance
- Small files: Syntax-aware diffing provides more meaningful results
- Large files: Automatically falls back to line-based diffing for performance
- Memory efficient: Tree parsing is done on-demand with caching
- Fast startup: Parser instances are cached for repeated operations
🛠️ Development
Get Started Contributing
Set up your dev environment:
git clone https://github.com/OthmaneBlial/linediff.git
cd linediff
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ".[dev]"
Run the Test Suite
pytest # Fast, comprehensive testing
Comprehensive Testing Suite
For an interactive testing experience with various scenarios and display modes:
./test_linediff.sh
This provides a menu-driven interface to test different file types, languages, and display modes with real example files.
Building Documentation
# Generate documentation (if applicable)
Code Quality
# Run linting
flake8 src/
# Run type checking
mypy src/
# Format code
black src/
📚 Documentation
Comprehensive documentation is available in the docs/ directory:
For online documentation, visit https://github.com/OthmaneBlial/linediff/blob/main/docs/index.md.
🤝 Contributing
Join the revolution! We love contributions from developers like you.
Check out our Contributing Guide for the full details.
Quick Contribution Flow
- 🍴 Fork the repository
- 🌿 Create a feature branch:
git checkout -b feature/amazing-idea - 💻 Make your awesome changes
- ✅ Add comprehensive tests
- 🚀 Ensure all tests pass:
pytest - 📤 Submit a pull request
Add a New Language
Expand Linediff's universe:
- Add tree-sitter parser to
pyproject.toml - Configure language support in
parser.py - Write tests for the new language
- Update this README with examples
License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
Standing on the shoulders of giants:
- Powered by Tree-sitter for syntax parsing
- Built with Python and cutting-edge algorithms
- Community-driven development with ❤️
Metadata
Release files for linediff 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| linediff-0.1.3.tar.gz | 25.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| linediff-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.1 kB
Release files / linediff-0.1.3.tar.gz
| Download URL | linediff-0.1.3.tar.gz |
|---|---|
| Size | 25.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c3f0ad2e6102f0a4c9d990f2db2cda3eecc3fe75b4a27e9ed5c7b774145dd687
|
|
BLAKE2b-256 checksum How to use checksums |
fe5bdf60ac53026b17f5ef24e2df1ed06d9640bc0c5658e455b4802f8e527305
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.7
|
Release files / linediff-0.1.3-py3-none-any.whl
| Download URL | linediff-0.1.3-py3-none-any.whl |
|---|---|
| Size | 15.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b0583d83525328d1df24798a822b3d062ea0af054cb129c82e36963fc103f4b6
|
|
BLAKE2b-256 checksum How to use checksums |
5c059827c978ee5c2a6c84c8becd89aa693d48f3cbdb3a8972833fc17b4836c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.7
|