From 9c815d689a2a4a5d433ba15154cb606bd986fc8d Mon Sep 17 00:00:00 2001 From: Yuriy Andamasov Date: Tue, 12 May 2026 15:34:04 +0300 Subject: fix(ext): parse cmdincludemd content as RST so legacy `_include/*.txt` directives render MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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:

.. cmdinclude:: /_include/interface-description.txt

.. cfgcmd:: set interfaces ethernet ...

.. code-block:: none

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) --- docs/_ext/vyos.py | 33 ++++++++++++++++++++++----------- 1 file 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): -- cgit v1.2.3