sphinx-structured-toc 0.1.0__tar.gz → 0.2.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 (64) hide show
  1. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/.readthedocs.yaml +10 -6
  2. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/PKG-INFO +5 -1
  3. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/common.mk +85 -85
  4. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/Makefile +10 -1
  5. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/conf.py +5 -1
  6. sphinx_structured_toc-0.2.0/docs/demo-targets/model-reference.rst +19 -0
  7. sphinx_structured_toc-0.2.0/docs/developer-set-up.rst +24 -0
  8. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/index.rst +1 -0
  9. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/reference.rst +65 -0
  10. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/pyproject.toml +17 -0
  11. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc/__init__.py +28 -9
  12. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc/_version.py +3 -3
  13. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc/directives.py +1 -3
  14. sphinx_structured_toc-0.2.0/sphinx_structured_toc/domain-list.css +31 -0
  15. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc/html.py +21 -41
  16. sphinx_structured_toc-0.2.0/sphinx_structured_toc/latex.py +30 -0
  17. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc/transforms.py +31 -41
  18. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc.egg-info/PKG-INFO +5 -1
  19. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc.egg-info/SOURCES.txt +3 -0
  20. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc.egg-info/requires.txt +1 -0
  21. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc.egg-info/scm_file_list.json +39 -36
  22. sphinx_structured_toc-0.2.0/sphinx_structured_toc.egg-info/scm_version.json +8 -0
  23. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/conftest.py +1 -1
  24. sphinx_structured_toc-0.2.0/tests/integration/test_docs_build.py +81 -0
  25. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_directives.py +0 -1
  26. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_item_parsing.py +0 -1
  27. sphinx_structured_toc-0.2.0/tests/unit/test_latex.py +91 -0
  28. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_options.py +0 -1
  29. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/uv.lock +241 -0
  30. sphinx_structured_toc-0.1.0/docs/demo-targets/model-reference.rst +0 -6
  31. sphinx_structured_toc-0.1.0/sphinx_structured_toc/domain-list.css +0 -29
  32. sphinx_structured_toc-0.1.0/sphinx_structured_toc.egg-info/scm_version.json +0 -8
  33. sphinx_structured_toc-0.1.0/tests/integration/test_docs_build.py +0 -24
  34. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/.gitignore +0 -0
  35. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/.pre-commit-config.yaml +0 -0
  36. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/LICENSE +0 -0
  37. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/Makefile +0 -0
  38. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/README.rst +0 -0
  39. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/approaches.rst +0 -0
  40. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/custom-fields-how-to.rst +0 -0
  41. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/field-types-reference.rst +0 -0
  42. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/lookup-expressions-how-to.rst +0 -0
  43. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/queries-reference.rst +0 -0
  44. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/queryset-operations-how-to.rst +0 -0
  45. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/view-functions-introduction.rst +0 -0
  46. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/demo-targets/views-reference.rst +0 -0
  47. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/developer-reference.rst +0 -0
  48. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/installation-and-usage.rst +0 -0
  49. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/docs/make.bat +0 -0
  50. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/setup.cfg +0 -0
  51. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc/nodes.py +0 -0
  52. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc.egg-info/dependency_links.txt +0 -0
  53. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/sphinx_structured_toc.egg-info/top_level.txt +0 -0
  54. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/__init__.py +0 -0
  55. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/integration/__init__.py +0 -0
  56. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/integration/example/__init__.py +0 -0
  57. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/integration/example/conf.py +0 -0
  58. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/integration/example/index.rst +0 -0
  59. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/__init__.py +0 -0
  60. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_ambiguity.py +0 -0
  61. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_html.py +0 -0
  62. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_ids.py +0 -0
  63. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_section_fallback.py +0 -0
  64. {sphinx_structured_toc-0.1.0 → sphinx_structured_toc-0.2.0}/tests/unit/test_suppress_warnings.py +0 -0
@@ -12,14 +12,18 @@ build:
12
12
 
13
13
  # Build documentation in the "docs/" directory with Sphinx
14
14
  sphinx:
