nixos-render-docs: genericize block numbering
examples and figures behave identically regarding numbering and titling, they just don't share a common number space. make the numbering/titling function generic over block types now so figures can just use it.
This commit is contained in:
parent
8c2d14a6b8
commit
e5e738b72a
@ -569,23 +569,24 @@ class HTMLConverter(BaseConverter[ManualHTMLRenderer]):
|
||||
self._redirection_targets.add(into)
|
||||
return tokens
|
||||
|
||||
def _number_examples(self, tokens: Sequence[Token], start: int = 1) -> int:
|
||||
def _number_block(self, block: str, prefix: str, tokens: Sequence[Token], start: int = 1) -> int:
|
||||
title_open, title_close = f'{block}_title_open', f'{block}_title_close'
|
||||
for (i, token) in enumerate(tokens):
|
||||
if token.type == "example_title_open":
|
||||
if token.type == title_open:
|
||||
title = tokens[i + 1]
|
||||
assert title.type == 'inline' and title.children
|
||||
# the prefix is split into two tokens because the xref title_html will want
|
||||
# only the first of the two, but both must be rendered into the example itself.
|
||||
title.children = (
|
||||
[
|
||||
Token('text', '', 0, content=f'Example {start}'),
|
||||
Token('text', '', 0, content=f'{prefix} {start}'),
|
||||
Token('text', '', 0, content='. ')
|
||||
] + title.children
|
||||
)
|
||||
start += 1
|
||||
elif token.type.startswith('included_') and token.type != 'included_options':
|
||||
for sub, _path in token.meta['included']:
|
||||
start = self._number_examples(sub, start)
|
||||
start = self._number_block(block, prefix, sub, start)
|
||||
return start
|
||||
|
||||
# xref | (id, type, heading inlines, file, starts new file)
|
||||
@ -636,7 +637,7 @@ class HTMLConverter(BaseConverter[ManualHTMLRenderer]):
|
||||
toc_html = f"{n}. {title_html}"
|
||||
title_html = f"Appendix {n}"
|
||||
elif typ == 'example':
|
||||
# skip the prepended `Example N. ` from _number_examples
|
||||
# skip the prepended `Example N. ` from numbering
|
||||
toc_html, title = self._renderer.renderInline(inlines.children[2:]), title_html
|
||||
# xref title wants only the prepended text, sans the trailing colon and space
|
||||
title_html = self._renderer.renderInline(inlines.children[0:1])
|
||||
@ -651,7 +652,7 @@ class HTMLConverter(BaseConverter[ManualHTMLRenderer]):
|
||||
return XrefTarget(id, title_html, toc_html, re.sub('<.*?>', '', title), path, drop_fragment)
|
||||
|
||||
def _postprocess(self, infile: Path, outfile: Path, tokens: Sequence[Token]) -> None:
|
||||
self._number_examples(tokens)
|
||||
self._number_block('example', "Example", tokens)
|
||||
xref_queue = self._collect_ids(tokens, outfile.name, 'book', True)
|
||||
|
||||
failed = False
|
||||
|
@ -1,6 +1,6 @@
|
||||
from abc import ABC
|
||||
from collections.abc import Mapping, MutableMapping, Sequence
|
||||
from typing import Any, cast, Generic, get_args, Iterable, Literal, NoReturn, Optional, TypeVar
|
||||
from typing import Any, Callable, cast, Generic, get_args, Iterable, Literal, NoReturn, Optional, TypeVar
|
||||
|
||||
import dataclasses
|
||||
import re
|
||||
@ -426,31 +426,37 @@ def _block_attr(md: markdown_it.MarkdownIt) -> None:
|
||||
|
||||
md.core.ruler.push("block_attr", block_attr)
|
||||
|
||||
def _example_titles(md: markdown_it.MarkdownIt) -> None:
|
||||
def _block_titles(block: str) -> Callable[[markdown_it.MarkdownIt], None]:
|
||||
open, close = f'{block}_open', f'{block}_close'
|
||||
title_open, title_close = f'{block}_title_open', f'{block}_title_close'
|
||||
|
||||
"""
|
||||
find title headings of examples and stick them into meta for renderers, then
|
||||
remove them from the token stream. also checks whether any example contains a
|
||||
find title headings of blocks and stick them into meta for renderers, then
|
||||
remove them from the token stream. also checks whether any block contains a
|
||||
non-title heading since those would make toc generation extremely complicated.
|
||||
"""
|
||||
def example_titles(state: markdown_it.rules_core.StateCore) -> None:
|
||||
def block_titles(state: markdown_it.rules_core.StateCore) -> None:
|
||||
in_example = [False]
|
||||
for i, token in enumerate(state.tokens):
|
||||
if token.type == 'example_open':
|
||||
if token.type == open:
|
||||
if state.tokens[i + 1].type == 'heading_open':
|
||||
assert state.tokens[i + 3].type == 'heading_close'
|
||||
state.tokens[i + 1].type = 'example_title_open'
|
||||
state.tokens[i + 3].type = 'example_title_close'
|
||||
state.tokens[i + 1].type = title_open
|
||||
state.tokens[i + 3].type = title_close
|
||||
else:
|
||||
assert token.map
|
||||
raise RuntimeError(f"found example without title in line {token.map[0] + 1}")
|
||||
raise RuntimeError(f"found {block} without title in line {token.map[0] + 1}")
|
||||
in_example.append(True)
|
||||
elif token.type == 'example_close':
|
||||
elif token.type == close:
|
||||
in_example.pop()
|
||||
elif token.type == 'heading_open' and in_example[-1]:
|
||||
assert token.map
|
||||
raise RuntimeError(f"unexpected non-title heading in example in line {token.map[0] + 1}")
|
||||
raise RuntimeError(f"unexpected non-title heading in {block} in line {token.map[0] + 1}")
|
||||
|
||||
md.core.ruler.push("example_titles", example_titles)
|
||||
def do_add(md: markdown_it.MarkdownIt) -> None:
|
||||
md.core.ruler.push(f"{block}_titles", block_titles)
|
||||
|
||||
return do_add
|
||||
|
||||
TR = TypeVar('TR', bound='Renderer')
|
||||
|
||||
@ -494,7 +500,7 @@ class Converter(ABC, Generic[TR]):
|
||||
self._md.use(_heading_ids)
|
||||
self._md.use(_compact_list_attr)
|
||||
self._md.use(_block_attr)
|
||||
self._md.use(_example_titles)
|
||||
self._md.use(_block_titles("example"))
|
||||
self._md.enable(["smartquotes", "replacements"])
|
||||
|
||||
def _parse(self, src: str) -> list[Token]:
|
||||
|
Loading…
Reference in New Issue
Block a user