diffstory 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffstory-0.2.1/PKG-INFO +242 -0
- diffstory-0.2.1/README.md +225 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/pyproject.toml +1 -1
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/__init__.py +1 -1
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/cli.py +0 -1
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/diff_parser.py +1 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/html_generator.py +61 -5
- diffstory-0.2.1/src/diffstory.egg-info/PKG-INFO +242 -0
- diffstory-0.2.0/PKG-INFO +0 -207
- diffstory-0.2.0/README.md +0 -190
- diffstory-0.2.0/src/diffstory.egg-info/PKG-INFO +0 -207
- {diffstory-0.2.0 → diffstory-0.2.1}/setup.cfg +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/__main__.py +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/git_utils.py +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory/syntax.py +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory.egg-info/SOURCES.txt +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory.egg-info/dependency_links.txt +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory.egg-info/entry_points.txt +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory.egg-info/requires.txt +0 -0
- {diffstory-0.2.0 → diffstory-0.2.1}/src/diffstory.egg-info/top_level.txt +0 -0
diffstory-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: diffstory
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Transform Git diffs into rich, interactive, self-contained HTML reports
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/lakshayjindal/diffstory
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: Pygments>=2.10
|
|
17
|
+
|
|
18
|
+
# DiffStory
|
|
19
|
+
|
|
20
|
+
**Transform Git diffs into rich, interactive, self-contained HTML reports.**
|
|
21
|
+
|
|
22
|
+
DiffStory turns any `git diff` into a beautiful, portable HTML report that answers not just *what* changed, but *who* changed it, *when*, and *why* — all offline, in a single file you can share, archive, or email.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install diffstory
|
|
26
|
+
cd my-repo
|
|
27
|
+
diffstory --staged -o review.html
|
|
28
|
+
# Open review.html in any browser — zero setup required
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
### Three Diff Views
|
|
36
|
+
|
|
37
|
+
| View | Description |
|
|
38
|
+
|---|---|
|
|
39
|
+
| **Unified** | Classic git-style diff with line numbers and syntax highlighting |
|
|
40
|
+
| **Side-by-Side** | Original (left) and modified (right) columns, visually aligned |
|
|
41
|
+
| **Inline Edit** | Word-level diff — shows exact token changes inline, green additions and red strikethrough removals. No more mental diffing. |
|
|
42
|
+
|
|
43
|
+
Switch between views instantly with the toolbar or keyboard shortcuts — no regeneration needed.
|
|
44
|
+
|
|
45
|
+
### Blame & Provenance
|
|
46
|
+
|
|
47
|
+
Every changed line carries its history. **Hover** any line to see a tooltip with author name, commit hash, subject, date, and relative time (e.g. "2h ago"). **Click** any line to open the commit drawer — a side panel with full metadata: commit body, author, committer, parents, files changed, insertions, and deletions.
|
|
48
|
+
|
|
49
|
+
### Search & Filtering
|
|
50
|
+
|
|
51
|
+
- **Global search** — find files by name, author, commit subject, or code content with live results
|
|
52
|
+
- **Filter chips** — narrow the view by file extension (`.py`, `.js`, `.html`, etc.) or change type (added, deleted, modified, renamed)
|
|
53
|
+
- **File sidebar** — searchable file list with add/delete indicators and collapse/expand
|
|
54
|
+
|
|
55
|
+
### Statistics Dashboard
|
|
56
|
+
|
|
57
|
+
A floating panel showing:
|
|
58
|
+
- Files changed, additions, deletions
|
|
59
|
+
- Added / deleted / modified / renamed file counts
|
|
60
|
+
- Author count and commit count (from blame)
|
|
61
|
+
- Contributor breakdown with commit counts
|
|
62
|
+
- Top 10 most-changed files
|
|
63
|
+
|
|
64
|
+
### Keyboard Navigation
|
|
65
|
+
|
|
66
|
+
| Key | Action |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `J` / `K` | Next / previous file |
|
|
69
|
+
| `F` or `/` | Focus global search |
|
|
70
|
+
| `U` / `S` / `I` | Unified / Side-by-side / Inline view |
|
|
71
|
+
| `D` | Toggle light/dark theme |
|
|
72
|
+
| `Esc` | Close drawer → close search → close stats |
|
|
73
|
+
|
|
74
|
+
### Deep Linking
|
|
75
|
+
|
|
76
|
+
Link directly to specific files and lines: `#file-0` scrolls to the first file, `#L-0-42` scrolls to line 42 in the first file. Shareable, stable anchors.
|
|
77
|
+
|
|
78
|
+
### Binary File Support
|
|
79
|
+
|
|
80
|
+
Binary files are detected and displayed with meaningful placeholders — image files get a preview icon, other binaries show metadata — preventing crashes and keeping the report clean.
|
|
81
|
+
|
|
82
|
+
### Customization
|
|
83
|
+
|
|
84
|
+
- **Light/Dark themes** — toggle instantly, persists across sessions
|
|
85
|
+
- **Config file** — `~/.diffstory.toml` or `.diffstory.toml` in your project sets defaults for verbose mode, debug output, and more
|
|
86
|
+
- **`--verbose` / `--debug` flags** — see what's happening under the hood
|
|
87
|
+
|
|
88
|
+
### Export Formats
|
|
89
|
+
|
|
90
|
+
Alongside the HTML report, export structured data:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
diffstory --staged --json --md --csv
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install diffstory
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Requires:** Python 3.10+ and Git.
|
|
105
|
+
|
|
106
|
+
To install from source:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/lakshayjindal/diffstory.git
|
|
110
|
+
cd diffstory
|
|
111
|
+
pip install -e .
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Usage
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Working tree diff
|
|
120
|
+
diffstory
|
|
121
|
+
|
|
122
|
+
# Staged changes (what will be committed)
|
|
123
|
+
diffstory --staged
|
|
124
|
+
|
|
125
|
+
# Compare commits
|
|
126
|
+
diffstory HEAD~3 HEAD
|
|
127
|
+
|
|
128
|
+
# Compare branches
|
|
129
|
+
diffstory main feature-branch
|
|
130
|
+
|
|
131
|
+
# Compare revisions with path restriction
|
|
132
|
+
diffstory HEAD~3 HEAD src/
|
|
133
|
+
|
|
134
|
+
# Generate from a diff file directly (no git repo needed)
|
|
135
|
+
diffstory --diff /path/to/patch.diff
|
|
136
|
+
|
|
137
|
+
# Custom output file
|
|
138
|
+
diffstory -o my-review.html
|
|
139
|
+
|
|
140
|
+
# Multiple export formats at once
|
|
141
|
+
diffstory --staged --json --md --csv -o release-v2.0
|
|
142
|
+
|
|
143
|
+
# Verbose mode
|
|
144
|
+
diffstory --staged --verbose
|
|
145
|
+
|
|
146
|
+
# Show version
|
|
147
|
+
diffstory --version
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Config File Example
|
|
151
|
+
|
|
152
|
+
Create `~/.diffstory.toml` or `.diffstory.toml` in your project:
|
|
153
|
+
|
|
154
|
+
```toml
|
|
155
|
+
[cli]
|
|
156
|
+
verbose = true
|
|
157
|
+
debug = false
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## HTML Report
|
|
163
|
+
|
|
164
|
+
Every generated HTML report is **fully self-contained**:
|
|
165
|
+
|
|
166
|
+
- All CSS inlined — no external stylesheets
|
|
167
|
+
- All JavaScript inlined — no external scripts
|
|
168
|
+
- All data (blame, commits, search index) embedded as JSON
|
|
169
|
+
- Works offline in any modern browser
|
|
170
|
+
- Safe to email, archive, or include in audit evidence
|
|
171
|
+
- Zero external dependencies at runtime
|
|
172
|
+
|
|
173
|
+
Open it, share it, attach it to a PR, or file it for compliance. It just works.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Project Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
diffstory/
|
|
181
|
+
├── pyproject.toml # Build config & CLI entry point
|
|
182
|
+
├── README.md
|
|
183
|
+
├── requirements.md # Full product requirements & spec
|
|
184
|
+
├── deploy.sh # Build & publish script
|
|
185
|
+
├── .github/workflows/publish.yml # CI/CD for PyPI publishing
|
|
186
|
+
├── src/diffstory/
|
|
187
|
+
│ ├── __init__.py # Package version
|
|
188
|
+
│ ├── __main__.py # python -m diffstory support
|
|
189
|
+
│ ├── cli.py # CLI argument parsing & orchestration
|
|
190
|
+
│ ├── git_utils.py # Git subprocess wrappers (diff, blame, log)
|
|
191
|
+
│ ├── diff_parser.py # Unified diff parser → structured data
|
|
192
|
+
│ ├── syntax.py # Pygments syntax highlighting
|
|
193
|
+
│ └── html_generator.py # Self-contained HTML report generation
|
|
194
|
+
└── tests/
|
|
195
|
+
└── __init__.py
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Install in editable mode
|
|
204
|
+
pip install -e .
|
|
205
|
+
|
|
206
|
+
# Test with a quick repo
|
|
207
|
+
cd /tmp && mkdir test-diffstory && cd test-diffstory
|
|
208
|
+
git init && echo "hello" > test.py && git add -A && git commit -m "init"
|
|
209
|
+
echo "world" >> test.py
|
|
210
|
+
diffstory --staged
|
|
211
|
+
|
|
212
|
+
# Build the package
|
|
213
|
+
python -m build
|
|
214
|
+
|
|
215
|
+
# Deploy (version bump, build, publish)
|
|
216
|
+
./deploy.sh # patch bump
|
|
217
|
+
./deploy.sh minor # minor bump
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Design Philosophy
|
|
223
|
+
|
|
224
|
+
DiffStory was built to answer five questions about every changed line:
|
|
225
|
+
|
|
226
|
+
> **What changed? Who changed it? When? Why? How did it evolve?**
|
|
227
|
+
|
|
228
|
+
It consolidates `git diff`, `git blame`, `git log`, and GitHub-style review UX into a single, portable artifact — no server, no accounts, no data leaving your machine.
|
|
229
|
+
|
|
230
|
+
### Security
|
|
231
|
+
|
|
232
|
+
- Never uploads code or transmits data
|
|
233
|
+
- No telemetry, no analytics, no accounts
|
|
234
|
+
- No external API calls by default
|
|
235
|
+
- Never modifies your repository
|
|
236
|
+
- Generated reports are safe for air-gapped environments, client deliverables, and compliance audits
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# DiffStory
|
|
2
|
+
|
|
3
|
+
**Transform Git diffs into rich, interactive, self-contained HTML reports.**
|
|
4
|
+
|
|
5
|
+
DiffStory turns any `git diff` into a beautiful, portable HTML report that answers not just *what* changed, but *who* changed it, *when*, and *why* — all offline, in a single file you can share, archive, or email.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install diffstory
|
|
9
|
+
cd my-repo
|
|
10
|
+
diffstory --staged -o review.html
|
|
11
|
+
# Open review.html in any browser — zero setup required
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
### Three Diff Views
|
|
19
|
+
|
|
20
|
+
| View | Description |
|
|
21
|
+
|---|---|
|
|
22
|
+
| **Unified** | Classic git-style diff with line numbers and syntax highlighting |
|
|
23
|
+
| **Side-by-Side** | Original (left) and modified (right) columns, visually aligned |
|
|
24
|
+
| **Inline Edit** | Word-level diff — shows exact token changes inline, green additions and red strikethrough removals. No more mental diffing. |
|
|
25
|
+
|
|
26
|
+
Switch between views instantly with the toolbar or keyboard shortcuts — no regeneration needed.
|
|
27
|
+
|
|
28
|
+
### Blame & Provenance
|
|
29
|
+
|
|
30
|
+
Every changed line carries its history. **Hover** any line to see a tooltip with author name, commit hash, subject, date, and relative time (e.g. "2h ago"). **Click** any line to open the commit drawer — a side panel with full metadata: commit body, author, committer, parents, files changed, insertions, and deletions.
|
|
31
|
+
|
|
32
|
+
### Search & Filtering
|
|
33
|
+
|
|
34
|
+
- **Global search** — find files by name, author, commit subject, or code content with live results
|
|
35
|
+
- **Filter chips** — narrow the view by file extension (`.py`, `.js`, `.html`, etc.) or change type (added, deleted, modified, renamed)
|
|
36
|
+
- **File sidebar** — searchable file list with add/delete indicators and collapse/expand
|
|
37
|
+
|
|
38
|
+
### Statistics Dashboard
|
|
39
|
+
|
|
40
|
+
A floating panel showing:
|
|
41
|
+
- Files changed, additions, deletions
|
|
42
|
+
- Added / deleted / modified / renamed file counts
|
|
43
|
+
- Author count and commit count (from blame)
|
|
44
|
+
- Contributor breakdown with commit counts
|
|
45
|
+
- Top 10 most-changed files
|
|
46
|
+
|
|
47
|
+
### Keyboard Navigation
|
|
48
|
+
|
|
49
|
+
| Key | Action |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `J` / `K` | Next / previous file |
|
|
52
|
+
| `F` or `/` | Focus global search |
|
|
53
|
+
| `U` / `S` / `I` | Unified / Side-by-side / Inline view |
|
|
54
|
+
| `D` | Toggle light/dark theme |
|
|
55
|
+
| `Esc` | Close drawer → close search → close stats |
|
|
56
|
+
|
|
57
|
+
### Deep Linking
|
|
58
|
+
|
|
59
|
+
Link directly to specific files and lines: `#file-0` scrolls to the first file, `#L-0-42` scrolls to line 42 in the first file. Shareable, stable anchors.
|
|
60
|
+
|
|
61
|
+
### Binary File Support
|
|
62
|
+
|
|
63
|
+
Binary files are detected and displayed with meaningful placeholders — image files get a preview icon, other binaries show metadata — preventing crashes and keeping the report clean.
|
|
64
|
+
|
|
65
|
+
### Customization
|
|
66
|
+
|
|
67
|
+
- **Light/Dark themes** — toggle instantly, persists across sessions
|
|
68
|
+
- **Config file** — `~/.diffstory.toml` or `.diffstory.toml` in your project sets defaults for verbose mode, debug output, and more
|
|
69
|
+
- **`--verbose` / `--debug` flags** — see what's happening under the hood
|
|
70
|
+
|
|
71
|
+
### Export Formats
|
|
72
|
+
|
|
73
|
+
Alongside the HTML report, export structured data:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
diffstory --staged --json --md --csv
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install diffstory
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Requires:** Python 3.10+ and Git.
|
|
88
|
+
|
|
89
|
+
To install from source:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git clone https://github.com/lakshayjindal/diffstory.git
|
|
93
|
+
cd diffstory
|
|
94
|
+
pip install -e .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Usage
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Working tree diff
|
|
103
|
+
diffstory
|
|
104
|
+
|
|
105
|
+
# Staged changes (what will be committed)
|
|
106
|
+
diffstory --staged
|
|
107
|
+
|
|
108
|
+
# Compare commits
|
|
109
|
+
diffstory HEAD~3 HEAD
|
|
110
|
+
|
|
111
|
+
# Compare branches
|
|
112
|
+
diffstory main feature-branch
|
|
113
|
+
|
|
114
|
+
# Compare revisions with path restriction
|
|
115
|
+
diffstory HEAD~3 HEAD src/
|
|
116
|
+
|
|
117
|
+
# Generate from a diff file directly (no git repo needed)
|
|
118
|
+
diffstory --diff /path/to/patch.diff
|
|
119
|
+
|
|
120
|
+
# Custom output file
|
|
121
|
+
diffstory -o my-review.html
|
|
122
|
+
|
|
123
|
+
# Multiple export formats at once
|
|
124
|
+
diffstory --staged --json --md --csv -o release-v2.0
|
|
125
|
+
|
|
126
|
+
# Verbose mode
|
|
127
|
+
diffstory --staged --verbose
|
|
128
|
+
|
|
129
|
+
# Show version
|
|
130
|
+
diffstory --version
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Config File Example
|
|
134
|
+
|
|
135
|
+
Create `~/.diffstory.toml` or `.diffstory.toml` in your project:
|
|
136
|
+
|
|
137
|
+
```toml
|
|
138
|
+
[cli]
|
|
139
|
+
verbose = true
|
|
140
|
+
debug = false
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## HTML Report
|
|
146
|
+
|
|
147
|
+
Every generated HTML report is **fully self-contained**:
|
|
148
|
+
|
|
149
|
+
- All CSS inlined — no external stylesheets
|
|
150
|
+
- All JavaScript inlined — no external scripts
|
|
151
|
+
- All data (blame, commits, search index) embedded as JSON
|
|
152
|
+
- Works offline in any modern browser
|
|
153
|
+
- Safe to email, archive, or include in audit evidence
|
|
154
|
+
- Zero external dependencies at runtime
|
|
155
|
+
|
|
156
|
+
Open it, share it, attach it to a PR, or file it for compliance. It just works.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Project Structure
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
diffstory/
|
|
164
|
+
├── pyproject.toml # Build config & CLI entry point
|
|
165
|
+
├── README.md
|
|
166
|
+
├── requirements.md # Full product requirements & spec
|
|
167
|
+
├── deploy.sh # Build & publish script
|
|
168
|
+
├── .github/workflows/publish.yml # CI/CD for PyPI publishing
|
|
169
|
+
├── src/diffstory/
|
|
170
|
+
│ ├── __init__.py # Package version
|
|
171
|
+
│ ├── __main__.py # python -m diffstory support
|
|
172
|
+
│ ├── cli.py # CLI argument parsing & orchestration
|
|
173
|
+
│ ├── git_utils.py # Git subprocess wrappers (diff, blame, log)
|
|
174
|
+
│ ├── diff_parser.py # Unified diff parser → structured data
|
|
175
|
+
│ ├── syntax.py # Pygments syntax highlighting
|
|
176
|
+
│ └── html_generator.py # Self-contained HTML report generation
|
|
177
|
+
└── tests/
|
|
178
|
+
└── __init__.py
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Development
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# Install in editable mode
|
|
187
|
+
pip install -e .
|
|
188
|
+
|
|
189
|
+
# Test with a quick repo
|
|
190
|
+
cd /tmp && mkdir test-diffstory && cd test-diffstory
|
|
191
|
+
git init && echo "hello" > test.py && git add -A && git commit -m "init"
|
|
192
|
+
echo "world" >> test.py
|
|
193
|
+
diffstory --staged
|
|
194
|
+
|
|
195
|
+
# Build the package
|
|
196
|
+
python -m build
|
|
197
|
+
|
|
198
|
+
# Deploy (version bump, build, publish)
|
|
199
|
+
./deploy.sh # patch bump
|
|
200
|
+
./deploy.sh minor # minor bump
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Design Philosophy
|
|
206
|
+
|
|
207
|
+
DiffStory was built to answer five questions about every changed line:
|
|
208
|
+
|
|
209
|
+
> **What changed? Who changed it? When? Why? How did it evolve?**
|
|
210
|
+
|
|
211
|
+
It consolidates `git diff`, `git blame`, `git log`, and GitHub-style review UX into a single, portable artifact — no server, no accounts, no data leaving your machine.
|
|
212
|
+
|
|
213
|
+
### Security
|
|
214
|
+
|
|
215
|
+
- Never uploads code or transmits data
|
|
216
|
+
- No telemetry, no analytics, no accounts
|
|
217
|
+
- No external API calls by default
|
|
218
|
+
- Never modifies your repository
|
|
219
|
+
- Generated reports are safe for air-gapped environments, client deliverables, and compliance audits
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## License
|
|
224
|
+
|
|
225
|
+
MIT
|
|
@@ -9,7 +9,7 @@ from typing import Any, Optional
|
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
11
|
|
|
12
|
-
from diffstory.diff_parser import DiffFile, DiffLine, Hunk, compute_word_diffs
|
|
12
|
+
from diffstory.diff_parser import DiffFile, DiffLine, Hunk, compute_word_diffs
|
|
13
13
|
from diffstory.syntax import get_highlighted_line, get_syntax_styles
|
|
14
14
|
from diffstory.git_utils import get_blame_for_revision, get_commit_info, get_repo_name
|
|
15
15
|
|
|
@@ -278,10 +278,33 @@ def _render_file_section(file: DiffFile, file_index: int, lexer_cache: dict) ->
|
|
|
278
278
|
sbs_html = ""
|
|
279
279
|
inline_html = ""
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
281
|
+
if file.is_binary_file:
|
|
282
|
+
# Binary file — show placeholder instead of diff hunks
|
|
283
|
+
binary_content = escape("Binary file")
|
|
284
|
+
if file.is_image:
|
|
285
|
+
binary_content = (
|
|
286
|
+
'<div class="binary-preview">'
|
|
287
|
+
'<div class="binary-icon">📷</div>'
|
|
288
|
+
'<div class="binary-label">Image file — ' + escape(file_label) + '</div>'
|
|
289
|
+
'<div class="binary-note">Preview requires the file to be checked out locally</div>'
|
|
290
|
+
'</div>'
|
|
291
|
+
)
|
|
292
|
+
else:
|
|
293
|
+
binary_content = (
|
|
294
|
+
'<div class="binary-preview">'
|
|
295
|
+
'<div class="binary-icon">📄</div>'
|
|
296
|
+
'<div class="binary-label">Binary file — ' + escape(file_label) + '</div>'
|
|
297
|
+
'<div class="binary-note">Diff content not available for binary files</div>'
|
|
298
|
+
'</div>'
|
|
299
|
+
)
|
|
300
|
+
unified_html = '<div class="binary-container">' + binary_content + '</div>'
|
|
301
|
+
sbs_html = '<div class="binary-container">' + binary_content + '</div>'
|
|
302
|
+
inline_html = '<div class="binary-container">' + binary_content + '</div>'
|
|
303
|
+
else:
|
|
304
|
+
for hunk in file.hunks:
|
|
305
|
+
unified_html += _render_unified_hunk(hunk, file.display_path, lexer_cache)
|
|
306
|
+
sbs_html += _render_sidebyside_hunk(hunk, file.display_path, lexer_cache)
|
|
307
|
+
inline_html += _render_inline_hunk(hunk, file.display_path, lexer_cache)
|
|
285
308
|
|
|
286
309
|
additions = sum(1 for h in file.hunks for l in h.lines if l.line_type == "addition")
|
|
287
310
|
deletions = sum(1 for h in file.hunks for l in h.lines if l.line_type == "deletion")
|
|
@@ -1713,6 +1736,39 @@ body {
|
|
|
1713
1736
|
background: #ffd70033;
|
|
1714
1737
|
}
|
|
1715
1738
|
|
|
1739
|
+
/* Binary file preview */
|
|
1740
|
+
.binary-container {
|
|
1741
|
+
padding: 20px;
|
|
1742
|
+
text-align: center;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
.binary-preview {
|
|
1746
|
+
padding: 24px;
|
|
1747
|
+
border: 2px dashed var(--border);
|
|
1748
|
+
border-radius: 8px;
|
|
1749
|
+
background: var(--bg-secondary);
|
|
1750
|
+
max-width: 400px;
|
|
1751
|
+
margin: 0 auto;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
.binary-icon {
|
|
1755
|
+
font-size: 40px;
|
|
1756
|
+
margin-bottom: 8px;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
.binary-label {
|
|
1760
|
+
font-size: 14px;
|
|
1761
|
+
font-weight: 600;
|
|
1762
|
+
color: var(--text);
|
|
1763
|
+
font-family: 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', monospace;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
.binary-note {
|
|
1767
|
+
font-size: 12px;
|
|
1768
|
+
color: var(--text-secondary);
|
|
1769
|
+
margin-top: 4px;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1716
1772
|
/* Diff line hover cursor for blame */
|
|
1717
1773
|
.diff-line {
|
|
1718
1774
|
cursor: pointer;
|