15
- configuration: docs/conf.py
15
+ configuration: docs/conf.py
16
+
17
+ # Also build a PDF, using Read the Docs' LaTeX toolchain
18
+ formats:
19
+ - pdf
16
20
 
17
21
  # Install the project with the `docs` extra so the `furo` theme is
18
22
  # available during the docs build.
19
23
  # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
20
24
  python:
21
- install:
22
- - method: pip
23
- path: .
24
- extra_requirements:
25
- - docs
25
+ install:
26
+ - method: pip
27
+ path: .
28
+ extra_requirements:
29
+ - docs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sphinx-structured-toc
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A Sphinx extension for rendering compact, semantic, accessible documentation link lists grouped by domain.
5
5
  Author: Daniele Procida
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -678,6 +678,9 @@ License: GNU GENERAL PUBLIC LICENSE
678
678
  Public License instead of this License. But first, please read
679
679
  <https://www.gnu.org/licenses/why-not-lgpl.html>.
680
680
 
681
+ Project-URL: Documentation, https://canonical-sphinx-structured-toc.readthedocs-hosted.com/
682
+ Project-URL: Source, https://github.com/canonical/sphinx-structured-toc
683
+ Project-URL: Issues, https://github.com/canonical/sphinx-structured-toc/issues
681
684
  Keywords: sphinx,accessibility,toc,aria
682
685
  Classifier: Framework :: Sphinx :: Extension
683
686
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -694,6 +697,7 @@ Requires-Dist: docutils>=0.21.2
694
697
  Requires-Dist: sphinx~=7.0
695
698
  Provides-Extra: docs
696
699
  Requires-Dist: furo>=2024.1.29; extra == "docs"
700
+ Requires-Dist: sphinxcontrib-svg2pdfconverter[CairoSVG]~=2.1; extra == "docs"
697
701
  Dynamic: license-file
698
702
 
699
703
  Sphinx structured table of contents
@@ -24,28 +24,28 @@ export UV_FROZEN := true
24
24
 
25
25
  .PHONY: help
26
26
  help: ## Show this help.
27
- @printf "\e[1m%-30s\e[0m | \e[1m%s\e[0m\n" "Target" "Description"
28
- printf "\e[2m%-30s + %-41s\e[0m\n" "------------------------------" "------------------------------------------------"
29
- egrep '^[^:]+\: [^#]*##' $$(echo $(MAKEFILE_LIST) | tac --separator=' ') | sed -e 's/^[^:]*://' -e 's/:[^#]*/ /' | sort -V| awk -F '[: ]*' \
30
- '{
31
- if ($$2 == "##")
32
- {
33
- $$1=sprintf(" %-28s", $$1);
34
- $$2=" | ";
35
- print $$0;
36
- }
37
- else
38
- {
39
- $$1= %-25s", $$1);sprintf("
40
- $$2=" | ";
41
- $$3= %s", $$3);sprintf("
42
- print $$0;
43
- }
44
- }'
27
+ @printf "\e[1m%-30s\e[0m | \e[1m%s\e[0m\n" "Target" "Description"
28
+ printf "\e[2m%-30s + %-41s\e[0m\n" "------------------------------" "------------------------------------------------"
29
+ egrep '^[^:]+\: [^#]*##' $$(echo $(MAKEFILE_LIST) | tac --separator=' ') | sed -e 's/^[^:]*://' -e 's/:[^#]*/ /' | sort -V| awk -F '[: ]*' \
30
+ '{
31
+ if ($$2 == "##")
32
+ {
33
+ $$1=sprintf(" %-28s", $$1);
34
+ $$2=" | ";
35
+ print $$0;
36
+ }
37
+ else
38
+ {
39
+ $$1=sprintf(" %-25s", $$1);
40
+ $$2=" | ";
41
+ $$3=sprintf(" %s", $$3);
42
+ print $$0;
43
+ }
44
+ }'
45
45
 
46
46
  .PHONY: install
47
47
  install: install-uv install-linters install-precommit install-build-deps ## Set up a development environment
