diff options
| author | Yuriy Andamasov <yuriy@vyos.io> | 2026-05-12 15:34:04 +0300 |
|---|---|---|
| committer | Mergify <37929162+mergify[bot]@users.noreply.github.com> | 2026-05-12 13:40:46 +0000 |
| commit | bd89afa9eb35e69dcd65a6fda768e462d03d9c6d (patch) | |
| tree | cd4708a6ca1e20c4374434f408cfa1a0c4a9cb3d /docs/_ext | |
| parent | 16543fc5808bd76c5737ce8a983a75ab72806ad6 (diff) | |
| download | vyos-documentation-bd89afa9eb35e69dcd65a6fda768e462d03d9c6d.tar.gz vyos-documentation-bd89afa9eb35e69dcd65a6fda768e462d03d9c6d.zip | |
fix(ext): parse cmdincludemd content as RST so legacy `_include/*.txt` directives render
The `_include/*.txt` library is written in reStructuredText (`.. cfgcmd::`,
`.. code-block::`, `.. note::`, `.. cmdinclude::`). After the RST→MyST
migration, the `{cmdincludemd}` fence on .md pages routed include content
through `MockState.nested_parse`, which in MyST 2.0 simply replays the
content through the MyST renderer (see myst_parser/mocking.py:153). RST
directives in the .txt file then rendered as literal paragraph text:
<p>.. cmdinclude:: /_include/interface-description.txt</p>
<p>.. cfgcmd:: set interfaces ethernet ...</p>
<p>.. code-block:: none</p>
User-visible symptom (reported on rolling docs): the Ethernet, dummy,
tunnel, bonding, bridge, macsec, vxlan, l2tpv3, pseudo-ethernet,
virtual-ethernet, and wireless pages all showed unprocessed `.. cfgcmd::`
and `.. cmdinclude::` directives instead of styled command boxes.
Fix: mirror MyST's own `{eval-rst}` plumbing
(`MockRSTParser().parse(text, doc)` per
`mdit_to_docutils/base.py:1655`). Build a fresh document that inherits
the outer document's settings + reporter, run `MockRSTParser` over the
substituted include content, and graft the resulting children back
into the calling document with explicit-target registration. Keeps the
Sphinx env available to `cfgcmd`/`opcmd`/`cmdinclude` directives.
Verified locally on rolling (Sphinx 7.x, myst-parser 2.0): zero literal
`cfgcmd::` / `cmdinclude::` / `code-block::` / `opcmd::` / `note::` /
`include::` strings remain in any built HTML page under
`configuration/`, `automation/`, `installation/`, `operation/`,
`vpp/`; all 11 affected interface pages now render proper
`cfgcmd-heading` / `cfgcmd-body` blocks (e.g. ethernet.html: 160,
wireless.html: 172, dummy.html: 4).
🤖 Generated by [robots](https://vyos.io)
(cherry picked from commit 9c815d689a2a4a5d433ba15154cb606bd986fc8d)
Diffstat (limited to 'docs/_ext')
| -rw-r--r-- | docs/_ext/vyos.py | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/docs/_ext/vyos.py b/docs/_ext/vyos.py index 527178d1..0c90f4bd 100644 --- a/docs/_ext/vyos.py +++ b/docs/_ext/vyos.py @@ -364,18 +364,29 @@ class CmdInclude(SphinxDirective): line = re.sub('{{\s?var' + str(i) + '\s?}}',value,line) new_include_lines.append(line) - if hasattr(self.state, '_renderer'): - self.state._renderer.nested_render_text(''.join(new_include_lines), self.lineno) - return [] - from docutils.statemachine import ViewList - from docutils import nodes + # The _include/*.txt library is written in reStructuredText + # (`.. cfgcmd::`, `.. code-block::`, `.. note::`, `.. cmdinclude::`). + # When called from a MyST `.md` page, `self.state` is MyST's + # MockState whose `nested_parse` just routes back through MyST — + # so the RST directives render as literal paragraph text. + # + # Parse the file as RST directly, mirroring what MyST itself does + # for `{eval-rst}` blocks (myst_parser.mocking.MockRSTParser via + # render_restructuredtext): build a fresh document that inherits + # the parent's settings (so Sphinx env / reporter survive) and + # graft its children back into the calling document. + from docutils.utils import new_document + from myst_parser.mocking import MockRSTParser + content = ''.join(new_include_lines) - vl = ViewList() - for i, line in enumerate(content.splitlines(keepends=False)): - vl.append(line, include_file[1], i) - node = nodes.Element() - self.state.nested_parse(vl, self.content_offset, node, match_titles=True) - return node.children + outer_doc = self.state.document + newdoc = new_document(include_file[1], outer_doc.settings) + newdoc.reporter = outer_doc.reporter + MockRSTParser().parse(content, newdoc) + for node in newdoc.children: + if getattr(node, 'attributes', None) and node.get('names'): + outer_doc.note_explicit_target(node, node) + return list(newdoc.children) class CfgcmdlistDirective(Directive): |
