doxtr-roadmap 0.1.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.
- doxtr_roadmap-0.1.0/LICENSE +21 -0
- doxtr_roadmap-0.1.0/PKG-INFO +653 -0
- doxtr_roadmap-0.1.0/README.md +631 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/__init__.py +269 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/config_defaults.py +144 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/csv_parser.py +301 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/directive.py +989 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/generator.py +868 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/link_resolver.py +239 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/plantuml_version.py +95 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/safe_query.py +345 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/tags.py +424 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap/theme_adapter.py +197 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap.egg-info/PKG-INFO +653 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap.egg-info/SOURCES.txt +27 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap.egg-info/dependency_links.txt +1 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap.egg-info/requires.txt +8 -0
- doxtr_roadmap-0.1.0/doxtr_roadmap.egg-info/top_level.txt +1 -0
- doxtr_roadmap-0.1.0/pyproject.toml +57 -0
- doxtr_roadmap-0.1.0/setup.cfg +4 -0
- doxtr_roadmap-0.1.0/tests/test_collision.py +369 -0
- doxtr_roadmap-0.1.0/tests/test_csv_parser.py +365 -0
- doxtr_roadmap-0.1.0/tests/test_directive.py +2116 -0
- doxtr_roadmap-0.1.0/tests/test_generator.py +823 -0
- doxtr_roadmap-0.1.0/tests/test_link_resolver.py +243 -0
- doxtr_roadmap-0.1.0/tests/test_plantuml_version.py +356 -0
- doxtr_roadmap-0.1.0/tests/test_safe_query.py +349 -0
- doxtr_roadmap-0.1.0/tests/test_tags.py +296 -0
- doxtr_roadmap-0.1.0/tests/test_theme_adapter.py +297 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Doxtr
|
|
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.
|
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: doxtr-roadmap
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sphinx extension that generates PlantUML Gantt roadmaps from CSV data.
|
|
5
|
+
Author: Jens Frey
|
|
6
|
+
Project-URL: Homepage, https://github.com/doxtr/doxtr-roadmap
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Framework :: Sphinx :: Extension
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: sphinx>=5.0
|
|
15
|
+
Requires-Dist: sphinxcontrib-plantuml>=0.9
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
19
|
+
Requires-Dist: sphinxcontrib-xlink; extra == "dev"
|
|
20
|
+
Requires-Dist: doxtr-pdf-theme-core; extra == "dev"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# doxtr-roadmap
|
|
24
|
+
|
|
25
|
+
A Sphinx extension that generates PlantUML Gantt roadmaps from CSV data.
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
`doxtr-roadmap` provides a `.. roadmap::` directive that reads roadmap items
|
|
30
|
+
from a CSV file (or inline CSV body), applies optional zoom/filter/tag
|
|
31
|
+
constraints, and emits a PlantUML Gantt chart node rendered via
|
|
32
|
+
`sphinxcontrib.plantuml`.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install doxtr-roadmap
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Requires `sphinxcontrib-plantuml>=0.9` (listed as a dependency).
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
Add both extensions to your `conf.py`:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
extensions = [
|
|
48
|
+
"sphinxcontrib.plantuml",
|
|
49
|
+
"doxtr_roadmap",
|
|
50
|
+
]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then use the directive in any RST document:
|
|
54
|
+
|
|
55
|
+
```rst
|
|
56
|
+
.. roadmap::
|
|
57
|
+
:file: path/to/roadmap.csv
|
|
58
|
+
:title: My Project Roadmap
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Or with inline CSV content:
|
|
62
|
+
|
|
63
|
+
```rst
|
|
64
|
+
.. roadmap::
|
|
65
|
+
:title: Sprint Overview
|
|
66
|
+
|
|
67
|
+
section,name,start,end,row_group,link,tags
|
|
68
|
+
Q1,Feature A,2026-01-01,2026-03-31,,,eng
|
|
69
|
+
Q1,Feature B,2026-02-01,2026-04-30,,,code
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Multiple files and globs
|
|
73
|
+
|
|
74
|
+
The `:file:` option accepts one or more CSV paths and/or glob patterns,
|
|
75
|
+
space- or comma-separated. All matched files are treated as **one combined
|
|
76
|
+
roadmap**: sections with the same name merge across files and subtasks /
|
|
77
|
+
`row_group` references work even when the parent task is defined in a
|
|
78
|
+
different file.
|
|
79
|
+
|
|
80
|
+
```rst
|
|
81
|
+
.. roadmap::
|
|
82
|
+
:file: sprints/sprint-01.csv sprints/sprint-02.csv sprints/sprint-03.csv
|
|
83
|
+
:title: All Sprints
|
|
84
|
+
|
|
85
|
+
.. roadmap::
|
|
86
|
+
:file: sprints/sprint-*.csv # equivalent glob
|
|
87
|
+
:title: All Sprints
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Both examples produce the **same** combined roadmap. Key rules:
|
|
91
|
+
|
|
92
|
+
- Paths are resolved relative to the document directory first, then `srcdir`.
|
|
93
|
+
- Glob matches within a single pattern are sorted lexicographically
|
|
94
|
+
(`sprint-01`, `sprint-02`, …) so the combination order is predictable.
|
|
95
|
+
- A file matched by more than one spec is read only once (de-duplicated,
|
|
96
|
+
first-seen order preserved).
|
|
97
|
+
- If a spec matches no files the directive reports an error.
|
|
98
|
+
- `env.note_dependency` is called for each resolved file so editing any of
|
|
99
|
+
them triggers an incremental rebuild. *Adding a brand-new file* matching
|
|
100
|
+
an existing glob is not detected automatically — run `make clean html`
|
|
101
|
+
after adding files to a glob pattern.
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
The CSV must have a header row. Only `name`, `start`, and `end` are
|
|
106
|
+
required; every other column is optional and may be omitted entirely:
|
|
107
|
+
|
|
108
|
+
| Column | Required | Description |
|
|
109
|
+
|-------------|----------|-------------|
|
|
110
|
+
| `section` | no | Section/group name, or a parent task name for subtasks. Blank or omitted → the task renders with no section header |
|
|
111
|
+
| `name` | yes | Task display name |
|
|
112
|
+
| `start` | yes | Start date (ISO `YYYY-MM-DD`) |
|
|
113
|
+
| `end` | yes | End date (ISO `YYYY-MM-DD`). Same as `start` → milestone |
|
|
114
|
+
| `row_group` | no | Tasks sharing this non-empty value render on one Gantt row |
|
|
115
|
+
| `link` | no | Plain URL or `:xlink:\`id\`` role expression |
|
|
116
|
+
| `tags` | no | Comma-separated tag list |
|
|
117
|
+
|
|
118
|
+
### Subtasks
|
|
119
|
+
|
|
120
|
+
A row whose `section` column matches an existing top-level task name becomes a
|
|
121
|
+
subtask, inserted directly beneath the parent task in the same section.
|
|
122
|
+
|
|
123
|
+
### Milestones
|
|
124
|
+
|
|
125
|
+
When `start == end`, the row is rendered as a Gantt milestone (diamond marker).
|
|
126
|
+
Milestones are never clamped to the clip window.
|
|
127
|
+
|
|
128
|
+
## Directive Options
|
|
129
|
+
|
|
130
|
+
| Option | Type | Description |
|
|
131
|
+
|------------------|-------------------|-------------|
|
|
132
|
+
| `:file:` | path(s)/glob(s) | One or more CSV paths and/or glob patterns, space- or comma-separated. All matched files are combined into a single roadmap (sections merge by name; subtasks and row-groups work across files). Glob metacharacters (`*`, `?`, `[…]`) are expanded; within each glob matches are sorted lexicographically. A single path with no separators behaves as before. |
|
|
133
|
+
| `:title:` | string | Override diagram title |
|
|
134
|
+
| `:scale:` | choice | `daily`, `weekly`, `monthly` |
|
|
135
|
+
| `:start:` | ISO date | Clip window start |
|
|
136
|
+
| `:end:` | ISO date | Clip window end |
|
|
137
|
+
| `:period:` | string | Comma-separated period name(s) to zoom to |
|
|
138
|
+
| `:close-weekends:` | flag | Force weekend closure |
|
|
139
|
+
| `:clean-style:` | true/false | Override `clean_style` for this directive; bare flag or `true` enables, `false` disables (see [clean_style](#clean_style-and-the-hide-column-directives)) |
|
|
140
|
+
| `:tags:` | string | Tag filter (nested `[ ]` / `!` / `!!` syntax) |
|
|
141
|
+
| `:query:` | Python expression | Safe-eval row filter; available names: `name`, `start`, `end`, `section`, `tags`, `row_group`, `match(pattern, string)`; safe builtins: `any`, `all`, `bool`, `set`, `len` |
|
|
142
|
+
| `:collision-detection:` | true/false | Override collision detection for this chart; bare flag or `true` enables, `false` disables (see [Collision detection](#collision-detection)) |
|
|
143
|
+
| `:collision-char-width-factor:` | float | Per-chart label-width tuning knob (overrides `doxtr_roadmap_collision_char_width_factor`) |
|
|
144
|
+
| `:column-zoom:` | float | Per-chart gantt column width multiplier; overrides `doxtr_roadmap_column_zoom` (see [Column width (zoom)](#column-width-zoom)) |
|
|
145
|
+
| `:width:` | length/% | Force the rendered image to fill a specific width in HTML and PDF (e.g. `100%`); not set by default |
|
|
146
|
+
| `:link-appendix:` | mode | Render task links as a real list below the chart. Values: `list` (bullet list), `footnote` (real RST auto-numbered footnotes — LaTeX `\footnote` in PDF), `off` (disable). Bare flag → `list`. Overrides the global `doxtr_roadmap_link_appendix` for this chart. |
|
|
147
|
+
| `:link-appendix-title:` | string | Heading text placed above the link appendix. Overrides `doxtr_roadmap_link_appendix_title` for this chart. |
|
|
148
|
+
| `:caption:` | string | Caption text; presence wraps the chart in a `nodes.figure` so it appears in the List of Figures and can be cross-referenced. |
|
|
149
|
+
| `:align:` | `left`\|`center`\|`right` | Horizontal alignment of the figure; also triggers figure wrapping even without `:caption:`. |
|
|
150
|
+
| `:name:` | string | Cross-reference target for the figure (e.g. `:numref:\`my-fig\`` or `:ref:\`my-fig\``). Requires `:caption:` or `:align:` to produce a figure node. |
|
|
151
|
+
|
|
152
|
+
### Period zoom
|
|
153
|
+
|
|
154
|
+
A "period" is any named task in the CSV (typically a sprint or increment row).
|
|
155
|
+
Specifying `:period: Set27-01` clips the diagram to exactly that task's
|
|
156
|
+
date range. Multiple periods are comma-separated:
|
|
157
|
+
|
|
158
|
+
```rst
|
|
159
|
+
.. roadmap::
|
|
160
|
+
:period: Set27-01, Set27-04
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
When exactly one distinct period is rendered and `:scale:` is not set, the
|
|
164
|
+
extension automatically switches to `daily` scale and closes weekends.
|
|
165
|
+
|
|
166
|
+
### Tag filter
|
|
167
|
+
|
|
168
|
+
Uses the same nested-bracket syntax as `sphinxcontrib.xlink`:
|
|
169
|
+
|
|
170
|
+
```rst
|
|
171
|
+
.. roadmap::
|
|
172
|
+
:tags: eng [ backend !! ], public
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Rows are included if at least one of their tags satisfies the filter tree.
|
|
176
|
+
`!tag` hides a tag; `!!` cascades to children.
|
|
177
|
+
|
|
178
|
+
### Query filter
|
|
179
|
+
|
|
180
|
+
A Python expression evaluated per row with safe builtins:
|
|
181
|
+
|
|
182
|
+
```rst
|
|
183
|
+
.. roadmap::
|
|
184
|
+
:query: "eng" in tags and end > start
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Available variables: `name`, `start` (date), `end` (date), `section`, `tags`
|
|
188
|
+
(set), `row_group`, `match(pattern, string)` (safe regex helper — returns
|
|
189
|
+
`bool(re.search(pattern, string))` without exposing the `re` module).
|
|
190
|
+
|
|
191
|
+
Safe builtins: `any`, `all`, `bool`, `set`, `len`.
|
|
192
|
+
|
|
193
|
+
## Configuration
|
|
194
|
+
|
|
195
|
+
All config values are prefixed `doxtr_roadmap_` and set in `conf.py`:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
doxtr_roadmap_default_scale = "monthly" # daily | weekly | monthly
|
|
199
|
+
doxtr_roadmap_scale_factor = 1.25 # PlantUML diagram scale
|
|
200
|
+
doxtr_roadmap_default_start = None # ISO date or None (→ today)
|
|
201
|
+
doxtr_roadmap_default_title = "Roadmap"
|
|
202
|
+
doxtr_roadmap_clean_style = True # hide start/end/duration columns — default True; requires PlantUML V1.2026.7+
|
|
203
|
+
doxtr_roadmap_close_weekends_on_single_period = True
|
|
204
|
+
|
|
205
|
+
doxtr_roadmap_bar = {
|
|
206
|
+
"done_color": "#FF8C00",
|
|
207
|
+
"undone_color": "#FFF3E0",
|
|
208
|
+
"frame_color": None,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
doxtr_roadmap_sections = {
|
|
212
|
+
"My Section": {
|
|
213
|
+
"done": "#1976D2",
|
|
214
|
+
"frame": None,
|
|
215
|
+
"frame_overrides": {"Special Task": "#E53935"},
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
doxtr_roadmap_today = {"color": "#E53935"}
|
|
220
|
+
|
|
221
|
+
doxtr_roadmap_fonts = {
|
|
222
|
+
"title": {"name": None, "size": 24, "style": "bold", "color": None},
|
|
223
|
+
"task": {"name": None, "size": 14, "style": None, "color": None},
|
|
224
|
+
"separator": {"name": None, "size": 16, "style": "bold", "color": None},
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
doxtr_roadmap_closed = {"background_color": None}
|
|
228
|
+
|
|
229
|
+
# PlantUML version check (default: fail build if PlantUML < v1.2026.7)
|
|
230
|
+
# Values: "error" (default) | "warn" | "off" / False
|
|
231
|
+
# See [PlantUML Version](#plantuml-version) section.
|
|
232
|
+
doxtr_roadmap_require_plantuml_version = "error"
|
|
233
|
+
|
|
234
|
+
# Collision detection (default: True — split same-row-group tasks that collide)
|
|
235
|
+
doxtr_roadmap_collision_detection = True
|
|
236
|
+
doxtr_roadmap_collision_char_width_factor = 1.0 # label-width tuning knob
|
|
237
|
+
doxtr_roadmap_collision_gap_days = 2 # minimum gap between tasks on a lane
|
|
238
|
+
|
|
239
|
+
# Column zoom — widen each gantt time column (default 1 = unchanged)
|
|
240
|
+
doxtr_roadmap_column_zoom = 1
|
|
241
|
+
|
|
242
|
+
# Link appendix — render task links as a list below the chart.
|
|
243
|
+
# Defaults to "list" but only for PDF/latex (see builders below); set to
|
|
244
|
+
# False to disable it everywhere including PDF.
|
|
245
|
+
doxtr_roadmap_link_appendix = "list" # "list" | "footnote" | False
|
|
246
|
+
doxtr_roadmap_link_appendix_builders = ["latex"] # default: PDF only
|
|
247
|
+
doxtr_roadmap_link_appendix_title = "Links"
|
|
248
|
+
|
|
249
|
+
# Figure / List-of-Figures (default off)
|
|
250
|
+
# Set True to wrap every roadmap as a numbered figure automatically.
|
|
251
|
+
doxtr_roadmap_figure = False
|
|
252
|
+
# Optional default caption when doxtr_roadmap_figure=True and no :caption: given.
|
|
253
|
+
# None → use the chart title as the caption.
|
|
254
|
+
doxtr_roadmap_figure_caption = None
|
|
255
|
+
|
|
256
|
+
# Tag allow-lists (optional)
|
|
257
|
+
doxtr_roadmap_allowed_tags = {
|
|
258
|
+
"eng": "Engineering",
|
|
259
|
+
"code": "Code",
|
|
260
|
+
"security": "Security",
|
|
261
|
+
}
|
|
262
|
+
doxtr_roadmap_allowed_tag_patterns = {}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Theme-core integration
|
|
266
|
+
|
|
267
|
+
When `doxtr_pdf_theme_core` is in `extensions`, the roadmap extension
|
|
268
|
+
automatically reads its semantic palette and typography:
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
doxtr_roadmap_use_theme_core = "auto" # "auto" | True | False
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
| Palette key | Maps to |
|
|
275
|
+
|--------------|----------------------|
|
|
276
|
+
| `primary` | bar `done_color` |
|
|
277
|
+
| `secondary` | today line `color` |
|
|
278
|
+
| `main_font` | task font name |
|
|
279
|
+
| `sans_font` | separator font name |
|
|
280
|
+
|
|
281
|
+
User-configured `doxtr_roadmap_*` values always win over theme-core.
|
|
282
|
+
|
|
283
|
+
### xlink integration
|
|
284
|
+
|
|
285
|
+
When `sphinxcontrib.xlink` is in `extensions`, the `link` CSV column accepts
|
|
286
|
+
`:xlink:\`id\`` role expressions that are resolved against the project's
|
|
287
|
+
`.xlink` files. The resolved URL and title are emitted as a PlantUML hyperlink:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
[Task] links to [[https://... Resolved Title]]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
If xlink is not loaded, xlink-style cells produce a one-time warning and the
|
|
294
|
+
link is silently skipped.
|
|
295
|
+
|
|
296
|
+
## Figures and the List of Figures
|
|
297
|
+
|
|
298
|
+
To render a roadmap as a **numbered figure** that appears in the List of
|
|
299
|
+
Figures (`\listoffigures` in PDF, or via Sphinx's `numfig` feature in HTML),
|
|
300
|
+
add a `:caption:` to the directive:
|
|
301
|
+
|
|
302
|
+
```rst
|
|
303
|
+
.. roadmap::
|
|
304
|
+
:caption: Q1 Sprint Roadmap
|
|
305
|
+
:name: fig-q1-sprint
|
|
306
|
+
:align: center
|
|
307
|
+
:start: 2026-01-01
|
|
308
|
+
|
|
309
|
+
section,name,start,end,row_group,link,tags
|
|
310
|
+
Work,Task A,2026-01-01,2026-03-31,,,
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
With `numfig = True` in `conf.py`, Sphinx numbers the figure automatically
|
|
314
|
+
("Fig. 1", "Fig. 2", …) and you can cross-reference it:
|
|
315
|
+
|
|
316
|
+
```rst
|
|
317
|
+
See :numref:`fig-q1-sprint` for the full timeline.
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Caption default.** When a roadmap is rendered as a figure, the caption text
|
|
321
|
+
follows this precedence:
|
|
322
|
+
|
|
323
|
+
1. Explicit `:caption:` option — highest priority (used verbatim).
|
|
324
|
+
2. `doxtr_roadmap_figure_caption` if non-empty — global override.
|
|
325
|
+
3. The chart `:title:` (or `doxtr_roadmap_default_title`) — default.
|
|
326
|
+
|
|
327
|
+
This means that an `:align:`-only wrap (no explicit `:caption:`) now also
|
|
328
|
+
gets the chart title as its caption, making the roadmap appear in the List
|
|
329
|
+
of Figures without any extra configuration.
|
|
330
|
+
|
|
331
|
+
### Options
|
|
332
|
+
|
|
333
|
+
| Option | Description |
|
|
334
|
+
|--------|-------------|
|
|
335
|
+
| `:caption:` | Caption text; presence wraps the chart in a `nodes.figure` so it appears in the List of Figures. |
|
|
336
|
+
| `:align:` | `left`, `center`, or `right`; also triggers figure wrapping with the chart title as the default caption. |
|
|
337
|
+
| `:name:` | Cross-reference target (`:numref:` / `:ref:`). |
|
|
338
|
+
|
|
339
|
+
### Making all roadmaps figures automatically
|
|
340
|
+
|
|
341
|
+
Set `doxtr_roadmap_figure = True` in `conf.py` to wrap **every** roadmap as a
|
|
342
|
+
figure without adding `:caption:` to each directive. The chart's `:title:`
|
|
343
|
+
becomes the caption by default:
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
# conf.py
|
|
347
|
+
doxtr_roadmap_figure = True
|
|
348
|
+
# Optional: override the default caption text for all auto-wrapped figures.
|
|
349
|
+
# None (default) → use each chart's :title: as the caption.
|
|
350
|
+
doxtr_roadmap_figure_caption = None
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
When `doxtr_roadmap_figure_caption` is set to a non-empty string, that string
|
|
354
|
+
is used verbatim as the caption for every roadmap that does not carry its own
|
|
355
|
+
per-directive `:caption:`.
|
|
356
|
+
|
|
357
|
+
### numfig and the List of Figures
|
|
358
|
+
|
|
359
|
+
- Enable `numfig = True` in `conf.py` for "Figure N" numbering and
|
|
360
|
+
`:numref:` cross-references.
|
|
361
|
+
- The HTML builder does not generate a standalone List of Figures page by
|
|
362
|
+
default; use a `.. contents::` directive or an additional index page.
|
|
363
|
+
- The **LaTeX/PDF builder** emits `\begin{figure}...\caption{...}\end{figure}`
|
|
364
|
+
for every captioned roadmap, which feeds into `\listoffigures` automatically
|
|
365
|
+
when your LaTeX preamble includes it.
|
|
366
|
+
- If `doxtr_pdf_theme_core` is in use, its `doxtr_globals` `show_list_of_figures`
|
|
367
|
+
key controls whether `\listoffigures` is emitted in the generated PDF.
|
|
368
|
+
|
|
369
|
+
## Link appendix
|
|
370
|
+
|
|
371
|
+
Links embedded inside the PlantUML image are **not clickable in PDF/LaTeX
|
|
372
|
+
output** — the image is a static graphic with no active hyperlink areas. The
|
|
373
|
+
link appendix feature solves this by rendering task links as real, clickable
|
|
374
|
+
docutils nodes placed *after* the chart image.
|
|
375
|
+
|
|
376
|
+
By default the appendix is **on for PDF/LaTeX output** (rendered as a bullet
|
|
377
|
+
list) and **off for every other builder** (HTML, epub, etc.), whose image
|
|
378
|
+
links are already clickable. It is controlled by three config values:
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
# conf.py
|
|
382
|
+
|
|
383
|
+
# Appendix mode. Defaults to "list"; the builder restriction below limits it
|
|
384
|
+
# to PDF by default. Set to False to disable it everywhere (including PDF).
|
|
385
|
+
doxtr_roadmap_link_appendix = "list" # "list" | "footnote" | False
|
|
386
|
+
|
|
387
|
+
# Which builders render the appendix. Checked against builder.name AND
|
|
388
|
+
# builder.format. Default ["latex"] → PDF only. Use "all" (or ["*"]) for
|
|
389
|
+
# every builder, or e.g. ["latex", "epub"] to add more.
|
|
390
|
+
doxtr_roadmap_link_appendix_builders = ["latex"] # default: PDF only
|
|
391
|
+
|
|
392
|
+
# Heading shown above the list (empty string → no heading)
|
|
393
|
+
doxtr_roadmap_link_appendix_title = "Links" # default
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
To turn the appendix off for PDF as well, set
|
|
397
|
+
``doxtr_roadmap_link_appendix = False`` (or ``:link-appendix: off`` on an
|
|
398
|
+
individual chart). To also show it in HTML/epub, add those builders to
|
|
399
|
+
``doxtr_roadmap_link_appendix_builders`` (or use ``"all"``).
|
|
400
|
+
|
|
401
|
+
**Mode `"list"`** renders a `nodes.bullet_list`; each item is
|
|
402
|
+
`<Task Name>: <clickable link>`. **Mode `"footnote"`** renders real
|
|
403
|
+
reStructuredText auto-numbered footnotes. In PDF/LaTeX output Sphinx's LaTeX
|
|
404
|
+
writer emits these as page-bottom `\footnote{}` commands. In HTML they
|
|
405
|
+
render as standard numbered footnotes with back-references.
|
|
406
|
+
|
|
407
|
+
**Footnote mode with a figure caption.** When the roadmap is rendered as a
|
|
408
|
+
figure (via `:caption:`, `:align:`, or `doxtr_roadmap_figure = True`) *and*
|
|
409
|
+
`link_appendix = "footnote"` *and* the builder is in `link_appendix_builders`,
|
|
410
|
+
the footnote links are embedded **compactly inside the figure caption** instead
|
|
411
|
+
of a separate "Links" block below the chart. The caption shows a single
|
|
412
|
+
label word (the `link_appendix_title`, default `"Links"`) followed by one
|
|
413
|
+
auto-numbered footnote marker per link:
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
<caption text> (Links [1], [2])
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
For example, with `numfig = True`: `Fig. 13.19: Projects with Links (Links⁹,¹⁰)`.
|
|
420
|
+
|
|
421
|
+
Each footnote body carries the task name, the link title (when available),
|
|
422
|
+
and the URL:
|
|
423
|
+
|
|
424
|
+
```
|
|
425
|
+
[1] API Redesign: https://example.com/api ← plain URL, no title
|
|
426
|
+
[2] Sphinx Migration >> Sphinx Docs: https://... ← xlink with resolved title
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
The footnote definitions are emitted as sibling nodes after the figure. The
|
|
430
|
+
separate "Links" heading/container is **not** emitted in this case. If there
|
|
431
|
+
are no resolvable links the caption is the plain title with no brackets.
|
|
432
|
+
|
|
433
|
+
`"list"` mode always produces the standalone bullet list regardless of whether
|
|
434
|
+
a figure is present — list links are not compact enough for a caption.
|
|
435
|
+
|
|
436
|
+
The same source produces an image-only HTML page and an image-plus-appendix
|
|
437
|
+
PDF page — no per-format conditionals needed.
|
|
438
|
+
|
|
439
|
+
Per-directive overrides (`:link-appendix:` and `:link-appendix-title:`) let
|
|
440
|
+
you enable, change, or disable the appendix for a single chart:
|
|
441
|
+
|
|
442
|
+
```rst
|
|
443
|
+
.. roadmap::
|
|
444
|
+
:file: roadmap.csv
|
|
445
|
+
:link-appendix: footnote
|
|
446
|
+
:link-appendix-title: External References
|
|
447
|
+
|
|
448
|
+
.. roadmap::
|
|
449
|
+
:file: roadmap.csv
|
|
450
|
+
:link-appendix: off ← disable even when globally enabled
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
A bare `:link-appendix:` flag (no value) defaults to `"list"`.
|
|
454
|
+
|
|
455
|
+
Tasks with no `link` cell, or whose link cell does not resolve, are silently
|
|
456
|
+
skipped. If no tasks have resolvable links, no container or heading is
|
|
457
|
+
appended.
|
|
458
|
+
|
|
459
|
+
## PlantUML Version
|
|
460
|
+
|
|
461
|
+
### Minimum version requirement — v1.2026.7
|
|
462
|
+
|
|
463
|
+
The extension requires **PlantUML v1.2026.7 or newer** for full feature
|
|
464
|
+
support (see [release notes](https://github.com/plantuml/plantuml/releases/tag/v1.2026.7)).
|
|
465
|
+
At startup (`builder-inited`) the extension runs `plantuml -version` and
|
|
466
|
+
compares the result against the minimum tuple `(1, 2026, 7)`.
|
|
467
|
+
|
|
468
|
+
The check behaviour is controlled by the `doxtr_roadmap_require_plantuml_version`
|
|
469
|
+
config value:
|
|
470
|
+
|
|
471
|
+
| Value | Effect |
|
|
472
|
+
|-------|--------|
|
|
473
|
+
| `"error"` (default) | An `ExtensionError` is raised, aborting the build if the version is below the minimum. |
|
|
474
|
+
| `"warn"` | A `WARNING` is emitted if the installed version is below the minimum; the build continues normally. |
|
|
475
|
+
| `"off"` / `False` | The check is skipped entirely; no subprocess call is made. |
|
|
476
|
+
|
|
477
|
+
```python
|
|
478
|
+
# conf.py
|
|
479
|
+
# Default — fail the build if PlantUML is below v1.2026.7:
|
|
480
|
+
doxtr_roadmap_require_plantuml_version = "error"
|
|
481
|
+
|
|
482
|
+
# Lenient — warn but never fail the build:
|
|
483
|
+
doxtr_roadmap_require_plantuml_version = "warn"
|
|
484
|
+
|
|
485
|
+
# Opt out — skip the check entirely:
|
|
486
|
+
doxtr_roadmap_require_plantuml_version = "off"
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
If the PlantUML binary cannot be found or its version output is unrecognisable,
|
|
490
|
+
an informational message is logged and the build continues regardless of the
|
|
491
|
+
setting — the check never crashes a build over an undeterminable version.
|
|
492
|
+
|
|
493
|
+
`[Display] as [pid]` same-name-distinct-bar support requires **PlantUML
|
|
494
|
+
V1.2024.6 or newer**. Older versions will silently merge tasks that share a
|
|
495
|
+
display name (e.g. duplicate period rows).
|
|
496
|
+
|
|
497
|
+
### `clean_style` and the `hide column` directives
|
|
498
|
+
|
|
499
|
+
`doxtr_roadmap_clean_style = True` hides the per-task **Start**, **End**, and
|
|
500
|
+
**Duration** columns in the rendered Gantt table. This is especially important
|
|
501
|
+
when `row_group` same-row grouping is used: without it the date stamps from
|
|
502
|
+
multiple tasks sharing a row overlap and become unreadable.
|
|
503
|
+
|
|
504
|
+
`clean_style` **defaults to `True`** because PlantUML v1.2026.7 is the
|
|
505
|
+
extension's minimum baseline and fully supports the `hide column
|
|
506
|
+
start/end/duration` syntax.
|
|
507
|
+
|
|
508
|
+
To disable it globally:
|
|
509
|
+
|
|
510
|
+
```python
|
|
511
|
+
# conf.py
|
|
512
|
+
doxtr_roadmap_clean_style = False
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
The `:clean-style:` directive option overrides the global setting per
|
|
516
|
+
directive instance:
|
|
517
|
+
|
|
518
|
+
```rst
|
|
519
|
+
.. roadmap:: # bare flag or explicit true — enables clean_style
|
|
520
|
+
:clean-style:
|
|
521
|
+
:file: roadmap.csv
|
|
522
|
+
|
|
523
|
+
.. roadmap:: # explicit false — disables clean_style for this block
|
|
524
|
+
:clean-style: false
|
|
525
|
+
:file: roadmap.csv
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
## Collision detection
|
|
530
|
+
|
|
531
|
+
When two or more tasks share a `row_group`, PlantUML draws their text labels
|
|
532
|
+
starting at (or across) their bars. If the bars overlap in time, or if an
|
|
533
|
+
earlier bar's label is long enough to overrun rightward into a later bar, the
|
|
534
|
+
labels collide and become unreadable.
|
|
535
|
+
|
|
536
|
+
By default, the extension detects these collisions and automatically splits
|
|
537
|
+
tasks within a `row_group` onto as few additional rows as needed so that no
|
|
538
|
+
two tasks on the same row would have overlapping labels. Tasks that fit
|
|
539
|
+
together stay together (no unnecessary splits); only tasks that would collide
|
|
540
|
+
are moved to a new row. This preserves the space-saving intent of `row_group`
|
|
541
|
+
while keeping text readable.
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
# conf.py
|
|
545
|
+
|
|
546
|
+
# Default True — split same-row-group tasks onto extra rows when they collide.
|
|
547
|
+
doxtr_roadmap_collision_detection = True
|
|
548
|
+
|
|
549
|
+
# Set False to force ALL same-row-group tasks onto one row regardless of
|
|
550
|
+
# overlap (for users who deliberately want overlap / the old behaviour).
|
|
551
|
+
doxtr_roadmap_collision_detection = False
|
|
552
|
+
|
|
553
|
+
# Tuning knob: higher value reserves more space per character → splits sooner.
|
|
554
|
+
# Default 1.0 corresponds to the calibrated base days-per-character.
|
|
555
|
+
doxtr_roadmap_collision_char_width_factor = 1.0
|
|
556
|
+
|
|
557
|
+
# Minimum gap (calendar days) between adjacent tasks on the same lane.
|
|
558
|
+
doxtr_roadmap_collision_gap_days = 2
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
The `:collision-detection:` directive option overrides the global setting for
|
|
562
|
+
a single chart:
|
|
563
|
+
|
|
564
|
+
```rst
|
|
565
|
+
.. roadmap:: # detection on for this chart only
|
|
566
|
+
:collision-detection: true
|
|
567
|
+
:file: roadmap.csv
|
|
568
|
+
|
|
569
|
+
.. roadmap:: # detection off — force overlap for this chart
|
|
570
|
+
:collision-detection: false
|
|
571
|
+
:file: roadmap.csv
|
|
572
|
+
|
|
573
|
+
.. roadmap:: # widen label estimate for this chart
|
|
574
|
+
:collision-char-width-factor: 1.5
|
|
575
|
+
:file: roadmap.csv
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
The detection algorithm estimates each label's horizontal footprint using a
|
|
579
|
+
per-scale days-per-character mapping (`daily` ≈ 1.1, `weekly` ≈ 4, `monthly`
|
|
580
|
+
≈ 9), multiplied by `collision_char_width_factor`. Within each `row_group`
|
|
581
|
+
tasks are packed into lanes using a greedy first-fit strategy: each task is
|
|
582
|
+
placed on the first lane whose last task's footprint does not overlap; if all
|
|
583
|
+
lanes are blocked, a new lane is opened. Different lanes render as separate
|
|
584
|
+
Gantt rows.
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
## Column width (zoom)
|
|
588
|
+
|
|
589
|
+
By default PlantUML sizes Gantt columns compactly. On wide pages the chart
|
|
590
|
+
may not use the full available width, resulting in a horizontally compressed
|
|
591
|
+
look — especially on monthly or weekly scale.
|
|
592
|
+
|
|
593
|
+
The `doxtr_roadmap_column_zoom` config value (default `1`) multiplies the
|
|
594
|
+
width of each time column by appending `zoom <factor>` to the PlantUML
|
|
595
|
+
`projectscale` line. A value of `1` (or absent) produces the current
|
|
596
|
+
unchanged behaviour. Example:
|
|
597
|
+
|
|
598
|
+
```python
|
|
599
|
+
# conf.py — make each month column 3× wider
|
|
600
|
+
doxtr_roadmap_column_zoom = 3
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
The `:column-zoom:` directive option overrides the global setting per chart:
|
|
604
|
+
|
|
605
|
+
```rst
|
|
606
|
+
.. roadmap::
|
|
607
|
+
:column-zoom: 3
|
|
608
|
+
:file: roadmap.csv
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
The `:width:` directive option (e.g. `:width: 100%`) forces the rendered
|
|
612
|
+
image to fill the available text/page width in HTML and PDF. This is handled
|
|
613
|
+
by `sphinxcontrib.plantuml` (maps to an HTML `style="width:100%"` attribute
|
|
614
|
+
or a LaTeX `adjustbox` width). By default no width is set (current
|
|
615
|
+
behaviour).
|
|
616
|
+
|
|
617
|
+
```rst
|
|
618
|
+
.. roadmap::
|
|
619
|
+
:column-zoom: 3
|
|
620
|
+
:width: 100%
|
|
621
|
+
:file: roadmap.csv
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
Combining both options gives full control: `:column-zoom:` widens each source
|
|
625
|
+
column so the chart is drawn at the desired detail level, and `:width: 100%`
|
|
626
|
+
stretches the resulting image to fill the page.
|
|
627
|
+
|
|
628
|
+
> **PlantUML version note:** The `zoom <factor>` keyword form requires
|
|
629
|
+
> PlantUML v1.2026.7 or newer — already the extension's minimum baseline.
|
|
630
|
+
> The older `projectscale monthly 3` form (no `zoom` keyword) errors on
|
|
631
|
+
> v1.2026.7 and is never emitted by this extension.
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
## Development
|
|
635
|
+
|
|
636
|
+
```bash
|
|
637
|
+
git clone https://github.com/doxtr/doxtr-roadmap
|
|
638
|
+
cd doxtr-roadmap
|
|
639
|
+
pip install -e ".[dev]"
|
|
640
|
+
pip install sphinxcontrib-plantuml
|
|
641
|
+
python -m pytest tests/ -v
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
Run the Sphinx HTML smoke-build:
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
cd test_harness
|
|
648
|
+
python test_runner.py
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
## License
|
|
652
|
+
|
|
653
|
+
MIT
|