dirplot 0.3.2__tar.gz → 0.4.0__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.
Files changed (155) hide show
  1. {dirplot-0.3.2 → dirplot-0.4.0}/.claude/settings.local.json +3 -1
  2. dirplot-0.4.0/CHANGELOG.md +431 -0
  3. dirplot-0.4.0/LICENSE2 +21 -0
  4. {dirplot-0.3.2 → dirplot-0.4.0}/PKG-INFO +178 -9
  5. {dirplot-0.3.2 → dirplot-0.4.0}/README.md +174 -5
  6. {dirplot-0.3.2 → dirplot-0.4.0}/TASKS.md~ +0 -1
  7. {dirplot-0.3.2 → dirplot-0.4.0}/docs/EXAMPLES.md +5 -5
  8. dirplot-0.4.0/paths.txt +17 -0
  9. {dirplot-0.3.2 → dirplot-0.4.0}/pyproject.toml +21 -4
  10. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/__init__.py +1 -1
  11. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/archives.py +1 -1
  12. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/display.py +21 -3
  13. dirplot-0.4.0/src/dirplot/git_scanner.py +309 -0
  14. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/github.py +30 -0
  15. dirplot-0.4.0/src/dirplot/main.py +1411 -0
  16. dirplot-0.4.0/src/dirplot/pathlist.py +154 -0
  17. dirplot-0.3.2/src/dirplot/render.py → dirplot-0.4.0/src/dirplot/render_png.py +340 -29
  18. dirplot-0.4.0/src/dirplot/replay_scanner.py +172 -0
  19. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/scanner.py +48 -2
  20. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/svg_render.py +27 -4
  21. dirplot-0.4.0/src/dirplot/watch.py +279 -0
  22. dirplot-0.4.0/test_file.txt +0 -0
  23. dirplot-0.4.0/test_file2.txt +0 -0
  24. dirplot-0.4.0/tests/__init__.py +0 -0
  25. dirplot-0.4.0/tests/test_cli.py +483 -0
  26. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_drawing.py +1 -1
  27. dirplot-0.4.0/tests/test_git_github.py +48 -0
  28. dirplot-0.4.0/tests/test_git_local.py +153 -0
  29. dirplot-0.4.0/tests/test_pathlist.py +196 -0
  30. dirplot-0.3.2/tests/test_render.py → dirplot-0.4.0/tests/test_render_png.py +55 -1
  31. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_scanner.py +78 -0
  32. dirplot-0.4.0/tests/test_watch_animate.py +276 -0
  33. {dirplot-0.3.2 → dirplot-0.4.0}/uv.lock +2 -4
  34. dirplot-0.3.2/CHANGELOG.md +0 -207
  35. dirplot-0.3.2/alpine-pod.png +0 -0
  36. dirplot-0.3.2/aws-lambda.png +0 -0
  37. dirplot-0.3.2/demo.cast +0 -418
  38. dirplot-0.3.2/demo1.cast +0 -414
  39. dirplot-0.3.2/docs/dirplot.png +0 -0
  40. dirplot-0.3.2/docs/docker.png +0 -0
  41. dirplot-0.3.2/docs/fastapi.png +0 -0
  42. dirplot-0.3.2/docs/flask.png +0 -0
  43. dirplot-0.3.2/docs/k8s.png +0 -0
  44. dirplot-0.3.2/docs/pypy.png +0 -0
  45. dirplot-0.3.2/docs/python.png +0 -0
  46. dirplot-0.3.2/docs/s3.png +0 -0
  47. dirplot-0.3.2/foo.svg +0 -158
  48. dirplot-0.3.2/misc/scan/FILE-SCANNING.md +0 -72
  49. dirplot-0.3.2/misc/scan/compare.py +0 -58
  50. dirplot-0.3.2/misc/scan/scan_async.py +0 -93
  51. dirplot-0.3.2/misc/scan/scan_dir.py +0 -66
  52. dirplot-0.3.2/misc/scan/scan_rust.py +0 -33
  53. dirplot-0.3.2/misc/scan/scan_threaded.py +0 -90
  54. dirplot-0.3.2/misc/scan/scan_walk.py +0 -46
  55. dirplot-0.3.2/misc/watch/foo.txt +0 -2
  56. dirplot-0.3.2/misc/watch/watch_dir.py +0 -72
  57. dirplot-0.3.2/misc/watch/wordcloud1.png +0 -0
  58. dirplot-0.3.2/misc-watched.png +0 -0
  59. dirplot-0.3.2/openclaw.png +0 -0
  60. dirplot-0.3.2/pg.png +0 -0
  61. dirplot-0.3.2/scripts/animate_demo.py +0 -121
  62. dirplot-0.3.2/scripts/make_docs_images.sh +0 -16
  63. dirplot-0.3.2/scripts/make_fixtures.py +0 -340
  64. dirplot-0.3.2/scripts/open_terminals.sh +0 -71
  65. dirplot-0.3.2/src/dirplot/main.py +0 -615
  66. dirplot-0.3.2/src/dirplot/watch.py +0 -168
  67. dirplot-0.3.2/src-portrait.png +0 -0
  68. dirplot-0.3.2/src.pdf +0 -0
  69. dirplot-0.3.2/src.png +0 -0
  70. dirplot-0.3.2/src.svg +0 -382
  71. dirplot-0.3.2/test-animation.png +0 -0
  72. dirplot-0.3.2/tests/animation/README.md +0 -3
  73. dirplot-0.3.2/tests/animation/changelog.txt +0 -1
  74. dirplot-0.3.2/tests/animation/config.toml +0 -3
  75. dirplot-0.3.2/tests/animation/data/records.csv +0 -4
  76. dirplot-0.3.2/tests/animation/data/schema_v1.json +0 -1
  77. dirplot-0.3.2/tests/animation/src/lib/parser.py +0 -2
  78. dirplot-0.3.2/tests/animation/src/main.py +0 -7
  79. dirplot-0.3.2/tests/test_cli.py +0 -172
  80. {dirplot-0.3.2 → dirplot-0.4.0}/.dockerignore +0 -0
  81. {dirplot-0.3.2 → dirplot-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  82. {dirplot-0.3.2 → dirplot-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  83. {dirplot-0.3.2 → dirplot-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  84. {dirplot-0.3.2 → dirplot-0.4.0}/.github/dependabot.yml +0 -0
  85. {dirplot-0.3.2 → dirplot-0.4.0}/.github/workflows/ci.yml +0 -0
  86. {dirplot-0.3.2 → dirplot-0.4.0}/.github/workflows/publish.yml +0 -0
  87. {dirplot-0.3.2 → dirplot-0.4.0}/.gitignore +0 -0
  88. {dirplot-0.3.2 → dirplot-0.4.0}/.ipynb_checkpoints/Untitled-checkpoint.ipynb +0 -0
  89. {dirplot-0.3.2 → dirplot-0.4.0}/.pre-commit-config.yaml +0 -0
  90. {dirplot-0.3.2 → dirplot-0.4.0}/.python-version +0 -0
  91. {dirplot-0.3.2 → dirplot-0.4.0}/CONTRIBUTING.md +0 -0
  92. {dirplot-0.3.2 → dirplot-0.4.0}/Dockerfile +0 -0
  93. {dirplot-0.3.2 → dirplot-0.4.0}/LICENSE +0 -0
  94. {dirplot-0.3.2 → dirplot-0.4.0}/Makefile +0 -0
  95. {dirplot-0.3.2 → dirplot-0.4.0}/SECURITY.md +0 -0
  96. {dirplot-0.3.2 → dirplot-0.4.0}/demo.yaml +0 -0
  97. {dirplot-0.3.2 → dirplot-0.4.0}/demo.yaml~ +0 -0
  98. {dirplot-0.3.2 → dirplot-0.4.0}/docs/ARCHIVES.md +0 -0
  99. {dirplot-0.3.2 → dirplot-0.4.0}/docs/SSH_DESIGN.md +0 -0
  100. /dirplot-0.3.2/src/dirplot/py.typed → /dirplot-0.4.0/echo +0 -0
  101. {dirplot-0.3.2 → dirplot-0.4.0}/gen_asciicast.py +0 -0
  102. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/__main__.py +0 -0
  103. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/colors.py +0 -0
  104. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/docker.py +0 -0
  105. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/fonts/JetBrainsMono-Bold.ttf +0 -0
  106. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  107. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/fonts/JetBrainsMono-Italic.ttf +0 -0
  108. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/fonts/JetBrainsMono-Regular.ttf +0 -0
  109. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/fonts/OFL.txt +0 -0
  110. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/k8s.py +0 -0
  111. /dirplot-0.3.2/tests/__init__.py → /dirplot-0.4.0/src/dirplot/py.typed +0 -0
  112. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/s3.py +0 -0
  113. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/ssh.py +0 -0
  114. {dirplot-0.3.2 → dirplot-0.4.0}/src/dirplot/terminal.py +0 -0
  115. {dirplot-0.3.2 → dirplot-0.4.0}/tests/conftest.py +0 -0
  116. {dirplot-0.3.2 → dirplot-0.4.0}/tests/example/bar/bar.py +0 -0
  117. {dirplot-0.3.2 → dirplot-0.4.0}/tests/example/bar/baz.json +0 -0
  118. {dirplot-0.3.2 → dirplot-0.4.0}/tests/example/foo/foo.md +0 -0
  119. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.7z +0 -0
  120. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.a +0 -0
  121. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.aab +0 -0
  122. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.apk +0 -0
  123. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.cpio +0 -0
  124. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.ear +0 -0
  125. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.epub +0 -0
  126. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.ipa +0 -0
  127. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.iso +0 -0
  128. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.jar +0 -0
  129. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.nupkg +0 -0
  130. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.rar +0 -0
  131. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tar +0 -0
  132. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tar.bz2 +0 -0
  133. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tar.gz +0 -0
  134. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tar.xz +0 -0
  135. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tar.zst +0 -0
  136. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tbz2 +0 -0
  137. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tgz +0 -0
  138. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.txz +0 -0
  139. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.tzst +0 -0
  140. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.vsix +0 -0
  141. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.war +0 -0
  142. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.whl +0 -0
  143. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.xar +0 -0
  144. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.xpi +0 -0
  145. {dirplot-0.3.2 → dirplot-0.4.0}/tests/fixtures/sample.zip +0 -0
  146. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_archives.py +0 -0
  147. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_colors.py +0 -0
  148. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_display.py +0 -0
  149. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_docker.py +0 -0
  150. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_github.py +0 -0
  151. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_k8s.py +0 -0
  152. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_s3.py +0 -0
  153. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_ssh.py +0 -0
  154. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_svg_render.py +0 -0
  155. {dirplot-0.3.2 → dirplot-0.4.0}/tests/test_terminal.py +0 -0
@@ -7,7 +7,9 @@
7
7
  "Bash(git mv:*)",
8
8
  "Bash(LC_ALL=C sed:*)",
9
9
  "Bash(find:*)",
10
- "Bash(docker run:*)"
10
+ "Bash(docker run:*)",
11
+ "Bash(wc:*)",
12
+ "Bash(identify:*)"
11
13
  ]
12
14
  }
13
15
  }
