fix(docs): title distro code blocks and fix missed shell highlighting #140

Merged
rootiest merged 2 commits from docs/troubleshooting-codeblock-titles into main 2026-09-09 04:43:51 +00:00
5 changed files with 96 additions and 18 deletions
+43 -2
View File
@@ -334,7 +334,16 @@ def _is_prose(para: list[str]) -> bool:
def _is_shell(para: list[str], entry_name: str | None) -> bool:
"""True when every line of a paragraph looks like a shell command."""
"""True when every line of a paragraph looks like a shell command.
Recognised command names are `SHELL_HEADS` plus the same code
vocabulary `codespans` wraps in backticks (repo function names and
`fish-deps` catalog entries included) — one shared list instead of a
second hand-maintained one that silently drifts, which is how
`fish-deps`/`config-settings`-style custom commands used to fall
through to an unhighlighted block.
"""
vocab = SHELL_HEADS | _code_vocabulary().full
name_re = (
re.compile(rf"(?<![\w-]){re.escape(entry_name)}(?![\w-])")
if entry_name
@@ -346,7 +355,7 @@ def _is_shell(para: list[str], entry_name: str | None) -> bool:
continue
if name_re and name_re.search(stripped):
continue
if stripped.split()[0].lstrip("$").rstrip(";") not in SHELL_HEADS:
if stripped.split()[0].lstrip("$").rstrip(";") not in vocab:
return False
return True
@@ -361,6 +370,30 @@ PATH_LINE_RE = re.compile(r"^[~$][\w./{}-]*\.\w+$")
# as a literal comment inside the code.
FILENAME_COMMENT_RE = re.compile(r"^#\s*(?:in\s+)?([$~\w./-]+\.\w+)\s*$")
# A leading comment that isn't a filename can still name what the block is
# about (e.g. "# Arch / AUR" heading a distro's install command) rather
# than explain a step ("# Turn it off:") — the trailing-punctuation and
# length checks in `_label_title` are what tell the two apart.
LABEL_COMMENT_RE = re.compile(r"^#\s*(.+)$")
def _label_title(line: str) -> str | None:
"""A short, label-shaped leading comment, promoted to a fence title.
Anything that reads as a sentence — trailing `.`/`!`/`?`/`;`/`:`/`,`,
or just long — is left as a literal comment instead: it's explaining a
step, not naming the block.
"""
m = LABEL_COMMENT_RE.match(line)
if not m:
return None
text = m.group(1).strip()
if not text or text[-1] in ".!?;:,":
return None
if len(text) > 48 or len(text.split()) > 8:
return None
return text
CELL_SPLIT = re.compile(r"\s{2,}")
# A rule line under a header row — the "Component Reference" tables'
@@ -505,12 +538,20 @@ def _render_para(para: list[str], entry_name: str | None, deeper: bool) -> str:
path = para[0].strip()
name = path.rsplit("/", 1)[-1]
return f'```fish title="{name}"\n{path}\n```'
# Checked even when `deeper`: a shell paragraph's own nested indentation
# (a for/if/while body) must not be mistaken for a table's alignment —
# `_is_shell` only looks at each line's first word, so it stays safe to
# try before falling through to the table/text fallbacks below.
if _is_shell(para, entry_name):
body = para
title = None
m = FILENAME_COMMENT_RE.match(para[0].strip())
if m:
title, body = m.group(1), para[1:]
else:
label = _label_title(para[0].strip())
if label:
title, body = label, para[1:]
info = f'fish title="{title}"' if title else "fish"
return f"```{info}\n" + "\n".join(body) + "\n```"
table = _as_ruled_table(para) or _as_table(para) or _as_file_tree(para)
+4 -4
View File
@@ -3465,9 +3465,9 @@ category variable.
C5 Logging and Capture — Session logs, command duration
C6 Greeting & First-Run UI — Custom startup banner
Each category further sub-divides into two to six sub-categories (25 in
total) with their own `__fish_config_op_<category>_<subcategory>` toggles
-- see that category's page for its sub-category list.
Each category further sub-divides into several sub-categories, each with
its own `__fish_config_op_<category>_<subcategory>` toggle -- see that
category's page for its sub-category list.
## Per-function overrides: `C0`/`always`
@@ -4317,7 +4317,7 @@ Re-enable everything:
set -Ue __fish_config_opinionated
Each category also has two to six sub-categories (e.g.
Each category can also have several sub-categories (e.g.
`__fish_config_op_aliases_filesystem`) that can be checked, disabled, or
reset the same way — `set -U __fish_config_op_<category>_<subcategory> off`
and `set -Ue __fish_config_op_<category>_<subcategory>` work identically to
+3 -3
View File
@@ -19,9 +19,9 @@ category variable.
C5 [Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) — Session logs, command duration
C6 [Greeting & First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) — Custom startup banner
Each category further sub-divides into two to six sub-categories (25 in
total) with their own `__fish_config_op_<category>_<subcategory>` toggles
-- see that category's page for its sub-category list.
Each category further sub-divides into several sub-categories, each with
its own `__fish_config_op_<category>_<subcategory>` toggle -- see that
category's page for its sub-category list.
## Per-function overrides: `C0`/`always`
+1 -1
View File
@@ -237,7 +237,7 @@ Re-enable everything:
set -Ue __fish_config_opinionated
Each category also has two to six sub-categories (e.g.
Each category can also have several sub-categories (e.g.
`__fish_config_op_aliases_filesystem`) that can be checked, disabled, or
reset the same way — `set -U __fish_config_op_<category>_<subcategory> off`
and `set -Ue __fish_config_op_<category>_<subcategory>` work identically to
+37
View File
@@ -681,6 +681,43 @@ def test_prettify_titles_paths_and_commented_examples():
)
def test_prettify_titles_label_comments_but_not_explanations():
"""A short leading comment titles a shell block; a sentence stays a comment."""
import build_manual
distro = "\n".join([" # Arch / AUR", " pacman -S fish"])
out = build_manual.prettify(distro)
assert '```fish title="Arch / AUR"\npacman -S fish\n```' in out, (
f"a distro label comment was not promoted to the fence title:\n{out}"
)
explanation = "\n".join(
[" # Turn it off:", " set -U __fish_config_op_logging off"]
)
out = build_manual.prettify(explanation)
assert 'title=' not in out and "# Turn it off:" in out, (
f"a sentence-shaped comment was wrongly promoted to a title:\n{out}"
)
def test_prettify_highlights_nested_shell_and_custom_commands():
"""A for-loop's indented body and a repo-only command still get shell highlighting."""
import build_manual
loop = "\n".join(
[" for v in (set -Un | string match 'x*')", " set -Ue $v", " end"]
)
out = build_manual.prettify(loop)
assert out.startswith("```fish\n") and "```text" not in out, (
f"a nested for-loop body lost shell highlighting:\n{out}"
)
out = build_manual.prettify(" fish-deps sync")
assert out == '```fish\nfish-deps sync\n```', (
f"a repo function name was not recognised as a shell command:\n{out}"
)
def test_as_aside_converts_a_single_line_label():
"""A `LABEL: text` line becomes a titled <Aside> with the label's type."""
import build_manual