doxtr-doto 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_doto-0.1.0/.gitignore +77 -0
- doxtr_doto-0.1.0/LICENSE +21 -0
- doxtr_doto-0.1.0/PKG-INFO +603 -0
- doxtr_doto-0.1.0/README.md +546 -0
- doxtr_doto-0.1.0/pyproject.toml +99 -0
- doxtr_doto-0.1.0/src/doxtr_doto/__init__.py +567 -0
- doxtr_doto-0.1.0/src/doxtr_doto/builders/__init__.py +22 -0
- doxtr_doto-0.1.0/src/doxtr_doto/builders/archive_doc.py +222 -0
- doxtr_doto-0.1.0/src/doxtr_doto/charts.py +1344 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/__init__.py +5 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/__init__.py +49 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/add.py +630 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/archive.py +111 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/completion.py +176 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/config.py +116 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/delete.py +357 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/deps.py +336 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/done.py +64 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/export.py +232 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/git.py +234 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/init.py +214 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/list.py +360 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/next.py +306 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/reopen.py +85 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/resolve.py +189 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/search.py +170 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/series.py +404 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/show.py +54 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/stats.py +238 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/tree.py +341 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/commands/update.py +543 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/completion.py +307 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/config.py +447 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/json_store.py +23 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/main.py +146 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/output.py +464 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/recurrence.py +374 -0
- doxtr_doto-0.1.0/src/doxtr_doto/cli/validators.py +110 -0
- doxtr_doto-0.1.0/src/doxtr_doto/collectors/__init__.py +708 -0
- doxtr_doto-0.1.0/src/doxtr_doto/config.py +195 -0
- doxtr_doto-0.1.0/src/doxtr_doto/constants.py +103 -0
- doxtr_doto-0.1.0/src/doxtr_doto/date_utils.py +384 -0
- doxtr_doto-0.1.0/src/doxtr_doto/directives/__init__.py +14 -0
- doxtr_doto-0.1.0/src/doxtr_doto/directives/doto.py +351 -0
- doxtr_doto-0.1.0/src/doxtr_doto/directives/doto_list.py +427 -0
- doxtr_doto-0.1.0/src/doxtr_doto/directives/doto_summary.py +250 -0
- doxtr_doto-0.1.0/src/doxtr_doto/domain.py +312 -0
- doxtr_doto-0.1.0/src/doxtr_doto/enums.py +69 -0
- doxtr_doto-0.1.0/src/doxtr_doto/exceptions.py +96 -0
- doxtr_doto-0.1.0/src/doxtr_doto/fields.py +183 -0
- doxtr_doto-0.1.0/src/doxtr_doto/hooks.py +278 -0
- doxtr_doto-0.1.0/src/doxtr_doto/integration/__init__.py +30 -0
- doxtr_doto-0.1.0/src/doxtr_doto/integration/doxtr.py +402 -0
- doxtr_doto-0.1.0/src/doxtr_doto/nodes.py +1429 -0
- doxtr_doto-0.1.0/src/doxtr_doto/query.py +174 -0
- doxtr_doto-0.1.0/src/doxtr_doto/regex_utils.py +203 -0
- doxtr_doto-0.1.0/src/doxtr_doto/roles/__init__.py +8 -0
- doxtr_doto-0.1.0/src/doxtr_doto/roles/doto_ref.py +119 -0
- doxtr_doto-0.1.0/src/doxtr_doto/sync/__init__.py +705 -0
- doxtr_doto-0.1.0/src/doxtr_doto/sync/conflict.py +116 -0
- doxtr_doto-0.1.0/src/doxtr_doto/sync/hash.py +67 -0
- doxtr_doto-0.1.0/src/doxtr_doto/sync/json_store.py +967 -0
- doxtr_doto-0.1.0/src/doxtr_doto/sync/merge.py +229 -0
- doxtr_doto-0.1.0/src/doxtr_doto/sync/rst_writer.py +724 -0
- doxtr_doto-0.1.0/src/doxtr_doto/template_loader.py +461 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/styles/critical.yaml +9 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/styles/default.yaml +21 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/styles/high.yaml +8 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/styles/low.yaml +8 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/styles/medium.yaml +8 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/styles/minimal.yaml +16 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/doxtr/task.tex.jinja +14 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/html/doto-list-cards.html +36 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/html/doto-list-simple.html +24 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/html/doto-list-table.html +59 -0
- doxtr_doto-0.1.0/src/doxtr_doto/templates/html/doto.html +46 -0
- doxtr_doto-0.1.0/src/doxtr_doto/themes/epub/doto-minimal.css +62 -0
- doxtr_doto-0.1.0/src/doxtr_doto/themes/epub/doto.css +246 -0
- doxtr_doto-0.1.0/src/doxtr_doto/themes/html/doto-minimal.css +112 -0
- doxtr_doto-0.1.0/src/doxtr_doto/themes/html/doto.css +716 -0
- doxtr_doto-0.1.0/src/doxtr_doto/themes/latex/doto-minimal.sty +51 -0
- doxtr_doto-0.1.0/src/doxtr_doto/themes/latex/doto.sty +351 -0
- doxtr_doto-0.1.0/src/doxtr_doto/transforms/__init__.py +11 -0
- doxtr_doto-0.1.0/src/doxtr_doto/transforms/archive.py +157 -0
- doxtr_doto-0.1.0/src/doxtr_doto/transforms/toc_inject.py +50 -0
- doxtr_doto-0.1.0/src/doxtr_doto/types.py +132 -0
- doxtr_doto-0.1.0/src/doxtr_doto/utils.py +366 -0
- doxtr_doto-0.1.0/tests/cli/__init__.py +1 -0
- doxtr_doto-0.1.0/tests/cli/test_add_helpers.py +401 -0
- doxtr_doto-0.1.0/tests/cli/test_archive.py +213 -0
- doxtr_doto-0.1.0/tests/cli/test_commands.py +2748 -0
- doxtr_doto-0.1.0/tests/cli/test_delete.py +405 -0
- doxtr_doto-0.1.0/tests/cli/test_git.py +354 -0
- doxtr_doto-0.1.0/tests/cli/test_init.py +196 -0
- doxtr_doto-0.1.0/tests/cli/test_next.py +462 -0
- doxtr_doto-0.1.0/tests/cli/test_output.py +194 -0
- doxtr_doto-0.1.0/tests/cli/test_recurrence.py +552 -0
- doxtr_doto-0.1.0/tests/cli/test_recurring_limits.py +221 -0
- doxtr_doto-0.1.0/tests/cli/test_reopen.py +207 -0
- doxtr_doto-0.1.0/tests/cli/test_resolve.py +269 -0
- doxtr_doto-0.1.0/tests/cli/test_series.py +516 -0
- doxtr_doto-0.1.0/tests/cli/test_standalone_mode.py +292 -0
- doxtr_doto-0.1.0/tests/cli/test_stats.py +345 -0
- doxtr_doto-0.1.0/tests/conftest.py +222 -0
- doxtr_doto-0.1.0/tests/sync/__init__.py +1 -0
- doxtr_doto-0.1.0/tests/sync/test_conflict_detection.py +418 -0
- doxtr_doto-0.1.0/tests/sync/test_conflict_formatting.py +347 -0
- doxtr_doto-0.1.0/tests/sync/test_json_store.py +154 -0
- doxtr_doto-0.1.0/tests/sync/test_json_store_refactor.py +478 -0
- doxtr_doto-0.1.0/tests/sync/test_reopen.py +302 -0
- doxtr_doto-0.1.0/tests/sync/test_rst_batching.py +442 -0
- doxtr_doto-0.1.0/tests/sync/test_rst_insertion.py +209 -0
- doxtr_doto-0.1.0/tests/sync/test_rst_removal.py +399 -0
- doxtr_doto-0.1.0/tests/sync/test_rst_writer_edge_cases.py +297 -0
- doxtr_doto-0.1.0/tests/sync/test_sync_error_handling.py +297 -0
- doxtr_doto-0.1.0/tests/sync/test_three_way_merge.py +184 -0
- doxtr_doto-0.1.0/tests/test_archive_doc.py +358 -0
- doxtr_doto-0.1.0/tests/test_auto_archive.py +387 -0
- doxtr_doto-0.1.0/tests/test_charts.py +863 -0
- doxtr_doto-0.1.0/tests/test_config.py +469 -0
- doxtr_doto-0.1.0/tests/test_config_features.py +340 -0
- doxtr_doto-0.1.0/tests/test_date_utils.py +499 -0
- doxtr_doto-0.1.0/tests/test_directive_doto.py +183 -0
- doxtr_doto-0.1.0/tests/test_directive_doto_list.py +270 -0
- doxtr_doto-0.1.0/tests/test_directive_doto_summary.py +348 -0
- doxtr_doto-0.1.0/tests/test_doto_task_methods.py +434 -0
- doxtr_doto-0.1.0/tests/test_doxtr_integration.py +299 -0
- doxtr_doto-0.1.0/tests/test_enums.py +270 -0
- doxtr_doto-0.1.0/tests/test_export_json.py +274 -0
- doxtr_doto-0.1.0/tests/test_fields.py +422 -0
- doxtr_doto-0.1.0/tests/test_filter_cache.py +471 -0
- doxtr_doto-0.1.0/tests/test_graceful_degradation.py +589 -0
- doxtr_doto-0.1.0/tests/test_hooks.py +477 -0
- doxtr_doto-0.1.0/tests/test_integration_doxtr.py +196 -0
- doxtr_doto-0.1.0/tests/test_integration_doxtr_pure.py +134 -0
- doxtr_doto-0.1.0/tests/test_output_epub.py +254 -0
- doxtr_doto-0.1.0/tests/test_output_html.py +675 -0
- doxtr_doto-0.1.0/tests/test_output_latex.py +405 -0
- doxtr_doto-0.1.0/tests/test_parallel_build.py +409 -0
- doxtr_doto-0.1.0/tests/test_progress.py +537 -0
- doxtr_doto-0.1.0/tests/test_query.py +509 -0
- doxtr_doto-0.1.0/tests/test_regex_utils.py +297 -0
- doxtr_doto-0.1.0/tests/test_role_doto.py +174 -0
- doxtr_doto-0.1.0/tests/test_security.py +290 -0
- doxtr_doto-0.1.0/tests/test_template_loader.py +569 -0
- doxtr_doto-0.1.0/tests/test_theme_selection.py +93 -0
- doxtr_doto-0.1.0/tests/test_validation_edge_cases.py +367 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
|
|
3
|
+
# Python
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
*.so
|
|
8
|
+
.Python
|
|
9
|
+
build/
|
|
10
|
+
develop-eggs/
|
|
11
|
+
dist/
|
|
12
|
+
downloads/
|
|
13
|
+
eggs/
|
|
14
|
+
.eggs/
|
|
15
|
+
lib/
|
|
16
|
+
lib64/
|
|
17
|
+
parts/
|
|
18
|
+
sdist/
|
|
19
|
+
var/
|
|
20
|
+
wheels/
|
|
21
|
+
*.egg-info/
|
|
22
|
+
.installed.cfg
|
|
23
|
+
*.egg
|
|
24
|
+
|
|
25
|
+
# Testing / coverage
|
|
26
|
+
.coverage
|
|
27
|
+
coverage.xml
|
|
28
|
+
htmlcov/
|
|
29
|
+
.pytest_cache/
|
|
30
|
+
|
|
31
|
+
# Virtual environments
|
|
32
|
+
venv/
|
|
33
|
+
.venv/
|
|
34
|
+
env/
|
|
35
|
+
.env/
|
|
36
|
+
|
|
37
|
+
# Sphinx build artifacts
|
|
38
|
+
*.doctrees
|
|
39
|
+
_source/.doctrees
|
|
40
|
+
|
|
41
|
+
# Generated files
|
|
42
|
+
*.tex
|
|
43
|
+
*.pdf
|
|
44
|
+
*.log
|
|
45
|
+
*.aux
|
|
46
|
+
*.toc
|
|
47
|
+
*.lof
|
|
48
|
+
*.lot
|
|
49
|
+
*.out
|
|
50
|
+
*.ind
|
|
51
|
+
*.idx
|
|
52
|
+
*.ilg
|
|
53
|
+
*.fls
|
|
54
|
+
*.fdb_latexmk
|
|
55
|
+
*.synctex.gz
|
|
56
|
+
|
|
57
|
+
# Test harness build artifacts
|
|
58
|
+
test_harness/build/
|
|
59
|
+
test_harness/source/conf.py
|
|
60
|
+
test_harness/source/_generated_toctree.rst
|
|
61
|
+
|
|
62
|
+
# IDE
|
|
63
|
+
.vscode/
|
|
64
|
+
.idea/
|
|
65
|
+
*.swp
|
|
66
|
+
*.swo
|
|
67
|
+
*~
|
|
68
|
+
|
|
69
|
+
# OS
|
|
70
|
+
.DS_Store
|
|
71
|
+
Thumbs.db
|
|
72
|
+
|
|
73
|
+
# Test assets (generated placeholders)
|
|
74
|
+
test_harness/source/_static/wizard-of-docs*.png
|
|
75
|
+
|
|
76
|
+
# DocDash Docker container
|
|
77
|
+
.DS_Store
|
doxtr_doto-0.1.0/LICENSE
ADDED
|
@@ -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,603 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: doxtr-doto
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Documentation task management for Sphinx
|
|
5
|
+
Project-URL: Homepage, https://github.com/doxtr/doxtr-doto
|
|
6
|
+
Project-URL: Documentation, https://doxtr-doto.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/doxtr/doxtr-doto
|
|
8
|
+
Project-URL: Issues, https://github.com/doxtr/doxtr-doto/issues
|
|
9
|
+
Author: doto contributors
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: documentation,project-management,sphinx,tasks,todo
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Environment :: Plugins
|
|
16
|
+
Classifier: Framework :: Sphinx :: Extension
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: Documentation :: Sphinx
|
|
25
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: sphinx>=7.0
|
|
28
|
+
Provides-Extra: all
|
|
29
|
+
Requires-Dist: click>=8.0; extra == 'all'
|
|
30
|
+
Requires-Dist: jinja2>=3.0; extra == 'all'
|
|
31
|
+
Requires-Dist: kaleido; extra == 'all'
|
|
32
|
+
Requires-Dist: mypy>=1.0; extra == 'all'
|
|
33
|
+
Requires-Dist: plotly>=5; extra == 'all'
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'all'
|
|
35
|
+
Requires-Dist: pytest>=7.0; extra == 'all'
|
|
36
|
+
Requires-Dist: rich>=13.0; extra == 'all'
|
|
37
|
+
Requires-Dist: ruff>=0.1.0; extra == 'all'
|
|
38
|
+
Requires-Dist: tomli-w>=1.0; extra == 'all'
|
|
39
|
+
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'all'
|
|
40
|
+
Provides-Extra: charts
|
|
41
|
+
Requires-Dist: kaleido; extra == 'charts'
|
|
42
|
+
Requires-Dist: plotly>=5; extra == 'charts'
|
|
43
|
+
Provides-Extra: cli
|
|
44
|
+
Requires-Dist: click>=8.0; extra == 'cli'
|
|
45
|
+
Requires-Dist: rich>=13.0; extra == 'cli'
|
|
46
|
+
Requires-Dist: tomli-w>=1.0; extra == 'cli'
|
|
47
|
+
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'cli'
|
|
48
|
+
Provides-Extra: dev
|
|
49
|
+
Requires-Dist: jinja2>=3.0; extra == 'dev'
|
|
50
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
54
|
+
Provides-Extra: templates
|
|
55
|
+
Requires-Dist: jinja2>=3.0; extra == 'templates'
|
|
56
|
+
Description-Content-Type: text/markdown
|
|
57
|
+
|
|
58
|
+
# doxtr-doto - Documentation Task Management for Sphinx
|
|
59
|
+
|
|
60
|
+
**doxtr-doto** (documentation task open) is a Sphinx extension for managing documentation tasks with structured metadata, bidirectional sync with JSON storage, and a companion CLI tool.
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
- **Structured task directives** - Define tasks with priorities, assignees, due dates, tags, and dependencies
|
|
65
|
+
- **Task lists and summaries** - Display filtered, sorted task lists and statistics
|
|
66
|
+
- **Styled PDF task boxes** - Each task renders as a `tcolorbox` with a high-contrast title bar and readable body (no more white-on-white boxes)
|
|
67
|
+
- **Stacked Font Awesome metadata icons** - PDF task boxes stack a semantic FA icon above each metadata label (calendar for due, user for assignee, flag for priority, etc.), degrading gracefully when Font Awesome is unavailable
|
|
68
|
+
- **Task-list icon modes** - Render list cells as Font Awesome icons, icon+text, or text, with clickable task IDs/titles
|
|
69
|
+
- **Cross-references** - Link to tasks with the `:doto:` role; PDF cross-references are clickable hyperlinks that jump to the task box
|
|
70
|
+
- **Bidirectional sync** - Keep RST files and JSON storage in sync with 3-way merge
|
|
71
|
+
- **Auto-archiving** - Automatically archive completed tasks
|
|
72
|
+
- **CLI tool** - Manage tasks from the command line
|
|
73
|
+
- **Theming** - Customizable HTML and LaTeX output
|
|
74
|
+
- **Charts** - Task summaries with built-in SVG charts, or richer [plotly](https://plotly.com/python/) charts (pie, bar, stacked-bar, progress, burndown)
|
|
75
|
+
- **Doxtr integration** - Optional integration with doxtr-pdf-theme-core: semantic-palette-derived task colors and automatic landscape rotation for wide task tables
|
|
76
|
+
|
|
77
|
+
## Installation
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install doxtr-doto
|
|
81
|
+
|
|
82
|
+
# With CLI support
|
|
83
|
+
pip install doxtr-doto[cli]
|
|
84
|
+
|
|
85
|
+
# With plotly charts (pie/bar/stacked-bar/progress/burndown)
|
|
86
|
+
pip install doxtr-doto[charts]
|
|
87
|
+
|
|
88
|
+
# Full installation
|
|
89
|
+
pip install doxtr-doto[all]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The `charts` extra installs `plotly>=5` and `kaleido`. Static image export
|
|
93
|
+
(used for HTML `<img>` charts and PDF `\includegraphics`) additionally requires
|
|
94
|
+
a Chrome/Chromium install for kaleido; when plotly, kaleido, or Chrome are
|
|
95
|
+
unavailable, `doto-summary` automatically falls back to built-in,
|
|
96
|
+
dependency-free charts so the build never breaks:
|
|
97
|
+
|
|
98
|
+
- **HTML** falls back to inline SVG charts.
|
|
99
|
+
- **PDF/LaTeX** falls back to native TikZ charts (`\dotochart*` macros in
|
|
100
|
+
`doto.sty`), so the PDF always renders a real visual chart — no browser or
|
|
101
|
+
kaleido required. A child theme can restyle these by redefining the
|
|
102
|
+
`\dotochart*` macros / `dotochart` environment.
|
|
103
|
+
|
|
104
|
+
## Quick Start
|
|
105
|
+
|
|
106
|
+
1. Add `doxtr_doto` to your Sphinx extensions in `conf.py`:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
extensions = [
|
|
110
|
+
'doxtr_doto',
|
|
111
|
+
]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
2. Create a task in your documentation:
|
|
115
|
+
|
|
116
|
+
```rst
|
|
117
|
+
.. doto:: Implement user authentication
|
|
118
|
+
:id: TASK-001
|
|
119
|
+
:assignee: alice
|
|
120
|
+
:priority: high
|
|
121
|
+
:status: open
|
|
122
|
+
:due: 2026-08-15
|
|
123
|
+
:tags: security, backend
|
|
124
|
+
|
|
125
|
+
Detailed description of the task goes here.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
3. Display a task list:
|
|
129
|
+
|
|
130
|
+
```rst
|
|
131
|
+
.. doto-list::
|
|
132
|
+
:status: open, in-progress
|
|
133
|
+
:sort: priority
|
|
134
|
+
:format: table
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
4. Reference tasks inline:
|
|
138
|
+
|
|
139
|
+
```rst
|
|
140
|
+
This relates to :doto:`TASK-001`.
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Directive Reference
|
|
144
|
+
|
|
145
|
+
### `.. doto::` - Task Definition
|
|
146
|
+
|
|
147
|
+
Creates a task with structured metadata.
|
|
148
|
+
|
|
149
|
+
**Options:**
|
|
150
|
+
|
|
151
|
+
| Option | Type | Default | Description |
|
|
152
|
+
|--------|------|---------|-------------|
|
|
153
|
+
| `:id:` | string | Auto-generated | Unique task identifier |
|
|
154
|
+
| `:assignee:` | string | None | Person responsible |
|
|
155
|
+
| `:priority:` | enum | `medium` | `low`, `medium`, `high`, `critical` |
|
|
156
|
+
| `:status:` | enum | `open` | `open`, `in-progress`, `blocked`, `done` |
|
|
157
|
+
| `:due:` | date | None | Due date (YYYY-MM-DD) |
|
|
158
|
+
| `:tags:` | list | None | Comma-separated categories |
|
|
159
|
+
| `:depends-on:` | list | None | Comma-separated task IDs |
|
|
160
|
+
|
|
161
|
+
### `.. doto-list::` - Task List
|
|
162
|
+
|
|
163
|
+
Displays a filtered list of tasks.
|
|
164
|
+
|
|
165
|
+
**Filter Options:** `:assignee:`, `:priority:`, `:status:`, `:tags:`, `:due-before:`, `:due-after:`, `:exclude-status:`
|
|
166
|
+
|
|
167
|
+
**Display Options:** `:sort:`, `:order:`, `:limit:`, `:format:` (table/list/cards), `:show-archived:`, `:columns:`, `:icon-mode:` (icon/icon-text/text)
|
|
168
|
+
|
|
169
|
+
Task IDs and titles in every list format are clickable links to the task box.
|
|
170
|
+
The `:icon-mode:` option overrides the global `doto_list_icon_mode` config for
|
|
171
|
+
a single directive.
|
|
172
|
+
|
|
173
|
+
```rst
|
|
174
|
+
.. doto-list::
|
|
175
|
+
:format: table
|
|
176
|
+
:columns: id, title, status, priority, assignee
|
|
177
|
+
:icon-mode: icon-text
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### `.. doto-summary::` - Task Statistics
|
|
181
|
+
|
|
182
|
+
Displays task counts grouped by status/priority, optionally with a chart.
|
|
183
|
+
|
|
184
|
+
**Options:** `:group-by:`, `:assignee:`, `:show-chart:`, `:chart-type:`
|
|
185
|
+
|
|
186
|
+
`:chart-type:` accepts `bar`, `pie`, `stacked-bar`, `progress`, and `burndown`.
|
|
187
|
+
The engine is selected by `doto_chart_engine` (`svg` default, or `plotly`).
|
|
188
|
+
|
|
189
|
+
```rst
|
|
190
|
+
.. doto-summary::
|
|
191
|
+
:group-by: status
|
|
192
|
+
:show-chart: true
|
|
193
|
+
:chart-type: pie
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `:doto:` Role
|
|
197
|
+
|
|
198
|
+
Cross-reference to a task: `:doto:`TASK-001`` or `:doto:`TASK-001 <custom text>``
|
|
199
|
+
|
|
200
|
+
## Configuration
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
# conf.py
|
|
204
|
+
|
|
205
|
+
# Core settings
|
|
206
|
+
doto_enabled = True
|
|
207
|
+
doto_include_done = True
|
|
208
|
+
|
|
209
|
+
# JSON store
|
|
210
|
+
doto_json_file = ".doto/tasks.json"
|
|
211
|
+
doto_auto_create_json = True
|
|
212
|
+
|
|
213
|
+
# Auto-archive
|
|
214
|
+
doto_auto_archive = False
|
|
215
|
+
doto_archive_doc = "_doto_archive"
|
|
216
|
+
doto_archive_after_days = 0
|
|
217
|
+
|
|
218
|
+
# Sync settings
|
|
219
|
+
doto_sync_on_build = True
|
|
220
|
+
doto_conflict_action = "error" # or "warn", "prefer-rst", "prefer-json"
|
|
221
|
+
|
|
222
|
+
# Defaults
|
|
223
|
+
doto_default_priority = "medium"
|
|
224
|
+
doto_default_status = "open"
|
|
225
|
+
|
|
226
|
+
# Display
|
|
227
|
+
doto_list_columns = ["id", "priority", "status", "assignee", "due", "title"]
|
|
228
|
+
# Task-list cell rendering: "icon" | "icon-text" | "text" (default "icon-text").
|
|
229
|
+
# "icon" = a Font Awesome icon where one fits the field/value (else text)
|
|
230
|
+
# "icon-text" = icon + text
|
|
231
|
+
# "text" = text only
|
|
232
|
+
# Overridable per directive with :icon-mode:.
|
|
233
|
+
doto_list_icon_mode = "icon-text"
|
|
234
|
+
|
|
235
|
+
# Charts
|
|
236
|
+
# Chart engine for doto-summary: "svg" (default) or "plotly".
|
|
237
|
+
# "svg" = built-in inline-SVG charts, no extra dependencies
|
|
238
|
+
# "plotly" = renders static images via plotly + kaleido; falls back
|
|
239
|
+
# automatically when plotly/kaleido/Chrome are unavailable
|
|
240
|
+
# (inline SVG for HTML output, native TikZ charts for PDF/LaTeX)
|
|
241
|
+
# Requires the [charts] extra when set to "plotly".
|
|
242
|
+
doto_chart_engine = "svg"
|
|
243
|
+
|
|
244
|
+
# Validation
|
|
245
|
+
doto_warn_overdue = True
|
|
246
|
+
doto_required_fields = [] # e.g., ["assignee"]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### CLI Configuration (`.doto.toml`)
|
|
250
|
+
|
|
251
|
+
```toml
|
|
252
|
+
[doto]
|
|
253
|
+
json_file = ".doto/tasks.json"
|
|
254
|
+
id_prefix = "TASK"
|
|
255
|
+
default_priority = "medium"
|
|
256
|
+
default_status = "open"
|
|
257
|
+
|
|
258
|
+
# Customize default columns for 'doto list'
|
|
259
|
+
list_columns = ["id", "title", "status", "priority", "assignee"]
|
|
260
|
+
|
|
261
|
+
# Valid values
|
|
262
|
+
statuses = ["open", "in-progress", "blocked", "done"]
|
|
263
|
+
priorities = ["low", "medium", "high", "critical"]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Environment Variables
|
|
267
|
+
|
|
268
|
+
| Variable | Description |
|
|
269
|
+
|----------|-------------|
|
|
270
|
+
| `DOTO_JSON_FILE` | Path to tasks.json |
|
|
271
|
+
| `DOTO_DEFAULT_PRIORITY` | Default priority for new tasks |
|
|
272
|
+
| `DOTO_DEFAULT_STATUS` | Default status for new tasks |
|
|
273
|
+
| `DOTO_LIST_COLUMNS` | Comma-separated list of columns for `doto list` |
|
|
274
|
+
| `DOTO_COLOR` | Color mode: `auto`, `always`, `never` |
|
|
275
|
+
|
|
276
|
+
## Command-Line Interface
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Initialize doto in a project
|
|
280
|
+
doto init
|
|
281
|
+
|
|
282
|
+
# Enable shell tab completion (bash, zsh, fish)
|
|
283
|
+
doto completion --install
|
|
284
|
+
|
|
285
|
+
# Show current configuration (JSON database path, mode, defaults)
|
|
286
|
+
doto config
|
|
287
|
+
doto config --format json
|
|
288
|
+
|
|
289
|
+
# Add a task
|
|
290
|
+
doto add "Fix authentication bug" --priority high --assignee alice
|
|
291
|
+
|
|
292
|
+
# List tasks
|
|
293
|
+
doto list --status open --format table
|
|
294
|
+
doto list --columns id,title,status,assignee # custom columns
|
|
295
|
+
doto list --with-deps # show dependency info
|
|
296
|
+
doto list --format tree # tree view with deps
|
|
297
|
+
|
|
298
|
+
# Update a task
|
|
299
|
+
doto update TASK-001 --status in-progress
|
|
300
|
+
|
|
301
|
+
# Bulk update tasks with filters
|
|
302
|
+
doto update --filter-status open --priority high --all
|
|
303
|
+
doto update --filter-priority low --status blocked --all
|
|
304
|
+
doto update --filter-assignee alice --status done --all
|
|
305
|
+
doto update --filter-tags bug --add-tags urgent --all
|
|
306
|
+
doto update --filter-overdue --add-tags needs-attention --all
|
|
307
|
+
doto update --filter-status open --priority high --all --dry-run
|
|
308
|
+
doto update --filter-status open --status in-progress --all --yes
|
|
309
|
+
|
|
310
|
+
# Mark as done
|
|
311
|
+
doto done TASK-001
|
|
312
|
+
|
|
313
|
+
# Archive tasks (hide from listings, can reopen later)
|
|
314
|
+
doto archive TASK-001
|
|
315
|
+
doto archive TASK-001 TASK-002 TASK-003
|
|
316
|
+
doto archive TASK-001 --json
|
|
317
|
+
|
|
318
|
+
# Delete tasks permanently (DESTRUCTIVE - cannot be undone)
|
|
319
|
+
doto delete TASK-001 # single task
|
|
320
|
+
doto delete TASK-001 TASK-002 # multiple tasks
|
|
321
|
+
doto delete TASK-001 --force # skip confirmation
|
|
322
|
+
doto delete TASK-001 --dry-run # preview without deleting
|
|
323
|
+
doto delete --filter-status done --all # delete all done tasks
|
|
324
|
+
doto delete --filter-archived --all # delete all archived tasks
|
|
325
|
+
doto delete TASK-001 --json # JSON output
|
|
326
|
+
|
|
327
|
+
# Show next task to work on
|
|
328
|
+
doto next # suggests based on priority, due dates, deps
|
|
329
|
+
doto next --assignee alice # filter by assignee
|
|
330
|
+
doto next --all # show top 5 ready tasks
|
|
331
|
+
|
|
332
|
+
# Show task dependency tree
|
|
333
|
+
doto tree # show all tasks as dependency forest
|
|
334
|
+
doto tree TASK-001 # show what TASK-001 depends on
|
|
335
|
+
doto tree TASK-001 -r # show what depends on TASK-001
|
|
336
|
+
doto tree --compact # minimal output (IDs only)
|
|
337
|
+
|
|
338
|
+
# Show task dependencies (tasks that must be completed first)
|
|
339
|
+
doto deps TASK-001 # direct dependencies
|
|
340
|
+
doto deps TASK-001 --recursive # include transitive dependencies
|
|
341
|
+
doto deps TASK-001 --pending-only # only incomplete dependencies
|
|
342
|
+
doto deps TASK-001 --format tree # tree visualization
|
|
343
|
+
|
|
344
|
+
# Search tasks
|
|
345
|
+
doto search "authentication"
|
|
346
|
+
|
|
347
|
+
# Show statistics
|
|
348
|
+
doto stats --by-status
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Recurring Tasks
|
|
352
|
+
|
|
353
|
+
Create recurring task series that automatically generate individual tasks:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
# Create a weekly recurring task
|
|
357
|
+
doto add "Weekly review" --repeat "every friday" --until 2025-12-31
|
|
358
|
+
|
|
359
|
+
# Bi-weekly sprint planning
|
|
360
|
+
doto add "Sprint planning" --repeat "every 2 weeks on monday" --until +6m
|
|
361
|
+
|
|
362
|
+
# Monthly report on the last Friday (with date in title)
|
|
363
|
+
doto add "Monthly report {date}" --repeat "every month on last friday" --until +1y
|
|
364
|
+
|
|
365
|
+
# Quarterly review on the first Monday
|
|
366
|
+
doto add "Quarterly review" --repeat "every 3 months on first monday" --until +2y
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Supported recurrence patterns:**
|
|
370
|
+
|
|
371
|
+
| Pattern | Example |
|
|
372
|
+
|---------|--------|
|
|
373
|
+
| Daily | `every day`, `every 3 days` |
|
|
374
|
+
| Weekly | `every friday`, `every 2 weeks on monday` |
|
|
375
|
+
| Monthly (day) | `every month on 15`, `every 2 months on 1` |
|
|
376
|
+
| Monthly (weekday) | `every month on first monday`, `every month on last friday` |
|
|
377
|
+
| Quarterly | `every 3 months on first monday` |
|
|
378
|
+
|
|
379
|
+
**Title templating:** Use `{date}` in the title to include the occurrence date (e.g., "Weekly review {date}" → "Weekly review Aug 7").
|
|
380
|
+
|
|
381
|
+
### Managing Series
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
# List all series
|
|
385
|
+
doto series list
|
|
386
|
+
|
|
387
|
+
# Show series details and all tasks
|
|
388
|
+
doto series show SER-001
|
|
389
|
+
|
|
390
|
+
# Mark all past tasks in a series as done
|
|
391
|
+
doto series complete SER-001
|
|
392
|
+
|
|
393
|
+
# Complete tasks before a specific date
|
|
394
|
+
doto series complete SER-001 --before 2025-08-15
|
|
395
|
+
|
|
396
|
+
# Extend a series with a new end date
|
|
397
|
+
doto series extend SER-001 +3m
|
|
398
|
+
|
|
399
|
+
# Delete a series and all its tasks
|
|
400
|
+
doto series delete SER-001
|
|
401
|
+
|
|
402
|
+
# Delete series but keep the tasks
|
|
403
|
+
doto series delete SER-001 --keep-tasks
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
When viewing a task that's part of a series, the series info is displayed:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
$ doto show DOTO-002
|
|
410
|
+
╭─ DOTO-002 - Weekly standup Jul 31 ───────────────────────────────────────────╮
|
|
411
|
+
│ Priority: medium │
|
|
412
|
+
│ Status: open │
|
|
413
|
+
│ Due: 2026-07-31 │
|
|
414
|
+
│ Tags: recurring, meeting │
|
|
415
|
+
│ Series: SER-001 (every friday, until 2026-08-28) │
|
|
416
|
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### CLI Commands Reference
|
|
420
|
+
|
|
421
|
+
| Command | Description |
|
|
422
|
+
|---------|-------------|
|
|
423
|
+
| `init` | Initialize doto in a project |
|
|
424
|
+
| `completion` | Set up shell tab completion (bash/zsh/fish) |
|
|
425
|
+
| `config` | Show current configuration (JSON path, mode, defaults) |
|
|
426
|
+
| `add` | Add a new task (supports `--repeat` for recurring tasks) |
|
|
427
|
+
| `list` | List tasks with filters and sorting |
|
|
428
|
+
| `show` | Show details of a specific task |
|
|
429
|
+
| `update` | Update task fields |
|
|
430
|
+
| `done` | Mark tasks as done |
|
|
431
|
+
| `next` | Show the next task to work on |
|
|
432
|
+
| `tree` | Display tasks as a dependency tree |
|
|
433
|
+
| `reopen` | Reopen archived tasks |
|
|
434
|
+
| `deps` | Show task dependencies (blocking tasks) |
|
|
435
|
+
| `series` | Manage recurring task series |
|
|
436
|
+
| `resolve` | Resolve merge conflicts between RST and JSON |
|
|
437
|
+
| `delete` | Permanently delete tasks (supports filters) |
|
|
438
|
+
| `archive` | Archive tasks (hide from listings, can reopen) |
|
|
439
|
+
| `export` | Export tasks to various formats (JSON, CSV, Markdown) |
|
|
440
|
+
| `search` | Search tasks by text pattern or regex |
|
|
441
|
+
| `stats` | Show task statistics |
|
|
442
|
+
|
|
443
|
+
### Filter Options Reference
|
|
444
|
+
|
|
445
|
+
Several commands (`list`, `update`, `delete`) support common filter options:
|
|
446
|
+
|
|
447
|
+
| Option | Short | Commands | Description |
|
|
448
|
+
|--------|-------|----------|-------------|
|
|
449
|
+
| `--status` | `-s` | list | Filter by status (comma-separated) |
|
|
450
|
+
| `--priority` | `-p` | list | Filter by priority (comma-separated) |
|
|
451
|
+
| `--assignee` | `-a` | list | Filter by assignee (comma-separated) |
|
|
452
|
+
| `--tags` | `-t` | list | Filter by tags (comma-separated, matches any) |
|
|
453
|
+
| `--filter-status` | | update, delete | Filter by status (comma-separated) |
|
|
454
|
+
| `--filter-priority` | | update, delete | Filter by priority (comma-separated) |
|
|
455
|
+
| `--filter-assignee` | | update, delete | Filter by assignee (comma-separated) |
|
|
456
|
+
| `--filter-tags` | | update, delete | Filter by tags (comma-separated) |
|
|
457
|
+
| `--filter-overdue` | | update | Filter only overdue tasks |
|
|
458
|
+
| `--filter-archived` | | delete | Only include archived tasks |
|
|
459
|
+
| `--archived` | | list, search, export, stats | Include archived tasks |
|
|
460
|
+
|
|
461
|
+
**Safety flags for bulk operations:**
|
|
462
|
+
|
|
463
|
+
| Flag | Description |
|
|
464
|
+
|------|-------------|
|
|
465
|
+
| `--all` | Required when using filters without specific task IDs (safety measure) |
|
|
466
|
+
| `--dry-run` | Preview which tasks would be affected without making changes |
|
|
467
|
+
| `--yes` / `-y` | Skip confirmation prompt for bulk updates |
|
|
468
|
+
| `--force` / `-f` | Skip confirmation prompt for delete |
|
|
469
|
+
|
|
470
|
+
### Shell Completion
|
|
471
|
+
|
|
472
|
+
Tab completion is available for bash, zsh, and fish. It completes:
|
|
473
|
+
- Task IDs (with status and title hints)
|
|
474
|
+
- Series IDs (with title hints)
|
|
475
|
+
- Assignee names (from existing tasks)
|
|
476
|
+
- Tags (from existing tasks)
|
|
477
|
+
- Status values (`open`, `in-progress`, `blocked`, `done`)
|
|
478
|
+
- Priority values (`low`, `medium`, `high`, `critical`)
|
|
479
|
+
- Due date shortcuts (`today`, `tomorrow`, `+1w`, `friday`, `next-monday`, `end-of-month`, etc.)
|
|
480
|
+
- Recurrence patterns (`every friday`, `every month on first monday`, etc.)
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
# Install permanently (auto-detects your shell)
|
|
484
|
+
doto completion --install
|
|
485
|
+
|
|
486
|
+
# Or enable for current session only
|
|
487
|
+
eval "$(doto completion bash)" # bash
|
|
488
|
+
eval "$(doto completion zsh)" # zsh
|
|
489
|
+
doto completion fish | source # fish
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Bidirectional Sync
|
|
493
|
+
|
|
494
|
+
The `.doto/tasks.json` file is the source of truth. The CLI operates on JSON, while Sphinx builds perform bidirectional sync:
|
|
495
|
+
|
|
496
|
+
- Changes in RST files are detected via content hashing
|
|
497
|
+
- Changes in JSON (via CLI) are merged back to RST
|
|
498
|
+
- 3-way merge detects and reports conflicts
|
|
499
|
+
- Archived tasks are removed from RST but preserved in JSON
|
|
500
|
+
|
|
501
|
+
## Theming
|
|
502
|
+
|
|
503
|
+
### Custom Theme Override
|
|
504
|
+
|
|
505
|
+
To customize doto's appearance, create a `_doto/` directory in your Sphinx source:
|
|
506
|
+
|
|
507
|
+
```
|
|
508
|
+
my-project/
|
|
509
|
+
├── _doto/
|
|
510
|
+
│ ├── html/
|
|
511
|
+
│ │ └── doto-custom.css
|
|
512
|
+
│ ├── latex/
|
|
513
|
+
│ │ └── doto-custom.sty
|
|
514
|
+
│ └── epub/
|
|
515
|
+
│ └── doto-custom.css
|
|
516
|
+
├── conf.py
|
|
517
|
+
└── index.rst
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Files in `_doto/` take precedence over built-in themes. This allows project-specific styling without modifying configuration.
|
|
521
|
+
|
|
522
|
+
### HTML
|
|
523
|
+
|
|
524
|
+
Built-in themes: `default`, `minimal`
|
|
525
|
+
|
|
526
|
+
CSS variables for customization:
|
|
527
|
+
|
|
528
|
+
```css
|
|
529
|
+
:root {
|
|
530
|
+
--doto-priority-low: #6c757d;
|
|
531
|
+
--doto-priority-medium: #0d6efd;
|
|
532
|
+
--doto-priority-high: #fd7e14;
|
|
533
|
+
--doto-priority-critical: #dc3545;
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### epub
|
|
538
|
+
|
|
539
|
+
Built-in themes: `default`, `minimal`
|
|
540
|
+
|
|
541
|
+
Set via `doto_epub_theme` in conf.py. epub styles are optimized for e-readers with `page-break-inside: avoid` and simplified layouts.
|
|
542
|
+
|
|
543
|
+
### LaTeX/PDF
|
|
544
|
+
|
|
545
|
+
Uses `tcolorbox` for styled output. Customize column widths with `doto_latex_column_specs`:
|
|
546
|
+
|
|
547
|
+
```python
|
|
548
|
+
doto_latex_column_specs = {
|
|
549
|
+
"title": r"p{6cm}", # Wider title column
|
|
550
|
+
"priority": r"c", # Centered
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Custom styles via `doto_latex_preamble`.
|
|
555
|
+
|
|
556
|
+
### Doxtr Integration
|
|
557
|
+
|
|
558
|
+
When `doxtr-pdf-theme-core` is available (and `doto_doxtr_integration` is `auto`
|
|
559
|
+
or `enabled`), doto integrates with its color and layout systems automatically
|
|
560
|
+
for PDF/LaTeX output. Standalone builds (without the theme core) keep doto's
|
|
561
|
+
built-in defaults unchanged.
|
|
562
|
+
|
|
563
|
+
```python
|
|
564
|
+
# conf.py
|
|
565
|
+
doto_doxtr_integration = "auto" # auto | enabled | disabled
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
**Semantic colors.** If a `doxtr_semantic_palette` is configured on the theme
|
|
569
|
+
core, doto derives its task-box, priority, and status colors from that palette
|
|
570
|
+
(via the core's `dd:` expression system, e.g. `dd:danger` for `critical`,
|
|
571
|
+
`dd:warning` for `high`, `dd:info` for `in-progress`) and emits them as
|
|
572
|
+
`\definecolor` overrides into the LaTeX preamble after `\usepackage{doto}`. This
|
|
573
|
+
means task boxes match the surrounding theme instead of doto's hardcoded
|
|
574
|
+
defaults. Without a palette (or without the theme core), the defaults in
|
|
575
|
+
`doto.sty` are used.
|
|
576
|
+
|
|
577
|
+
**Auto-landscape wide tables.** When integrated and the theme core's
|
|
578
|
+
`doxtr_table_auto_landscape` is enabled (the default), a `doto-list` task table
|
|
579
|
+
whose column count is at least `doxtr_landscape_min_columns` (theme-core option,
|
|
580
|
+
default `4`) is wrapped in the core's breakable landscape environment so it
|
|
581
|
+
rotates to landscape automatically and does not overflow the page margins.
|
|
582
|
+
Narrow tables (below the threshold) are left in portrait, and standalone builds
|
|
583
|
+
emit the unrotated table unchanged.
|
|
584
|
+
|
|
585
|
+
> `doxtr_semantic_palette`, `doxtr_table_auto_landscape`, and
|
|
586
|
+
> `doxtr_landscape_min_columns` are configuration values owned by
|
|
587
|
+
> `doxtr-pdf-theme-core`; doto only reads them when the theme core is active.
|
|
588
|
+
|
|
589
|
+
## Development
|
|
590
|
+
|
|
591
|
+
Set up a local development environment and run the checks that CI enforces:
|
|
592
|
+
|
|
593
|
+
```bash
|
|
594
|
+
pip install -e ".[dev]"
|
|
595
|
+
python scripts/check_imports.py # circular-import check (also run in CI)
|
|
596
|
+
python -m pytest # runs the suite with the coverage gate (fails under 80% via pyproject)
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
The coverage gate is set to 80% to guard against coverage drift (current coverage is ~83%). The threshold lives in a single place, `pyproject.toml` `[tool.pytest.ini_options]` `addopts`, so running `python -m pytest` locally enforces the same gate as CI. The same import-cycle check (`scripts/check_imports.py`) runs in CI before the test suite.
|
|
600
|
+
|
|
601
|
+
## License
|
|
602
|
+
|
|
603
|
+
MIT License
|