@@ -0,0 +1,431 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.0] - 2026-03-28
11
+
12
+ ### Added
13
+
14
+ - **MP4 video output** — all three animation commands (`watch --animate`, `git --animate`,
15
+ `replay`) now write MP4 video when the output path ends in `.mp4` or `.mov`. Quality is
16
+ controlled via `--crf` (Constant Rate Factor: 0 = lossless, 51 = worst, default 23) and
17
+ `--codec` (`libx264` H.264 or `libx265` H.265). MP4 files are typically 10–100× smaller
18
+ than equivalent APNGs. Requires `ffmpeg` on PATH.
19
+ ```bash
20
+ dirplot git . -o history.mp4 --animate
21
+ dirplot git . -o history.mp4 --animate --crf 18 --codec libx265
22
+ dirplot replay events.jsonl -o replay.mp4 --total-duration 30
23
+ dirplot watch . -o treemap.mp4 --animate
24
+ ```
25
+ - **`@ref` suffix for `dirplot git`**: local repository paths now accept an optional
26
+ `@ref` suffix to target a specific branch, tag, or commit SHA without needing
27
+ `--range` (e.g. `dirplot git .@my-branch -o out.apng --animate`). `--range` takes
28
+ precedence when both are provided.
29
+ - **`dirplot git` subcommand** — replays a git repository's commit history as an
30
+ animated treemap. Each commit becomes one frame; changed tiles receive the same
31
+ colour-coded highlight borders as `watch --animate` (green = created, blue = modified,
32
+ red = deleted). The commit SHA and local timestamp are shown in the root tile header,
33
+ and a progress bar at the top of each frame advances as the animation plays.
34
+ ```bash
35
+ # Animate all commits, write APNG
36
+ dirplot git . --output history.apng --animate --exclude .git
37
+
38
+ # Last 50 commits on main, 30-second animation with time-proportional frame durations
39
+ dirplot git . --output history.apng --animate \
40
+ --range main~50..main --total-duration 30
41
+
42
+ # Live-updating static PNG (last frame wins; useful with an auto-refreshing viewer)
43
+ dirplot git /path/to/repo --output treemap.png --max-commits 100
44
+ ```
45
+ - **`--range`** (`-r`): git revision range passed directly to `git log`
46
+ (e.g. `main~50..main`, `v1.0..HEAD`). Defaults to the full history of the current branch.
47
+ - **`--max-commits`** (`-n`): cap the number of commits processed.
48
+ - **`--frame-duration`**: fixed frame display time in ms when `--total-duration` is not set
49
+ (default: 1000 ms).
50
+ - **`--total-duration`**: target total animation length in seconds. Frame durations are
51
+ scaled proportionally to the real elapsed time between commits, so quiet periods in
52
+ development history map to longer pauses and burst activity to rapid flips. A 200 ms
53
+ floor prevents very fast commits from being invisible; durations are capped at 65 535 ms
54
+ (APNG uint16 limit). A summary line reports the actual range:
55
+ `Proportional timing: 200–7553 ms/frame (total ~30.1s)`.
56
+ - **`--workers`** (`-w`): number of parallel render workers in animate mode (default: all
57
+ CPU cores). Rendering is memory-bandwidth bound, so 4–8 workers is typically optimal;
58
+ use this flag to tune for your hardware.
59
+ - **Time-proportional progress bar**: a 2 px bar at the top of each frame advances in
60
+ proportion to animation time consumed, not frame count — so a burst of closely-spaced
61
+ commits produces only a small movement while a long quiet period advances it visibly.
62
+ With fixed `--frame-duration` the bar is linear as before.
63
+
64
+ - **Debounced watch** (`--debounce SECONDS`, default `0.5`): the `watch` subcommand now
65
+ collects rapid file-system event bursts and regenerates the treemap once per quiet
66
+ period instead of on every raw event. A `git checkout` touching 100 files triggers
67
+ exactly one render after the activity settles. Pass `--debounce 0` to restore the
68
+ old immediate-fire behaviour.
69
+ ```bash
70
+ dirplot watch . --output treemap.png # 500 ms debounce (default)
71
+ dirplot watch . --output treemap.png --debounce 1.0 # 1 s quiet window
72
+ dirplot watch . --output treemap.png --debounce 0 # immediate, as before
73
+ ```
74
+ - **Event log** (`--event-log FILE`): on Ctrl-C exit, all raw file-system events
75
+ recorded during the session are written as newline-delimited JSON (JSONL) to the
76
+ given file. Each line has `timestamp`, `type`, `path`, and `dest_path` fields.
77
+ The log is written only if there are events to record.
78
+ ```bash
79
+ dirplot watch src --output treemap.png --event-log events.jsonl
80
+ # Ctrl-C, then:
81
+ cat events.jsonl | python3 -m json.tool
82
+ ```
83
+ - **File-change highlights** (`--animate`): each APNG frame now draws colour-coded
84
+ borders around tiles that changed since the previous frame — green for created,
85
+ blue for modified, red for deleted, orange for moved. Deleted files are highlighted
86
+ retroactively on the *previous* frame (since the tile no longer exists in the current
87
+ one), so the animation clearly shows both the disappearance and the appearance of files.
88
+ Moved files appear as a deletion at the old path and a creation at the new path.
89
+ - **Graceful finalization**: Ctrl-C now flushes any pending debounced render before
90
+ stopping the observer, so the output file always reflects the final state of the
91
+ watched tree. A second Ctrl-C during APNG writing is ignored so the file can finish
92
+ being written.
93
+ - **Tree comment stripping**: trailing `# comments` in `tree` output are now ignored
94
+ by the path-list parser, so annotated tree listings (e.g. `├── config.json # app config`)
95
+ are parsed correctly. Filenames containing `#` without a leading space are preserved.
96
+ - **`scripts/apng_frames.py`**: utility script to list frame durations, dimensions, and
97
+ offsets in an APNG file.
98
+ - **`scripts/watch_events.py`**: utility script to watch directories and log filesystem
99
+ events to a CSV file (or stdout) in real time using watchdog.
100
+ - **`--depth` for `watch`**: the `watch` subcommand now accepts `--depth N` to limit
101
+ recursion depth, matching the behaviour of `dirplot map`.
102
+ ```bash
103
+ dirplot watch . --output treemap.png --depth 3
104
+ ```
105
+ - **`dirplot replay` subcommand** — replays a JSONL filesystem event log (as produced
106
+ by `dirplot watch --event-log`) as an animated treemap APNG. Events are grouped into
107
+ time buckets (one frame per bucket, default 60 s), with colour-coded highlight borders
108
+ matching `watch --animate`. Only files referenced in the event log appear in the
109
+ treemap; the common ancestor of all paths is used as the tree root. Frame durations
110
+ can be uniform (`--frame-duration`, default 500 ms) or proportional to the real time
111
+ gaps between buckets (`--total-duration`). Frames are rendered in parallel.
112
+ ```bash
113
+ # Replay an event log with 60-second buckets, 30-second total animation
114
+ dirplot replay events.jsonl --output replay.apng --total-duration 30
115
+
116
+ # Smaller buckets for fine-grained activity, fixed frame duration
117
+ dirplot replay events.jsonl --output replay.apng --bucket 10 --frame-duration 200
118
+ ```
119
+
120
+ - **`dirplot git` accepts GitHub URLs** — pass a `github://owner/repo[@branch]` or
121
+ `https://github.com/owner/repo` URL directly to `dirplot git`. dirplot clones the
122
+ repository into a temporary directory (shallow when `--max-commits` is set, full
123
+ otherwise), runs the full history pipeline locally, and removes the clone on exit.
124
+ No permanent local copy is created.
125
+ ```bash
126
+ # Animate the last 50 commits of a GitHub repo — no local clone needed
127
+ dirplot git github://owner/repo --output history.png --animate --max-commits 50
128
+
129
+ # Specific branch
130
+ dirplot git github://owner/repo@main --output history.png --animate --max-commits 50
131
+ ```
132
+ - **Total commit count shown** — `dirplot git` now reports the total number of commits
133
+ available alongside the number being animated, so you can gauge how much history
134
+ exists before committing to a longer run:
135
+ ```
136
+ Replaying 20 of 147 commit(s) (increase --max-commits to process more) ...
137
+ ```
138
+ For GitHub URLs the count is fetched with a single cheap API request (one commit
139
+ object + `Link` header). For local repos `git rev-list --count HEAD` is used.
140
+ - **`--github-token`** (`$GITHUB_TOKEN`): added to `dirplot git` for private GitHub
141
+ repos or to raise the API rate limit when fetching the total commit count.
142
+
143
+ ### Changed
144
+
145
+ - **`libarchive-c` is now an optional dependency.** Install it with
146
+ `pip install 'dirplot[libarchive]'` (plus the system library:
147
+ `brew install libarchive` / `apt install libarchive-dev`) to enable
148
+ `.iso`, `.cpio`, `.rpm`, `.cab`, `.lha`, `.xar`, `.pkg`, `.dmg`, `.a`, `.ar`,
149
+ and `.tar.zst` / `.tzst` support. The base install works without it; a clear
150
+ error is shown if you try to open one of these formats without the extra.
151
+
152
+ - **`--animate` writes the APNG once on exit** instead of reading and rewriting the
153
+ entire file on every render. Frames are accumulated as raw PNG bytes in memory and
154
+ flushed as a single multi-frame APNG when the watcher stops (Ctrl-C). This removes
155
+ an O(N²) disk-I/O pattern where frame K required reading a K-frame APNG just to
156
+ append one more frame. Status output during a session now reads `Captured frame N`;
157
+ the final `Wrote N-frame APNG → …` line confirms the file was written on exit.
158
+
159
+ ### Fixed
160
+
161
+ - **Initial scan progress**: the `watch` subcommand now prints `Scanning <roots> …`
162
+ before the first render and starts the filesystem observer only after the initial
163
+ treemap has been generated, avoiding spurious events during the first scan.
164
+ - **`--animate` race condition**: the debounce timer thread was marked as daemon,
165
+ causing an in-progress render to be killed when the main thread exited after
166
+ `observer.join()`. The timer is no longer a daemon thread; `flush()` joins any
167
+ in-flight render before stopping.
168
+ - **`--animate` Pillow APNG regression**: passing `pnginfo` alongside `save_all=True`
169
+ caused Pillow to silently write a static PNG instead of an APNG. The `pnginfo`
170
+ argument is now omitted from multi-frame saves (cross-process timing metadata is
171
+ no longer needed since frames are held in memory for the lifetime of the process).
172
+ - **APNG frame duration overflow**: restoring the inter-session frame duration from
173
+ stored metadata could produce a value exceeding 65 535 ms — the maximum expressible
174
+ by APNG's uint16 `delay_num` field when `delay_den = 1000` — causing Pillow to raise
175
+ `cannot write duration`. Durations are now capped at 65 535 ms (≈ 65 s).
176
+
177
+ - **Path-list input from `tree` / `find`** (`--paths-from FILE` or stdin pipe): the `map`
178
+ subcommand now accepts a list of paths produced by `tree` or `find` — either piped via
179
+ stdin or read from a file with `--paths-from`. Format is auto-detected: `tree` output
180
+ (detected by `├──` / `└──` box-drawing characters) or `find` output (one path per line).
181
+ Handles `tree -s` / `tree -h` (size columns), `tree -f` (full embedded paths), and the
182
+ default indented name format. Ancestor/descendant duplicates are collapsed automatically
183
+ so only the minimal set of roots is passed to the scanner.
184
+ ```bash
185
+ # Implicit stdin — no flag needed
186
+ tree src/ | dirplot map
187
+ tree -s src/ | dirplot map # with file sizes in tree output
188
+ find . -name "*.py" | dirplot map
189
+
190
+ # Explicit file
191
+ tree src/ > paths.txt && dirplot map --paths-from paths.txt
192
+
193
+ # Explicit stdin
194
+ tree src/ | dirplot map --paths-from -
195
+ ```
196
+ Positional path arguments and path-list input are mutually exclusive — combining them
197
+ exits with a clear error. Only local paths are supported (remote backends such as
198
+ `docker://`, `s3://`, `ssh://` remain positional-arg only).
199
+
200
+ - **`dirplot watch` accepts multiple directories**: the `watch` subcommand now takes
201
+ one or more positional path arguments and schedules a filesystem observer for each,
202
+ regenerating the treemap from all roots on every change.
203
+ ```bash
204
+ dirplot watch src tests --output treemap.png
205
+ ```
206
+ - **`dirplot map` accepts multiple file paths as roots**: previously, multi-root mode
207
+ required every argument to be a directory. Individual files can now be passed as roots;
208
+ each is treated as a leaf node and displayed under the common parent directory.
209
+ ```bash
210
+ dirplot map src/main.py src/util.py --no-show
211
+ ```
212
+ - **stdout output** (`--output -`): passing `-` as the output path writes the PNG or SVG
213
+ bytes to stdout, enabling piping to other tools. Header and progress lines are
214
+ automatically redirected to stderr to keep the binary stream clean.
215
+ ```bash
216
+ dirplot map . --output - --no-show | convert - -resize 50% small.png
217
+ dirplot map . --output - --format svg --no-show > treemap.svg
218
+ ```
219
+
220
+ ## [0.3.3] - 2026-03-14
221
+
222
+ ### Added
223
+
224
+ - **Breadcrumbs mode** (`--breadcrumbs/--no-breadcrumbs`, `-b/-B`, on by default): directories
225
+ that form a single-child chain (one subdirectory, no files) are collapsed into a single tile
226
+ whose header shows the full path separated by ` / ` (e.g. `src / dirplot / fonts`). When the
227
+ label is too wide, middle segments are replaced with `…` (`src / … / fonts`). The root tile
228
+ is never collapsed. Disable with `-B` or `--no-breadcrumbs`.
229
+ - **Tree depth in root label**: the root tile header now includes `depth: N` alongside the
230
+ file, directory, and size summary (e.g. `myproject — 124 files, 18 dirs, 4.0 MB (…), depth: 6`).
231
+ The depth reflects the original tree structure and is invariant to whether breadcrumbs mode
232
+ is active.
233
+
234
+ ## [0.3.2] - 2026-03-13
235
+
236
+ ### Added
237
+
238
+ - **`dirplot watch`** subcommand — watches a directory and regenerates the treemap
239
+ on every file-system change using watchdog (FSEvents on macOS, inotify on Linux,
240
+ kqueue on BSD). Requires `watchdog`, now a core dependency.
241
+ ```bash
242
+ dirplot watch . --output treemap.png
243
+ dirplot watch . --output treemap.png --animate # APNG, one frame per change
244
+ ```
245
+ - **Vertical file labels**: file tiles that are at least twice as tall as wide now
246
+ display their label rotated 90° CCW, letting the text span the full tile height
247
+ instead of being squeezed into the narrow width.
248
+ - **Scan and render timing** shown in header output:
249
+ `Found 1,414 files … [2.3s]` and `Saved dirplot to out.png [0.4s]`.
250
+ - **Multiple local roots**: `dirplot map src tests` accepts two or more local
251
+ directory paths, finds their common parent, and shows only those subtrees.
252
+ - **`--subtree` / `-s`** option (repeatable) — allowlist complement to `--exclude`:
253
+ keep only the named direct children of the root after scanning. Supports nested
254
+ paths such as `--subtree src/dirplot/fonts`.
255
+
256
+ ### Fixed
257
+
258
+ - `--exclude` on pod and Docker backends now prunes entire subtrees — previously only
259
+ the exact path was matched, so all children leaked through.
260
+ - Clearer error for distroless pods: exit code 126 from `kubectl exec` now surfaces as
261
+ an actionable message explaining that the container has no shell or `find` utility.
262
+ - Adaptive file-label font size is now computed with a single `textbbox` measurement
263
+ (one call per tile) instead of stepping down one pixel at a time — eliminates an
264
+ O(font_size × n_tiles) bottleneck that caused near-blocking on large trees such as
265
+ `.venv` directories.
266
+
267
+ ### Changed
268
+
269
+ - `-s` short alias reassigned from `--font-size` to `--subtree`. `--font-size` still
270
+ works as before; it just no longer has a single-letter alias.
271
+
272
+ ## [0.3.1] - 2026-03-11
273
+
274
+ ### Added
275
+
276
+ - `github://` URI now accepts an optional subpath after the repository name, letting
277
+ you scan a subdirectory directly:
278
+ - `github://owner/repo/sub/path` — subpath on the default branch
279
+ - `github://owner/repo@ref/sub/path` — subpath on a specific branch, tag, or commit SHA
280
+ - `https://github.com/owner/repo/tree/branch/sub/path` — full GitHub URL form
281
+ - Tags and commit SHAs are supported wherever a branch ref was previously accepted
282
+ (e.g. `github://torvalds/linux@v6.12`), as the GitHub trees API accepts any git ref.
283
+ - `--legend N` replaces the old boolean `--legend/--no-legend` flag. It now shows a
284
+ **file-count legend** — a sorted list of the top N extensions by number of files,
285
+ with a coloured swatch and the file count for each entry:
286
+ - Pass `--legend` alone to use the default of 20 entries.
287
+ - Pass `--legend 10` for a custom limit.
288
+ - Omit the flag entirely to show no legend.
289
+ - The number of rows is also capped automatically so the box never overflows the
290
+ image, based on available vertical space and the current `--font-size`.
291
+ - Extensions with the same count are sorted alphabetically as a tiebreaker.
292
+ - When the total number of extensions exceeds the limit, a `(+N more)` line is
293
+ appended at the bottom of the box.
294
+
295
+ - The root tile header now includes a summary of the scanned tree after an em-dash
296
+ separator: `myproject — 124 files, 18 dirs, 4.0 MB (4,231,680 bytes)`.
297
+ Applies to both PNG and SVG output. The label is truncated with `…` when the tile
298
+ is too narrow to fit the full string.
299
+
300
+ - Greatly expanded archive format support via the new `libarchive-c` core dependency
301
+ (wraps the system libarchive C library):
302
+ - **New formats**: `.iso`, `.cpio`, `.xar`, `.pkg`, `.dmg`, `.img`, `.rpm`, `.cab`,
303
+ `.lha`, `.lzh`, `.a`, `.ar`, `.tar.zst`, `.tzst`
304
+ - **New ZIP aliases**: `.nupkg` (NuGet), `.vsix` (VS Code extension), `.ipa` (iOS app),
305
+ `.aab` (Android App Bundle)
306
+ - `.tar.zst` / `.tzst` routed through libarchive for consistent behaviour across all
307
+ supported Python versions (stdlib `tarfile` only gained zstd support in 3.12).
308
+ - `libarchive-c>=5.0` added as a core dependency alongside `py7zr` and `rarfile`.
309
+ Requires the system libarchive library:
310
+ `brew install libarchive` / `apt install libarchive-dev`.
311
+ - See [ARCHIVES.md](docs/ARCHIVES.md) for the full format table, platform notes, and
312
+ intentionally unsupported formats (`.deb`, UDIF `.dmg`).
313
+ - Encrypted archive handling:
314
+ - `--password` CLI option passes a passphrase upfront.
315
+ - If an archive turns out to be encrypted and no password was given, dirplot prompts
316
+ interactively (`Password:` hidden-input prompt) and retries — no need to re-run with a flag.
317
+ - A wrong password exits cleanly with `Error: incorrect password.`
318
+ - `PasswordRequired` exception exported from `dirplot.archives` for programmatic use.
319
+ - **Encryption behaviour by format** (since dirplot reads metadata only, never extracts):
320
+ - ZIP and 7z: central directory / file list is unencrypted by default → readable without
321
+ a password even for encrypted archives.
322
+ - RAR with header encryption (`-hp`): listing is hidden without password;
323
+ wrong password raises `PasswordRequired`.
324
+
325
+ ### Fixed
326
+
327
+ - `--version` moved back to the top-level `dirplot` command (was accidentally scoped
328
+ to `dirplot map` after the CLI was restructured into subcommands).
329
+
330
+ ## [0.3.0] - 2026-03-10
331
+
332
+ ### Added
333
+
334
+ - Kubernetes pod scanning via `pod://pod-name/path` syntax — uses `kubectl exec` and
335
+ `find` to build the tree without copying files out of the pod. Works on any running
336
+ pod that has a POSIX shell and `find` (GNU or BusyBox). No extra dependency; only
337
+ `kubectl` is required.
338
+ - Namespace can be specified inline (`pod://pod-name@namespace:/path`) or via
339
+ `--k8s-namespace`.
340
+ - Container can be selected for multi-container pods via `--k8s-container`.
341
+ - `-xdev` is intentionally omitted so mounted volumes (emptyDir, PVC, etc.) within
342
+ the scanned path are traversed — the common case in k8s where images declare
343
+ `VOLUME` entries that are always mounted on a separate filesystem.
344
+ - Automatically falls back to a portable `sh` + `stat` loop on BusyBox/Alpine pods.
345
+ - Docker container scanning via `docker://container:/path` syntax — uses `docker exec`
346
+ and `find` to build the tree without copying files out of the container. Works on any
347
+ running container that has a POSIX shell and `find` (GNU or BusyBox). No extra
348
+ dependency; only the `docker` CLI is required.
349
+ - Automatically detects BusyBox `find` (Alpine-based images) and falls back to a
350
+ portable `sh` + `stat` loop when GNU `-printf` is unavailable.
351
+ - Virtual filesystems (`/proc`, `/sys`, `/dev`) are skipped via `-xdev`.
352
+ - Supports `--exclude`, `--depth`, `--log`, and all other standard options.
353
+ - `Dockerfile` and `.dockerignore` added so the project itself can be used as a
354
+ scan target.
355
+ - SVG output format via `--format svg` or by saving to a `.svg`-suffixed path with `--output`.
356
+ The output is a fully self-contained, interactive SVG file:
357
+ - **CSS hover highlight** — file tiles brighten and gain a soft glow; directory headers
358
+ brighten on mouse-over (`.tile` / `.dir-tile` classes, no JavaScript needed).
359
+ - **Floating tooltip panel** — a JavaScript-driven semi-transparent panel tracks the cursor
360
+ and shows the file or directory name, human-readable size, and file-type / item count.
361
+ No external scripts or stylesheets — the panel logic is embedded in the SVG itself.
362
+ - **Van Wijk cushion shading** — approximated via a single diagonal `linearGradient`
363
+ overlay (`gradientUnits="objectBoundingBox"`), defined once and shared across all tiles.
364
+ Matches the ×1.20 highlight / ×0.80 shadow range of the PNG renderer.
365
+ Disabled with `--no-cushion`.
366
+ - `--format png|svg` CLI option; format is also auto-detected from the `--output` file
367
+ extension.
368
+ - `create_treemap_svg()` added to the public Python API (`from dirplot import create_treemap_svg`).
369
+ - `drawsvg>=2.4` added as a core dependency.
370
+ - Rename the treemap command to `map` (dirplot map <root>).
371
+ - Add `termsize` subcommand and restructure CLI as multi-command app.
372
+ - Add `--depht` parameter to limit the scanning of large file trees.
373
+ - Support for SSH remote directory scanning (`pip install dirplot[ssh]`).
374
+ - Support for AWS S3 buckets in the cloud (`pip install dirplot[s3]`).
375
+ - Support for local archive files, .zip, tgz, .tar.xz, .rar, .7z, etc.
376
+ - Include example archives for 17 different extentions for testing.
377
+ - Comprehensive documentation.
378
+ - `github://owner/repo[@branch]` URI scheme for GitHub repository scanning. The old
379
+ `github:owner/repo` shorthand has been removed.
380
+ - File tiles now have a 1-px dark outline (60/255 below fill colour per channel) so
381
+ adjacent same-coloured tiles — e.g. a directory full of extension-less files — are
382
+ always visually distinct rather than blending into a single flat block.
383
+
384
+ ### Changed
385
+
386
+ - `docs/REMOTE-ACCESS.md` renamed to `docs/EXAMPLES.md`; Docker and Kubernetes pod
387
+ sections added; images with captions added for all remote backends.
388
+
389
+ ### Fixed
390
+
391
+ - SVG tooltips now show the original byte count when `--log` is active, not the
392
+ log-transformed layout value. `Node.original_size` is populated by `apply_log_sizes`
393
+ for both file and directory nodes and is used by the SVG renderer for `data-size`.
394
+ - GitHub error messages are now clear and actionable.
395
+
396
+ ## [0.2.0] - 2026-03-09
397
+
398
+ ### Added
399
+
400
+ - Support for Windows, incl. full test suite
401
+
402
+ ### Fixed
403
+
404
+ - Improved README, Makefile
405
+
406
+ ## [0.1.2] - 2026-03-06
407
+
408
+ ### Fixed
409
+
410
+ - Partly incorrect `uvx install dirplot` command
411
+ - Wrong version number in `uv.lock`
412
+
413
+ ## [0.1.1] - 2026-03-06
414
+
415
+ ### Fixed
416
+
417
+ - Typing complaints
418
+ - Improved README with better install/run commands
419
+
420
+ ## [0.1.0] - 2026-03-06
421
+
422
+ ### Added
423
+
424
+ - Nested squarified treemap rendered as a PNG at the exact pixel dimensions of the terminal window.
425
+ - Inline terminal display via iTerm2 and Kitty graphics protocols, auto-detected at runtime; supports iTerm2, WezTerm, Warp, Hyper, Kitty, and Ghostty.
426
+ - System-viewer fallback (`open` / `xdg-open`) as the default display mode.
427
+ - File-extension colours from the GitHub Linguist palette (~500 known extensions); unknown extensions fall back to a stable MD5-derived colour from the chosen colormap.
428
+ - Van Wijk quadratic cushion shading giving each tile a raised 3-D look (`--cushion`, on by default).
429
+ - Bundled JetBrains Mono fonts for crisp directory labels at any size.
430
+ - CLI options: `--output`, `--show/--no-show`, `--inline`, `--legend`, `--font-size`, `--colormap`, `--exclude`, `--size`, `--header/--no-header`, `--cushion/--no-cushion`, `--log`.
431
+ - Full test suite (65 tests), strict mypy, ruff linting, pre-commit hooks, and CI on Python 3.10–3.13.
dirplot-0.4.0/LICENSE2 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dinu Gherman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.