48
- uv sync $(UV_TEST_GROUPS) $(UV_LINT_GROUPS)
48
+ uv sync $(UV_TEST_GROUPS) $(UV_LINT_GROUPS)
49
49
 
50
50
  .PHONY: install-linters
51
51
  install-linters: install-uv install-shellcheck install-pyright install-lint-build-deps
@@ -53,213 +53,213 @@ install-linters: install-uv install-shellcheck install-pyright install-lint-buil
53
53
  .PHONY: install-precommit
54
54
  install-precommit: install-uv ##- Set up pre-commit hooks in this repository.
55
55
  ifeq ($(shell which pre-commit),)
56
- uv tool run pre-commit install
56
+ uv tool run pre-commit install
57
57
  else
58
- pre-commit install
58
+ pre-commit install
59
59
  endif
60
60
 
61
61
  .PHONY: clean
62
62
  clean: ## Clean up the development environment
63
- uv tool run pyclean .
64
- rm -rf dist/ build/ .test_output/ .coverage*
63
+ uv tool run pyclean .
64
+ rm -rf dist/ build/ .test_output/ .coverage*
65
65
 
66
66
  .PHONY: autoformat
67
67
  autoformat: format # Hidden alias for 'format'
68
68
 
69
69
  .PHONY: format-ruff
70
70
  format-ruff: install-ruff ##- Automatically format with ruff
71
- success=true
72
- ruff check --fix $(SOURCES) || success=false
73
- ruff format $(SOURCES)
74
- $$success || exit 1
71
+ success=true
72
+ ruff check --fix $(SOURCES) || success=false
73
+ ruff format $(SOURCES)
74
+ $$success || exit 1
75
75
 
76
76
  .PHONY: format-codespell
77
77
  format-codespell: ##- Fix spelling issues with codespell
78
- uv run codespell --toml pyproject.toml --write-changes $(SOURCES)
78
+ uv run codespell --toml pyproject.toml --write-changes $(SOURCES)
79
79
 
80
80
  .PHONY: format-prettier
81
81
  format-prettier: install-npm ##- Format files with prettier
82
- $(PRETTIER) --write $(PRETTIER_FILES)
82
+ $(PRETTIER) --write $(PRETTIER_FILES)
83
83
 
84
84
  .PHONY: setup-tests
85
85
  setup-tests: install-uv install-build-deps ##- Set up a testing environment without linters
86
- uv sync $(UV_TEST_GROUPS)
86
+ uv sync $(UV_TEST_GROUPS)
87
87
 
88
88
  .PHONY: setup-lint
89
89
  setup-lint: install-uv install-shellcheck install-pyright install-lint-build-deps ##- Set up a linting-only environment
90
- uv sync $(UV_LINT_GROUPS)
90
+ uv sync $(UV_LINT_GROUPS)
91
91
 
92
92
  .PHONY: lint-ruff
93
93
  lint-ruff: install-ruff ##- Lint with ruff
94
94
  ifneq ($(CI),)
95
- @echo ::group::$@
95
+ @echo ::group::$@
96
96
  endif
97
- ruff check $(SOURCES)
98
- ruff format --diff $(SOURCES)
97
+ ruff check $(SOURCES)
98
+ ruff format --diff $(SOURCES)
99
99
  ifneq ($(CI),)
100
- @echo ::endgroup::
100
+ @echo ::endgroup::
101
101
  endif
102
102
 
103
103
  .PHONY: lint-codespell
104
104
  lint-codespell: install-codespell ##- Check spelling with codespell
105
105
  ifneq ($(CI),)
106
- @echo ::group::$@
106
+ @echo ::group::$@
107
107
  endif
108
- uv run codespell --toml pyproject.toml $(SOURCES)
108
+ uv run codespell --toml pyproject.toml $(SOURCES)
109
109
  ifneq ($(CI),)
110
- @echo ::endgroup::
110
+ @echo ::endgroup::
111
111
  endif
112
112
 
113
113
  .PHONY: lint-mypy
114
114
  lint-mypy: ##- Check types with mypy
115
115
  ifneq ($(CI),)
