sphinx-rustdoc-postprocess 0.1.0__py3-none-any.whl
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.
- sphinx_rustdoc_postprocess/__init__.py +320 -0
- sphinx_rustdoc_postprocess/_version.py +34 -0
- sphinx_rustdoc_postprocess/py.typed +0 -0
- sphinx_rustdoc_postprocess-0.1.0.dist-info/METADATA +258 -0
- sphinx_rustdoc_postprocess-0.1.0.dist-info/RECORD +7 -0
- sphinx_rustdoc_postprocess-0.1.0.dist-info/WHEEL +4 -0
- sphinx_rustdoc_postprocess-0.1.0.dist-info/licenses/LICENSE +19 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""Post-process sphinxcontrib-rust RST output via pandoc.
|
|
2
|
+
|
|
3
|
+
sphinxcontrib-rust dumps rustdoc (markdown) doc-comments verbatim into RST
|
|
4
|
+
directive bodies. This extension runs *after* sphinxcontrib_rust's
|
|
5
|
+
``builder-inited`` handler (priority 600 > default 500), walks the generated
|
|
6
|
+
``.rst`` files, extracts the markdown content blocks, and converts them to
|
|
7
|
+
proper RST through ``pandoc -f markdown -t rst``.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
import subprocess
|
|
14
|
+
import textwrap
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from sphinx.application import Sphinx
|
|
18
|
+
from sphinx.util import logging
|
|
19
|
+
|
|
20
|
+
from sphinx_rustdoc_postprocess._version import ( # noqa: F401
|
|
21
|
+
__version__,
|
|
22
|
+
__version_tuple__,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
_log = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
# Matches an indented markdown fenced code block:
|
|
28
|
+
# <indent>```lang
|
|
29
|
+
# ...code...
|
|
30
|
+
# <indent>```
|
|
31
|
+
_FENCE_RE = re.compile(
|
|
32
|
+
r"^(?P<indent>[ ]+)```(?P<lang>\w*)\s*\n"
|
|
33
|
+
r"(?P<body>.*?)"
|
|
34
|
+
r"^(?P=indent)```[ ]*$",
|
|
35
|
+
re.MULTILINE | re.DOTALL,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Matches an indented markdown table (header + separator + rows).
|
|
39
|
+
_TABLE_RE = re.compile(
|
|
40
|
+
r"^(?P<indent>[ ]+)\|.+\|[ ]*\n" # header row
|
|
41
|
+
r"(?P=indent)\|[-| :]+\|[ ]*\n" # separator row
|
|
42
|
+
r"(?:(?P=indent)\|.+\|[ ]*\n)+", # data rows
|
|
43
|
+
re.MULTILINE,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Matches an indented markdown ATX heading (## Heading).
|
|
47
|
+
_HEADING_RE = re.compile(
|
|
48
|
+
r"^(?P<indent>[ ]+)(?P<hashes>#{1,6})[ ]+(?P<text>.+)$",
|
|
49
|
+
re.MULTILINE,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Matches markdown inline code (`code`) that is NOT already double-backtick RST.
|
|
53
|
+
# Handles the common case where `code`<letter> breaks RST inline markup rules.
|
|
54
|
+
# Excludes <> so RST links (`text <url>`_) are not mangled.
|
|
55
|
+
_INLINE_CODE_RE = re.compile(
|
|
56
|
+
r"(?<!`)(`)((?!`)(?:[^`\n<>])+)\1(?!`)",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Matches markdown hyperlinks: [text](url)
|
|
60
|
+
_MD_LINK_RE = re.compile(
|
|
61
|
+
r"\[(?P<text>[^\[\]]+)\]\((?P<url>https?://[^)]+)\)",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Matches rustdoc intra-doc links: [`code`] or [``code``] (without a URL part).
|
|
65
|
+
_INTRADOC_LINK_RE = re.compile(
|
|
66
|
+
r"\[`{1,2}(?P<name>[^`\]]+)`{1,2}\](?!\()",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _pandoc(markdown: str) -> str:
|
|
71
|
+
"""Convert a markdown fragment to RST via pandoc.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
markdown : str
|
|
76
|
+
The markdown text to convert.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
str
|
|
81
|
+
The converted RST text, or the original markdown if pandoc fails.
|
|
82
|
+
"""
|
|
83
|
+
result = subprocess.run(
|
|
84
|
+
["pandoc", "-f", "markdown-smart", "-t", "rst", "--wrap=none"],
|
|
85
|
+
input=markdown,
|
|
86
|
+
capture_output=True,
|
|
87
|
+
text=True,
|
|
88
|
+
timeout=10,
|
|
89
|
+
)
|
|
90
|
+
if result.returncode != 0:
|
|
91
|
+
_log.warning("[rustdoc_postprocess] pandoc failed: %s", result.stderr)
|
|
92
|
+
return markdown
|
|
93
|
+
return result.stdout
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _convert_fences(content: str) -> str:
|
|
97
|
+
"""Convert markdown code fences to RST code-block directives.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
content : str
|
|
102
|
+
RST file content potentially containing indented markdown code fences.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
str
|
|
107
|
+
Content with code fences replaced by ``.. code-block::`` directives.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def _replace(m: re.Match) -> str:
|
|
111
|
+
indent = m.group("indent")
|
|
112
|
+
lang = m.group("lang") or "none"
|
|
113
|
+
body = m.group("body")
|
|
114
|
+
|
|
115
|
+
body_indent = indent + " "
|
|
116
|
+
lines = []
|
|
117
|
+
for line in body.split("\n"):
|
|
118
|
+
stripped = line.rstrip()
|
|
119
|
+
if stripped:
|
|
120
|
+
if stripped.startswith(indent):
|
|
121
|
+
stripped = stripped[len(indent) :]
|
|
122
|
+
lines.append(body_indent + stripped)
|
|
123
|
+
else:
|
|
124
|
+
lines.append("")
|
|
125
|
+
while lines and not lines[-1].strip():
|
|
126
|
+
lines.pop()
|
|
127
|
+
|
|
128
|
+
body_text = "\n".join(lines)
|
|
129
|
+
return f"{indent}.. code-block:: {lang}\n\n{body_text}\n"
|
|
130
|
+
|
|
131
|
+
return _FENCE_RE.sub(_replace, content)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _convert_tables(content: str) -> str:
|
|
135
|
+
"""Convert markdown tables to RST tables via pandoc.
|
|
136
|
+
|
|
137
|
+
Parameters
|
|
138
|
+
----------
|
|
139
|
+
content : str
|
|
140
|
+
RST file content potentially containing indented markdown tables.
|
|
141
|
+
|
|
142
|
+
Returns
|
|
143
|
+
-------
|
|
144
|
+
str
|
|
145
|
+
Content with markdown tables replaced by RST grid tables.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def _replace(m: re.Match) -> str:
|
|
149
|
+
indent = m.group("indent")
|
|
150
|
+
table_md = textwrap.dedent(m.group(0))
|
|
151
|
+
rst = _pandoc(table_md).rstrip("\n")
|
|
152
|
+
lines = [indent + line if line.strip() else "" for line in rst.split("\n")]
|
|
153
|
+
return "\n".join(lines) + "\n"
|
|
154
|
+
|
|
155
|
+
return _TABLE_RE.sub(_replace, content)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _convert_links(content: str) -> str:
|
|
159
|
+
"""Convert markdown links to RST.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
content : str
|
|
164
|
+
RST file content potentially containing markdown-style links.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
str
|
|
169
|
+
Content with ``[text](url)`` converted to ```text <url>`_`` and
|
|
170
|
+
rustdoc intra-doc links ``[`name`]`` converted to ````name````.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
def _process_line(line: str) -> str:
|
|
174
|
+
stripped = line.lstrip()
|
|
175
|
+
if stripped.startswith("..") or stripped.startswith(":"):
|
|
176
|
+
return line
|
|
177
|
+
line = _MD_LINK_RE.sub(r"`\g<text> <\g<url>>`_", line)
|
|
178
|
+
line = _INTRADOC_LINK_RE.sub(r"``\g<name>``", line)
|
|
179
|
+
return line
|
|
180
|
+
|
|
181
|
+
return "\n".join(_process_line(line) for line in content.split("\n"))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _convert_inline_code(content: str) -> str:
|
|
185
|
+
"""Convert markdown inline code to RST double-backtick literals.
|
|
186
|
+
|
|
187
|
+
Parameters
|
|
188
|
+
----------
|
|
189
|
+
content : str
|
|
190
|
+
RST file content potentially containing markdown single-backtick code.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
str
|
|
195
|
+
Content with single-backtick code converted to double-backtick literals.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
def _process_line(line: str) -> str:
|
|
199
|
+
stripped = line.lstrip()
|
|
200
|
+
if stripped.startswith("..") or stripped.startswith(":"):
|
|
201
|
+
return line
|
|
202
|
+
return _INLINE_CODE_RE.sub(r"``\2``", line)
|
|
203
|
+
|
|
204
|
+
return "\n".join(_process_line(line) for line in content.split("\n"))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _convert_headings(content: str) -> str:
|
|
208
|
+
"""Convert markdown ATX headings to bold labels.
|
|
209
|
+
|
|
210
|
+
RST section headings cannot appear inside directive bodies, so we
|
|
211
|
+
convert ``## Heading`` to ``**Heading**`` which renders as bold.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
content : str
|
|
216
|
+
RST file content potentially containing markdown ATX headings.
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
str
|
|
221
|
+
Content with headings replaced by bold text.
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
def _replace(m: re.Match) -> str:
|
|
225
|
+
indent = m.group("indent")
|
|
226
|
+
text = m.group("text").strip()
|
|
227
|
+
return f"{indent}**{text}**"
|
|
228
|
+
|
|
229
|
+
return _HEADING_RE.sub(_replace, content)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def postprocess_rst_files(app: Sphinx) -> None:
|
|
233
|
+
"""Walk generated RST files and convert markdown fragments.
|
|
234
|
+
|
|
235
|
+
Scans the directory specified by the ``rustdoc_postprocess_rst_dir``
|
|
236
|
+
config value (relative to ``app.srcdir``) for ``.rst`` files and applies
|
|
237
|
+
all markdown-to-RST conversions in sequence.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
app : Sphinx
|
|
242
|
+
The Sphinx application instance.
|
|
243
|
+
"""
|
|
244
|
+
rst_dir = Path(app.srcdir) / app.config.rustdoc_postprocess_rst_dir
|
|
245
|
+
if not rst_dir.exists():
|
|
246
|
+
return
|
|
247
|
+
|
|
248
|
+
for rst_file in sorted(rst_dir.rglob("*.rst")):
|
|
249
|
+
original = rst_file.read_text(encoding="utf-8")
|
|
250
|
+
converted = original
|
|
251
|
+
converted = _convert_fences(converted)
|
|
252
|
+
converted = _convert_links(converted)
|
|
253
|
+
converted = _convert_tables(converted)
|
|
254
|
+
converted = _convert_headings(converted)
|
|
255
|
+
converted = _convert_inline_code(converted)
|
|
256
|
+
if converted != original:
|
|
257
|
+
_log.info(
|
|
258
|
+
"[rustdoc_postprocess] Converted markdown in %s",
|
|
259
|
+
rst_file.relative_to(app.srcdir),
|
|
260
|
+
)
|
|
261
|
+
rst_file.write_text(converted, encoding="utf-8")
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def inject_rust_toctree(app: Sphinx) -> None:
|
|
265
|
+
"""Append a toctree snippet to a target RST file.
|
|
266
|
+
|
|
267
|
+
Reads the ``rustdoc_postprocess_toctree_target`` and
|
|
268
|
+
``rustdoc_postprocess_toctree_rst`` config values. If either is empty,
|
|
269
|
+
the injection is skipped.
|
|
270
|
+
|
|
271
|
+
Parameters
|
|
272
|
+
----------
|
|
273
|
+
app : Sphinx
|
|
274
|
+
The Sphinx application instance.
|
|
275
|
+
"""
|
|
276
|
+
target = app.config.rustdoc_postprocess_toctree_target
|
|
277
|
+
toctree_rst = app.config.rustdoc_postprocess_toctree_rst
|
|
278
|
+
if not target or not toctree_rst:
|
|
279
|
+
return
|
|
280
|
+
|
|
281
|
+
target_path = Path(app.srcdir) / target
|
|
282
|
+
if not target_path.exists():
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
content = target_path.read_text(encoding="utf-8")
|
|
286
|
+
if toctree_rst.strip() in content:
|
|
287
|
+
return
|
|
288
|
+
|
|
289
|
+
target_path.write_text(content.rstrip("\n") + "\n" + toctree_rst, encoding="utf-8")
|
|
290
|
+
_log.info("[rustdoc_postprocess] Injected toctree into %s", target)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _on_builder_inited(app: Sphinx) -> None:
|
|
294
|
+
"""builder-inited callback: postprocess then inject toctree."""
|
|
295
|
+
postprocess_rst_files(app)
|
|
296
|
+
inject_rust_toctree(app)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def setup(app: Sphinx) -> dict:
|
|
300
|
+
"""Register the extension with Sphinx.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
app : Sphinx
|
|
305
|
+
The Sphinx application instance.
|
|
306
|
+
|
|
307
|
+
Returns
|
|
308
|
+
-------
|
|
309
|
+
dict
|
|
310
|
+
Extension metadata with version and parallel safety flags.
|
|
311
|
+
"""
|
|
312
|
+
app.add_config_value("rustdoc_postprocess_rst_dir", "crates", "env")
|
|
313
|
+
app.add_config_value("rustdoc_postprocess_toctree_target", "", "env")
|
|
314
|
+
app.add_config_value("rustdoc_postprocess_toctree_rst", "", "env")
|
|
315
|
+
app.connect("builder-inited", _on_builder_inited, priority=600)
|
|
316
|
+
return {
|
|
317
|
+
"version": __version__,
|
|
318
|
+
"parallel_read_safe": True,
|
|
319
|
+
"parallel_write_safe": True,
|
|
320
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
File without changes
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sphinx-rustdoc-postprocess
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Post-process sphinxcontrib-rust RST output, converting leftover markdown to proper RST via pandoc.
|
|
5
|
+
Author-email: Rohit Goswami <rgoswami@ieee.org>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: sphinx>=7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# sphinx-rustdoc-postprocess
|
|
15
|
+
|
|
16
|
+
Post-process [sphinxcontrib-rust](https://github.com/aspect-build/sphinxcontrib-rust) RST output, converting leftover markdown
|
|
17
|
+
fragments (code fences, tables, links, headings, inline code) to proper RST
|
|
18
|
+
via [pandoc](https://pandoc.org/).
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## The problem
|
|
22
|
+
|
|
23
|
+
[sphinxcontrib-rust](https://github.com/aspect-build/sphinxcontrib-rust) generates RST files from Rust crates, but `rustdoc`
|
|
24
|
+
doc-comments are written in markdown. The generated RST ends up with markdown
|
|
25
|
+
fragments embedded verbatim inside directive bodies, which Sphinx cannot render
|
|
26
|
+
correctly.
|
|
27
|
+
|
|
28
|
+
For a real-world example, see [rgpot](https://rgpot.rgoswami.me/) ([source](https://github.com/HaoZeke/rgpot)), which uses this extension to
|
|
29
|
+
document its Rust core library alongside C++ API docs.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Before (raw sphinxcontrib-rust output)
|
|
33
|
+
|
|
34
|
+
Given Rust doc-comments like these in `lib.rs`:
|
|
35
|
+
|
|
36
|
+
//! ## Module Overview
|
|
37
|
+
//!
|
|
38
|
+
//! | Module | Purpose |
|
|
39
|
+
//! |--------|---------|
|
|
40
|
+
//! | [`types`] | `#[repr(C)]` data structures for force/energy I/O |
|
|
41
|
+
//! | [`tensor`] | DLPack tensor helpers |
|
|
42
|
+
|
|
43
|
+
sphinxcontrib-rust produces RST with the markdown still intact inside
|
|
44
|
+
directives:
|
|
45
|
+
|
|
46
|
+
.. py:module:: rgpot_core
|
|
47
|
+
|
|
48
|
+
## Module Overview
|
|
49
|
+
|
|
50
|
+
| Module | Purpose |
|
|
51
|
+
|--------|---------|
|
|
52
|
+
| [`types`] | `#[repr(C)]` data structures for force/energy I/O |
|
|
53
|
+
| [`tensor`] | DLPack tensor helpers |
|
|
54
|
+
|
|
55
|
+
This renders incorrectly in Sphinx: headings inside directives break the
|
|
56
|
+
document structure, markdown tables appear as literal pipe characters, and
|
|
57
|
+
single-backtick code is not valid RST.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### After (postprocessed output)
|
|
61
|
+
|
|
62
|
+
After this extension runs, the same file becomes:
|
|
63
|
+
|
|
64
|
+
.. py:module:: rgpot_core
|
|
65
|
+
|
|
66
|
+
**Module Overview**
|
|
67
|
+
|
|
68
|
+
+------------+----------------------------------------------------+
|
|
69
|
+
| Module | Purpose |
|
|
70
|
+
+============+====================================================+
|
|
71
|
+
| ``types`` | ``#[repr(C)]`` data structures for force/energy IO |
|
|
72
|
+
+------------+----------------------------------------------------+
|
|
73
|
+
| ``tensor`` | DLPack tensor helpers |
|
|
74
|
+
+------------+----------------------------------------------------+
|
|
75
|
+
|
|
76
|
+
Similarly, markdown code fences:
|
|
77
|
+
|
|
78
|
+
```c
|
|
79
|
+
rgpot_status_t s = rgpot_potential_calculate(pot, &input, &output);
|
|
80
|
+
if (s != RGPOT_SUCCESS) {
|
|
81
|
+
fprintf(stderr, "rgpot error: %s\n", rgpot_last_error());
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
become proper RST code-block directives:
|
|
86
|
+
|
|
87
|
+
.. code-block:: c
|
|
88
|
+
|
|
89
|
+
rgpot_status_t s = rgpot_potential_calculate(pot, &input, &output);
|
|
90
|
+
if (s != RGPOT_SUCCESS) {
|
|
91
|
+
fprintf(stderr, "rgpot error: %s\n", rgpot_last_error());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
And markdown links like `[metatensor](https://docs.metatensor.org/)` become
|
|
95
|
+
`` `metatensor <https://docs.metatensor.org/>`_ ``, while rustdoc intra-doc links
|
|
96
|
+
like ``[`types`]`` become `` ``types`` ``.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Installation
|
|
100
|
+
|
|
101
|
+
pip install sphinx-rustdoc-postprocess
|
|
102
|
+
|
|
103
|
+
Pandoc must be available on your `PATH`. See [pandoc.org](https://pandoc.org/installing.html) for installation
|
|
104
|
+
instructions.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
Add to your Sphinx `conf.py`:
|
|
110
|
+
|
|
111
|
+
extensions = [
|
|
112
|
+
"sphinxcontrib_rust",
|
|
113
|
+
"sphinx_rustdoc_postprocess",
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
The extension hooks into `builder-inited` at priority 600 (after
|
|
117
|
+
sphinxcontrib-rust's default 500), so it automatically runs on the generated
|
|
118
|
+
RST files before Sphinx reads them.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
### Configuration
|
|
122
|
+
|
|
123
|
+
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
<colgroup>
|
|
127
|
+
<col class="org-left" />
|
|
128
|
+
|
|
129
|
+
<col class="org-left" />
|
|
130
|
+
|
|
131
|
+
<col class="org-left" />
|
|
132
|
+
</colgroup>
|
|
133
|
+
<thead>
|
|
134
|
+
<tr>
|
|
135
|
+
<th scope="col" class="org-left">Config value</th>
|
|
136
|
+
<th scope="col" class="org-left">Default</th>
|
|
137
|
+
<th scope="col" class="org-left">Description</th>
|
|
138
|
+
</tr>
|
|
139
|
+
</thead>
|
|
140
|
+
<tbody>
|
|
141
|
+
<tr>
|
|
142
|
+
<td class="org-left"><code>rustdoc_postprocess_rst_dir</code></td>
|
|
143
|
+
<td class="org-left"><code>"crates"</code></td>
|
|
144
|
+
<td class="org-left">Subdirectory of <code>srcdir</code> to scan for RST files</td>
|
|
145
|
+
</tr>
|
|
146
|
+
|
|
147
|
+
<tr>
|
|
148
|
+
<td class="org-left"><code>rustdoc_postprocess_toctree_target</code></td>
|
|
149
|
+
<td class="org-left"><code>""</code></td>
|
|
150
|
+
<td class="org-left">RST file to inject a toctree snippet into (empty = skip)</td>
|
|
151
|
+
</tr>
|
|
152
|
+
|
|
153
|
+
<tr>
|
|
154
|
+
<td class="org-left"><code>rustdoc_postprocess_toctree_rst</code></td>
|
|
155
|
+
<td class="org-left"><code>""</code></td>
|
|
156
|
+
<td class="org-left">RST snippet to append to the target file (empty = skip)</td>
|
|
157
|
+
</tr>
|
|
158
|
+
</tbody>
|
|
159
|
+
</table>
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### Full configuration example
|
|
163
|
+
|
|
164
|
+
# conf.py
|
|
165
|
+
import os
|
|
166
|
+
|
|
167
|
+
extensions = [
|
|
168
|
+
"sphinxcontrib_rust",
|
|
169
|
+
"sphinx_rustdoc_postprocess",
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
# sphinxcontrib-rust settings
|
|
173
|
+
rust_crates = {
|
|
174
|
+
"my_crate": os.path.abspath("../../my-crate/"),
|
|
175
|
+
}
|
|
176
|
+
rust_doc_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "crates")
|
|
177
|
+
rust_rustdoc_fmt = "rst"
|
|
178
|
+
|
|
179
|
+
# Inject a toctree entry for the Rust docs into an existing index page
|
|
180
|
+
rustdoc_postprocess_toctree_target = "api/index.rst"
|
|
181
|
+
rustdoc_postprocess_toctree_rst = """
|
|
182
|
+
|
|
183
|
+
Rust API
|
|
184
|
+
--------
|
|
185
|
+
|
|
186
|
+
.. toctree::
|
|
187
|
+
:maxdepth: 2
|
|
188
|
+
|
|
189
|
+
../crates/my_crate/lib
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
## What gets converted
|
|
194
|
+
|
|
195
|
+
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
<colgroup>
|
|
199
|
+
<col class="org-left" />
|
|
200
|
+
|
|
201
|
+
<col class="org-left" />
|
|
202
|
+
</colgroup>
|
|
203
|
+
<thead>
|
|
204
|
+
<tr>
|
|
205
|
+
<th scope="col" class="org-left">Markdown construct</th>
|
|
206
|
+
<th scope="col" class="org-left">RST output</th>
|
|
207
|
+
</tr>
|
|
208
|
+
</thead>
|
|
209
|
+
<tbody>
|
|
210
|
+
<tr>
|
|
211
|
+
<td class="org-left"><code>```lang</code> code fences</td>
|
|
212
|
+
<td class="org-left"><code>.. code-block:: lang</code> directives</td>
|
|
213
|
+
</tr>
|
|
214
|
+
|
|
215
|
+
<tr>
|
|
216
|
+
<td class="org-left"><code>\vert table \vert</code> pipe tables</td>
|
|
217
|
+
<td class="org-left">RST grid tables (via pandoc)</td>
|
|
218
|
+
</tr>
|
|
219
|
+
|
|
220
|
+
<tr>
|
|
221
|
+
<td class="org-left"><code>[text](url)</code> links</td>
|
|
222
|
+
<td class="org-left"><code>`text <url>`_</code></td>
|
|
223
|
+
</tr>
|
|
224
|
+
|
|
225
|
+
<tr>
|
|
226
|
+
<td class="org-left"><code>[`Name`]</code> intra-doc links</td>
|
|
227
|
+
<td class="org-left"><code>``Name``</code></td>
|
|
228
|
+
</tr>
|
|
229
|
+
|
|
230
|
+
<tr>
|
|
231
|
+
<td class="org-left"><code>`code`</code> inline code</td>
|
|
232
|
+
<td class="org-left"><code>``code``</code></td>
|
|
233
|
+
</tr>
|
|
234
|
+
|
|
235
|
+
<tr>
|
|
236
|
+
<td class="org-left"><code>## Heading</code> ATX headings</td>
|
|
237
|
+
<td class="org-left"><code>**Heading**</code> (bold, since RST headings can't nest in directives)</td>
|
|
238
|
+
</tr>
|
|
239
|
+
</tbody>
|
|
240
|
+
</table>
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
pixi install
|
|
246
|
+
pixi run test
|
|
247
|
+
|
|
248
|
+
A `pre-commit` job is setup on CI to enforce consistent styles, so it is best
|
|
249
|
+
to set it up locally as well (using [uvx](https://docs.astral.sh/uv/guides/tools/) for isolation):
|
|
250
|
+
|
|
251
|
+
# Run before committing
|
|
252
|
+
uvx pre-commit run --all-files
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
|
258
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
sphinx_rustdoc_postprocess/__init__.py,sha256=gab2A2_nHrAY3pOKfv8JcyOr5Et6FizPAXZI0MfEOcg,9396
|
|
2
|
+
sphinx_rustdoc_postprocess/_version.py,sha256=5jwwVncvCiTnhOedfkzzxmxsggwmTBORdFL_4wq0ZeY,704
|
|
3
|
+
sphinx_rustdoc_postprocess/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
sphinx_rustdoc_postprocess-0.1.0.dist-info/METADATA,sha256=QPdl16iCTnBrBGsdaEFprdluo-W1PYo8omG1MsF_VcY,7040
|
|
5
|
+
sphinx_rustdoc_postprocess-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
6
|
+
sphinx_rustdoc_postprocess-0.1.0.dist-info/licenses/LICENSE,sha256=bqBLQGg818jLAkkiLe-4rr7oElM-AtfQsBeyoWjmK9Q,1123
|
|
7
|
+
sphinx_rustdoc_postprocess-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
MIT License Copyright (c) 2026 Rohit Goswami <rgoswami[at]ieee.org>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is furnished
|
|
8
|
+
to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice (including the next
|
|
11
|
+
paragraph) shall be included in all copies or substantial portions of the
|
|
12
|
+
Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
|
17
|
+
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
18
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
19
|
+
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|