Sphinx

Sphinx is absolutely core to the architecture of aidoc. But while Sphinx is wonderfully powerful, extensible, and directive-driven, there are limitations.

This module encapsules the Sphinx/build because we want to control outputs. But we also want to programatically set up variables via rst_prolog/rst_epilog.

In addition, there proves to be frustrations around Sphinx/directives; so we simply allow you to write Jinja into your .rst files. Absolutely everything in this design allow you to continue to use all the Sphinx you have and use.

Sphinx publishing/publishers is also problematic. We have some specific objectives around this too. You should never have to bring your own template(s) to make publisher(s) work. Specifically, Microsoft Word - is difficult to format correctly. We have Sphinx/connectors to fix this up: injecting page numbers and footers and generally fixing up docx files directly using Python/OpenOffice.

The Sphinx/text publisher also does dastardly things to your rst. Ordinarily we wouldn’t care about text presentation: but it turns out that in a world of AI, a document can be tokenised and then sent to a LLM using this. aidoc has a grammar and a lexx/yacc to fix this:

templates/tidytext.lark
start: (tight_list | line | newline)+

tight_list: INTRO_COLON _NL+ bullet_item+

# Bullets allow for wrapped text (the link fix)
bullet_item: [_MARGIN] "*" _SP? wrapped_text _NL*

# A line is now strictly ONE line of text.
# If it's indented, it remains its own 'line' object.
line: [_MARGIN] TEXT _NL?

# We only use this where we explicitly want to eat internal EOLs
wrapped_text: TEXT (_NL TEXT)*

newline: _NL

_MARGIN: /[ ]{1,10}/
INTRO_COLON: /[^:\n]+:$/m
TEXT: /[^\n]+/

_SP: " "
_NL: /(\r?\n)/

%import common.WS_INLINE
%ignore WS_INLINE
class lbn.aidoc.sphinxj2.Builder(builder, outdir='/builddir/build/BUILD/python-lbn-aidoc-1.3.9-build/lbn.aidoc-1.3.9/_build', quiet=False, warningiserror=False)

Bases: object

control and manage sphinx build

build(srcdir: str, tags: List[str], prolog: DocNamespace, epilog: DocNamespace | None = None, overrides: Dict[str, Any] = {}) Sphinx

Surgical Builder: Orchestrates the Sphinx environment and renders the tailored document.

Args:

srcdir: The root hardware path for the template source files. prolog: The DocNamespace containing global identity and freetext substitutions. tags: List of Sphinx tags to activate specific ‘only’ blocks (e.g., ‘ai’, ‘data’). epilog: Optional DocNamespace for footer links and dynamic SeeAlso blocks. overrides: Direct configuration strikes for the SphinxApp (e.g., ‘doc_title’).

Returns:

The filesystem path to the rendered output artifact.

doctree()
post_process(outfile)

perform any post processing on the output file outfile is supposed to be the final output of the sphinx build, but we don’t actually seem to know what that might be…

sourcedir()
stream(outfile, target_file=None)

stream outfile to stdout outfile is supposed to be the final output of the sphinx build, but we don’t actually seem to know what that might be…

class lbn.aidoc.sphinxj2.DocNamespace(replace: bool = False, **variables)

Bases: object

Helper to convert a dictionary into a Sphinx rst_prolog/rst_epilog string. Maps Python facts to reST substitutions. Acts as both rst_prolog and rst_epilog for the Sphinx engine.

property jinja_vars

Returns a copy of variables plus helpers purely for Jinja rendering.

write(output_dir: str, indent: int = 0)

Delegates the write strike to all registered SeeAlso objects.

class lbn.aidoc.sphinxj2.IncludeOutput(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)

Bases: SphinxDirective

Surgical IncludeOutput Directive. Behaves exactly like the vanilla Sphinx Include directive by emitting include-read events and noting structural dependencies, but resolves file paths out of app.outdir instead of the Git source tree.

final_argument_whitespace = True

May the final argument contain whitespace?

required_arguments = 1

Number of required directive arguments.

run() Sequence[Node]

Surgical IncludeOutput Directive Execution. Recursively resolves file bytes straight out of app.outdir, parsing the text inside an isolated clean-room sub-document canvas to permanently prevent path inheritance leaks from hijacking standard source includes.

class lbn.aidoc.sphinxj2.SeeAlso(tag: str)

Bases: object

Surgical Link Generator. Produces the two-part reST handshake: Substitution + Hyperlink Target.

add(label: str, value: str, asset_type: AssetType = AssetType.PRODUCT)
as_line()

everything on one line

as_list(indent: int = 3, replace: bool = True) str

The ‘Surgical Handshake’: Every exhale results in a |seealso_tag| target.

If replace is set; then sets up a reference/replace directive

write(output_dir: str | Path, indent: int = 0, replace: bool = True)

The ‘Mechanical Exhale’: Writes the group’s block to a standalone file. Ensures the include hardware always finds a target.

Bases: object

Surgical Asset Hardware. Encapsulates label, value, and the wire-protocol for URL resolution.

class AssetType(*values)

Bases: Enum

DOC = 2
PRODUCT = 1
RPM = 3
RPMLIKE = 4
as_ref() str

Returns a clean, clickable reST link.

default_assettype()
get_url() str

The ‘Wire Protocol’: Resolves raw slugs into high-fidelity URLs.

class lbn.aidoc.sphinxj2.Sphinx(builder, outfile, quiet=False, warningiserror=False)

Bases: object

coordinates all the jinja/sphinx, pre and post processing to create clean, complete build artifacts

build(*args, **kw)

creates sphinx app and builds the project

workingdir()

output directory - available as an includes path

class lbn.aidoc.sphinxj2.SphinxPlain(outfile, quiet=False, warningiserror=False, extractor=<function basic_to_text>)

Bases: Sphinx

make a single plain-text document out of the build

not only does this create a single page from multiple; but it uses html-style blocks to render links and make the entire reference/substitution system behave properly, as the standard text renderer is stupendously silly when it comes to this.

the text builder only does multipage, so this does a single html text and then runs it through bs4 to fi

build(srcdir: str, tags: List[str], prolog: DocNamespace, epilog: DocNamespace | None = None, overrides: Dict[str, Any] = {})

creates sphinx app and builds the project

class lbn.aidoc.sphinxj2.TidyText(visit_tokens: bool = True)

Bases: Transformer

reassembles text document based upon our grammar rules

TEXT(token)
bullet_item(children)
joined_text(children)
line(children)
newline(children)
ordinary_line(children)
start(children)
tight_list(children)
wrapped_text(children)
lbn.aidoc.sphinxj2.basic_to_text(html_content: str) str

High-Fidelity DOM Transformer. Surgically group list structures to enforce proper plain-text line-spacing.

lbn.aidoc.sphinxj2.extract_text(html)

remove sphinxtheme.bastion from html

lbn.aidoc.sphinxj2.jinjaEnv(loader=None)

we’re shipping a bunch of extensions for jinja/rst to make creating markup easier

lbn.aidoc.sphinxj2.suffix(builder)
lbn.aidoc.sphinxj2.underline_filter(text, char='=')

Returns a string of characters matching the length of the text.