116
- @echo ::group::$@
116
+ @echo ::group::$@
117
117
  endif
118
- uv run mypy --show-traceback --show-error-codes $(PROJECT)
118
+ uv run mypy --show-traceback --show-error-codes $(PROJECT)
119
119
  ifneq ($(CI),)
120
- @echo ::endgroup::
120
+ @echo ::endgroup::
121
121
  endif
122
122
 
123
123
  .PHONY: lint-pyright
124
124
  lint-pyright: ##- Check types with pyright
125
125
  ifneq ($(CI),)
126
- @echo ::group::$@
126
+ @echo ::group::$@
127
127
  endif
128
128
  ifneq ($(shell which pyright),)
129
- pyright --pythonpath .venv/bin/python
129
+ pyright --pythonpath .venv/bin/python
130
130
  else
131
- uv tool run pyright --pythonpath .venv/bin/python
131
+ uv tool run pyright --pythonpath .venv/bin/python
132
132
  endif
133
133
  ifneq ($(CI),)
134
- @echo ::endgroup::
134
+ @echo ::endgroup::
135
135
  endif
136
136
 
137
137
  .PHONY: lint-shellcheck
138
138
  lint-shellcheck: ##- Lint shell scripts
139
139
  ifneq ($(CI),)
140
- @echo ::group::$@
140
+ @echo ::group::$@
141
141
  endif
142
- git ls-files | file --mime-type -Nnf- | grep shellscript | cut -f1 -d: | xargs -r shellcheck
142
+ git ls-files | file --mime-type -Nnf- | grep shellscript | cut -f1 -d: | xargs -r shellcheck
143
143
  ifneq ($(CI),)
144
- @echo ::endgroup::
144
+ @echo ::endgroup::
145
145
  endif
146
146
 
147
147
  .PHONY: lint-prettier
148
148
  lint-prettier: install-npm ##- Lint files with prettier
149
149
  ifneq ($(CI),)
150
- @echo ::group::$@
150
+ @echo ::group::$@
151
151
  endif
152
- $(PRETTIER) --check $(PRETTIER_FILES)
152
+ $(PRETTIER) --check $(PRETTIER_FILES)
153
153
  ifneq ($(CI),)
154
- @echo ::endgroup::
154
+ @echo ::endgroup::
155
155
  endif
156
156
 
157
157
  .PHONY: lint-twine
158
158
  lint-twine: pack-pip ##- Lint Python packages with twine
159
159
  ifneq ($(CI),)
160
- @echo ::group::$@
160
+ @echo ::group::$@
161
161
  endif
162
- uv tool run twine check dist/*
162
+ uv tool run twine check dist/*
163
163
  ifneq ($(CI),)
164
- @echo ::endgroup::
164
+ @echo ::endgroup::
165
165
  endif
166
166
 
167
167
  .PHONY: test
168
168
  test: ## Run all tests
169
- uv run pytest
169
+ uv run pytest
170
170
 
171
171
  .PHONY: test-fast
172
172
  test-fast: ##- Run fast tests
173
- uv run pytest -m 'not slow'
173
+ uv run pytest -m 'not slow'
174
174
 
175
175
  .PHONY: test-slow
176
176
  test-slow: ##- Run slow tests
177
- uv run pytest -m 'slow'
177
+ uv run pytest -m 'slow'
178
178
 
179
179
  .PHONY: test-coverage
180
180
  test-coverage: ## Generate coverage report
181
- uv run coverage run --source $(PROJECT) -m pytest
182
- uv run coverage xml -o coverage.xml
183
- uv run coverage report -m
184
- uv run coverage html
181
+ uv run coverage run --source $(PROJECT) -m pytest
182
+ uv run coverage xml -o coverage.xml
183
+ uv run coverage report -m
184
+ uv run coverage html
185
185
 
186
186
  .PHONY: test-find-slow
187
187
  test-find-slow: ##- Identify slow tests. Set cutoff time in seconds with SLOW_CUTOFF_TIME
188
- uv run pytest --durations 0 --durations-min $(SLOW_CUTOFF_TIME)
188
+ uv run pytest --durations 0 --durations-min $(SLOW_CUTOFF_TIME)
189
189
 
190
190
  .PHONY: pack-pip
191
191
  pack-pip: ##- Build packages for pip (sdist, wheel)
192
192
  ifneq ($(CI),)
193
- @echo ::group::$@
193
+ @echo ::group::$@
194
194
  endif
195
- uv build --quiet .
195
+ uv build --quiet .
196
196
  ifneq ($(CI),)
197
- @echo ::endgroup::
197
+ @echo ::endgroup::
198
198
  endif
199
199
 
200
200
  .PHONY: install-uv
201
201
  install-uv:
202
202
  ifneq ($(shell which uv),)
203
203
  else ifneq ($(shell which snap),)
204
- sudo snap install --classic astral-uv
204
+ sudo snap install --classic astral-uv
205
205
  else ifneq ($(shell which brew),)
206
- brew install uv
206
+ brew install uv
207
207
  else ifeq ($(OS),Windows_NT)
208
- pwsh -c "irm https://astral.sh/uv/install.ps1 | iex"
208
+ pwsh -c "irm https://astral.sh/uv/install.ps1 | iex"
209
209
  else
210
- curl -LsSf https://astral.sh/uv/install.sh | sh
210
+ curl -LsSf https://astral.sh/uv/install.sh | sh
211
211
  endif
212
212
 
213
213
  .PHONY: install-codespell
214
214
  install-codespell:
215
215
  ifneq ($(shell which codespell),)
216
216
  else ifneq ($(shell which snap),)
217
- sudo snap install codespell
217
+ sudo snap install codespell
218
218
  else ifneq ($(shell which brew),)
219
- make install-uv
220
- uv tool install codespell
219
+ make install-uv
220
+ uv tool install codespell
221
221
  else
222
- $(warning Codespell not installed. Please install it yourself.)
222
+ $(warning Codespell not installed. Please install it yourself.)
223
223
  endif
224
224
 
225
225
  .PHONY: install-pyright
226
226
  install-pyright: install-uv
227
227
  ifneq ($(shell which pyright),)
228
228
  else ifneq ($(shell which snap),)
229
- sudo snap install --classic pyright
229
+ sudo snap install --classic pyright
230
230
  else
231
- [ -d "$(HOME)/.npm/_cacache" ] && chown -R `id -u`:`id -g` "$(HOME)/.npm" || true
232
- uv tool install pyright
231
+ [ -d "$(HOME)/.npm/_cacache" ] && chown -R `id -u`:`id -g` "$(HOME)/.npm" || true
232
+ uv tool install pyright
233
233
  endif
234
234
 
235
235
  .PHONY: install-ruff
236
236
  install-ruff:
237
237
  ifneq ($(shell which ruff),)
238
238
  else ifneq ($(shell which snap),)
239
- sudo snap install ruff
239
+ sudo snap install ruff
240
240
  else
241
- make install-uv
242
- uv tool install ruff
241
+ make install-uv
242
+ uv tool install ruff
243
243
  endif
244
244
 
245
245
  .PHONY: install-shellcheck
246
246
  install-shellcheck:
247
247
  ifneq ($(shell which shellcheck),)
248
248
  else ifneq ($(shell which snap),)
249
- sudo snap install shellcheck
249
+ sudo snap install shellcheck
250
250
  else ifneq ($(shell which brew),)
251
- brew install shellcheck
251
+ brew install shellcheck
252
252
  else
253
- $(warning Shellcheck not installed. Please install it yourself.)
253
+ $(warning Shellcheck not installed. Please install it yourself.)
254
254
  endif
255
255
 
256
256
  .PHONY: install-npm
257
257
  install-npm:
258
258
  ifneq ($(shell which npm),)
259
259
  else ifneq ($(shell which snap),)
260
- sudo snap install --classic node
260
+ sudo snap install --classic node
261
261
  else ifneq ($(shell which brew),)
262
- brew install node
262
+ brew install node
263
263
  else
264
- $(error npm not installed. Please install it yourself.)
264
+ $(error npm not installed. Please install it yourself.)
265
265
  endif
@@ -12,7 +12,7 @@ BUILDDIR = _build
12
12
  help:
13
13
  @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14
14
 
15
- .PHONY: help Makefile livehtml
15
+ .PHONY: help Makefile livehtml pdf
16
16
 
17
17
  # Catch-all target: route all unknown targets through Sphinx using the new
18
18
  # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
@@ -21,3 +21,12 @@ help:
21
21
 
22
22
  run:
23
23
  @$(SPHINXAUTOBUILD) "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS) $(O)
24
+
25
+ # Build a PDF with the standard LaTeX toolchain (latexmk + xelatex, as used
26
+ # by the sphinx-docs-starter-pack). The finished PDF is moved to $(BUILDDIR).
27
+ # `-Q` quiets Sphinx; LATEXMKOPTS quiets the latexmk/xelatex passes (it
28
+ # propagates via the environment to the Makefile that `-M latexpdf` runs).
29
+ pdf:
30
+ @LATEXMKOPTS=-silent $(SPHINXBUILD) -M latexpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) -Q $(O)
31
+ @find "$(BUILDDIR)/latex" -name '*.pdf' -exec mv {} "$(BUILDDIR)"/ \;
32
+ @echo "Output can be found in ./$(BUILDDIR)"
@@ -11,7 +11,11 @@ sys.path.insert(0, str(project_root))
11
11
  project = "sphinx-structured-toc"
12
12
  author = "sphinx-structured-toc contributors"
13
13
 
14
- extensions = ["sphinx_structured_toc"]
14
+ extensions = [
15
+ "sphinx_structured_toc",
16
+ # Convert SVG images to PDF for LaTeX/PDF output
17
+ "sphinxcontrib.cairosvgconverter",
18
+ ]
15
19
 
16
20
  html_theme = "furo"
17
21
  html_title = project
@@ -0,0 +1,19 @@
1
+ :orphan:
2
+
3
+ Model reference
4
+ ===============
5
+
6
+ This page exists as a target for the ``domain`` demonstration.
7
+
8
+ The example below is just a handly place to keep an example of the directive for use elsewhere in this documentation.
9
+
10
+ The model layer
11
+ ...............
12
+
13
+ .. domain:: Model layer
14
+
15
+ .. slice:: Models
16
+
17
+ :doc:`Introduction </demo-targets/field-types-reference>` domain
18
+ :doc:`Reference </demo-targets/model-reference>` slice
19
+ :doc:`Custom fields </demo-targets/custom-fields-how-to>`
@@ -0,0 +1,24 @@
1
+ Development set-up
2
+ ======================
3
+
4
+ Having cloned the repository, build with ``make install`` (at the root; there's a completely unrelated ``Makefile`` for the ``docs`` directory).
5
+
6
+ ``make setup-tests`` is a lighter-weight alternative if you want to run tests but need less of the tooling.
7
+
8
+ There's some complexity in this; it will opt for ``homebrew`` or ``apt`` to install components.
9
+
10
+
11
+ Testing
12
+ -------
13
+
14
+ ``make test`` runs ``uv run pytest``. There's a slow test that can be skipped: ``make test-fast``.
15
+
16
+ Use ``make test`` to run rests, and ``make test-coverage`` for a coverage report.
17
+
18
+
19
+ Running the documentation
20
+ -------------------------
21
+
22
+ In ``docs``: ``make run`` to launch the documentation site on port 8000.
23
+
24
+ Changes to the extension code will be picked up live.
@@ -156,6 +156,7 @@ The view layer
156
156
 
157
157
  Home <self>
158
158
  installation-and-usage
159
+ developer-set-up
159
160
  reference
160
161
  developer-reference
161
162
  approaches
@@ -1,6 +1,8 @@
1
1
  Reference
2
2
  =============
3
3
 
4
+ The extension can only apply ARIA attributes to HTML output. For PDF, links are generated but without any additional context.
5
+
4
6
  Basic rendering
5
7
  ---------------
6
8
 
@@ -39,6 +41,69 @@ The example above renders as:
39
41
  The ``id``\s are automatically generated as required.
40
42
 
41
43
 
44
+ ARIA labelling
45
+ --------------
46
+
47
+ Here's an example that includes accessibility labelling via the ``slice`` and ``domain`` options. There are three links in the slice:
48
+
49
+ * *Introduction* (to the Model layer, via the ``domain`` option)
50
+ * *Reference* (for Models, via the ``slice`` option)
51
+ * *Custom fields*
52
+
53
+ .. code-block:: rst
54
+
55
+ The model layer
56
+ ...............
57
+
58
+ .. domain::
59
+
60
+ .. slice:: Models
61
+
62
+ :doc:`Introduction </demo-targets/field-types-reference>` domain
63
+ :doc:`Reference </demo-targets/model-reference>` slice
64
+ :doc:`Custom fields </demo-targets/custom-fields-how-to>`
65
+
66
+ The HTML output below has been simplified by removing some elements, classes and other attributes.
67
+
68
+ In the HTML you can see the ``aria-labelledby`` attribute on various items.
69
+
70
+ The ``id``\s an ``aria-labelledby`` attribute refers to will give a screen reader an accessible name for that element.
71
+
72
+ For example, there is an ``<a id="the-model-layer-models-reference">`` (the last highlighted link) that is "labelled by" two other ``id``\s: ``the-model-layer-models-reference`` and ``the-model-layer-models``.
73
+
74
+ You can identify the text associated with those two ``id``\s; the screenreader will find them and render the accessible name *Reference, Models*.
75
+
76
+
77
+ .. code-block:: html
78
+ :emphasize-lines: 1, 2, 5, 9, 10, 16, 17
79
+
80
+ <nav aria-labelledby="model-layer-domain">
81
+ <span id="model-layer-domain">Model layer</span>
82
+ <ul>
83
+ <li>
84
+ <span id="the-model-layer-models">Models</span>:
85
+ <ul>
86
+ <li>
87
+ <a
88
+ id="the-model-layer-models-introduction"
89
+ aria-labelledby="the-model-layer-models-introduction model-layer-domain">
90
+ <span>Introduction</span>
91
+ </a>
92
+ </li>
93
+ <li>
94
+ <a
95
+ id="the-model-layer-models-reference"
96
+ aria-labelledby="the-model-layer-models-reference the-model-layer-models">
97
+ <span>Reference</span>
98
+ </a>
99
+ </li>
100
+ <li><a>Custom fields</a></li>
101
+ </ul>
102
+ </li>
103
+ </ul>
104
+ </nav>
105
+
106
+
42
107
  Explicitly named domains
43
108
  ~~~~~~~~~~~~~~~~~~~~~~~~
44
109
 
@@ -22,9 +22,15 @@ classifiers = [
22
22
  ]
23
23
  license = { file = "LICENSE" }
24
24
 
25
+ [project.urls]
26
+ Documentation = "https://canonical-sphinx-structured-toc.readthedocs-hosted.com/"
27
+ Source = "https://github.com/canonical/sphinx-structured-toc"
28
+ Issues = "https://github.com/canonical/sphinx-structured-toc/issues"
29
+
25
30
  [project.optional-dependencies]
26
31
  docs = [
27
32
  "furo>=2024.1.29",
33
+ "sphinxcontrib-svg2pdfconverter[CairoSVG]~=2.1",
28
34
  ]
29
35
 
30
36
  [dependency-groups]
@@ -44,6 +50,7 @@ dev = [
44
50
  "pytest-cov~=6.0",
45
51
  "pytest-mock~=3.12",
46
52
  "sphinx-autobuild>=2024.10.3",
53
+ "sphinxcontrib-svg2pdfconverter[CairoSVG]~=2.1",
47
54
  "twine>=6.2.0",
48
55
  ]
49
56
 
@@ -217,12 +224,18 @@ select = [
217
224
  ]
218
225
  ignore = [
219
226
  "E501",
227
+ "D100",
228
+ "D101",
229
+ "D102",
230
+ "D103",
231
+ "D104",
220
232
  "D105",
221
233
  "D107",
222
234
  "D203",
223
235
  "D213",
224
236
  "D215",
225
237
  "A003",
238
+ "A005",
226
239
  "SIM117",
227
240
  "COM812",
228
241
  "ISC001",
@@ -240,6 +253,7 @@ ignore-decorators = [
240
253
 
241
254
  [tool.ruff.lint.pylint]
242
255
  max-args = 8
256
+ max-branches = 16
243
257
 
244
258
  [tool.ruff.lint.per-file-ignores]
245
259
  "tests/**.py" = [
@@ -257,3 +271,6 @@ max-args = 8
257
271
  "I001",
258
272
  "F401",
259
273
  ]
274
+ "docs/conf.py" = [
275
+ "INP001",
276
+ ]
@@ -1,5 +1,8 @@
1
+ """A Sphinx extension for rendering compact, semantic, accessible documentation link lists grouped by domain."""
2
+
1
3
  from pathlib import Path
2
4
 
5
+ from docutils import nodes as docutils_nodes
3
6
  from sphinx.application import Sphinx
4
7
  from sphinx.util.typing import ExtensionMetadata
5
8
 
@@ -8,10 +11,19 @@ from .html import (
8
11
  depart_domain,
9
12
  depart_slice,
10
13
  depart_slice_item,
14
+ make_reference_visitor,
11
15
  visit_domain,
12
16
  visit_slice,
13
17
  visit_slice_item,
14
18
  )
19
+ from .latex import (
20
+ depart_domain as latex_depart_domain,
21
+ depart_slice as latex_depart_slice,
22
+ depart_slice_item as latex_depart_slice_item,
23
+ visit_domain as latex_visit_domain,
24
+ visit_slice as latex_visit_slice,
25
+ visit_slice_item as latex_visit_slice_item,
26
+ )
15
27
  from .nodes import Domain, Slice, SliceItem
16
28
  from .transforms import resolve_domains
17
29
 
@@ -29,12 +41,25 @@ except ImportError: # pragma: no cover
29
41
 
30
42
 
31
43
  def setup(app: Sphinx) -> ExtensionMetadata:
44
+ """Register the extension's nodes, directives, transforms and static assets."""
32
45
  # register various components
33
46
 
34
47
  # nodes
35
- app.add_node(Domain, html=(visit_domain, depart_domain))
36
- app.add_node(Slice, html=(visit_slice, depart_slice))
37
- app.add_node(SliceItem, html=(visit_slice_item, depart_slice_item))
48
+ app.add_node(
49
+ Domain,
50
+ html=(visit_domain, depart_domain),
51
+ latex=(latex_visit_domain, latex_depart_domain),
52
+ )
53
+ app.add_node(
54
+ Slice,
55
+ html=(visit_slice, depart_slice),
56
+ latex=(latex_visit_slice, latex_depart_slice),
57
+ )
58
+ app.add_node(
59
+ SliceItem,
60
+ html=(visit_slice_item, depart_slice_item),
61
+ latex=(latex_visit_slice_item, latex_depart_slice_item),
62
+ )
38
63
 
39
64
  # directives
40
65
  app.add_directive("domain", DomainDirective)
@@ -60,18 +85,12 @@ def setup(app: Sphinx) -> ExtensionMetadata:
60
85
 
61
86
  def add_static_dir(app: Sphinx) -> None:
62
87
  """Add the extension package directory to ``html_static_path``."""
63
-
64
88
  if _CSS_DIR not in app.config.html_static_path:
65
89
  app.config.html_static_path.append(_CSS_DIR)
66
90
 
67
91
 
68
92
  def install_reference_override(app: Sphinx) -> None:
69
93
  """Override ``docutils.nodes.reference`` HTML visitors."""
70
-
71
- from docutils import nodes as docutils_nodes
72
-
73
- from .html import make_reference_visitor
74
-
75
94
  visit, depart = make_reference_visitor(app)
76
95
  app.add_node(
77
96
  docutils_nodes.reference,