fix: wiki links now root-relative — handles Tolaria [[docs/path/to/page]] format
Some checks failed
Deploy Docs / deploy (push) Failing after 23s

Strips docs/ prefix from Tolaria-generated links, collapses /index suffixes,
removes .md extensions, and produces root-relative URLs (/page/path/) that
work from any page regardless of depth. Images get root-relative asset paths.
This commit is contained in:
Tolaria 2026-06-03 20:38:15 +08:00
parent fa0b34c3c2
commit a1db08f32e
2 changed files with 59 additions and 19 deletions

View file

@ -3,15 +3,19 @@ Python-Markdown extension: converts [[Wikilinks]] to standard Markdown links.
Mirrors the behavior of mkdocs-ezlinks-plugin's WikiLinkScanner, but as a
pure Markdown preprocessor (no MkDocs plugin API needed). Zensical handles
the resulting .md links natively.
the resulting links natively.
Syntax:
[[Page Name]] [Page Name](page-name.md)
[[Page Name|Display Text]] [Display Text](page-name.md)
[[Page Name#anchor]] → [Page Name](page-name.md#anchor)
[[Page Name#anchor|Text]] → [Text](page-name.md#anchor)
![[image.png]] ![image.png](image.png)
[[folder/Page Name]] [Page Name](folder/page-name.md)
[[Page Name]] [Page Name](/page-name/)
[[Page Name|Display Text]] [Display Text](/page-name/)
[[Page Name#anchor]] → [Page Name](/page-name/#anchor)
[[Page Name#anchor|Text]] → [Text](/page-name/#anchor)
![[image.png]] ![image.png](/image.png)
Tolaria-compatible: when the vault root is the project root, links like
``[[docs/contributing/index]]`` are stripped of the ``docs/`` prefix and
converted to root-relative URLs (e.g. ``/contributing/``) that work from
any page regardless of depth.
Code blocks (fenced and inline) are skipped wiki links inside them pass
through unchanged.
@ -44,6 +48,10 @@ _CODE_RE = re.compile(
re.DOTALL,
)
# Prefix to strip from Tolaria-generated links when the vault root is
# the project root (so links look like [[docs/foo/bar]]).
_DOCS_PREFIX = "docs/"
def _slugify(text: str) -> str:
"""Convert a human page name into a filename slug.
@ -58,8 +66,35 @@ def _slugify(text: str) -> str:
return slug
def _url_from_link(link: str) -> str:
"""Convert a wiki link target to a root-relative URL.
Handles Tolaria-style full paths: strips ``docs/`` prefix,
removes ``.md`` extension, collapses ``/index`` suffixes,
slugifies each component, and prepends ``/``.
"""
raw = link.strip()
# Strip .md extension
raw = re.sub(r"\.md$", "", raw, flags=re.IGNORECASE)
# Strip docs/ prefix (Tolaria vault root = project root)
if raw.lower().startswith(_DOCS_PREFIX):
raw = raw[len(_DOCS_PREFIX) :]
# Collapse trailing /index — section index pages resolve to the dir
raw = re.sub(r"/index$", "", raw)
if not raw:
return "/"
# Slugify each path component
parts = [_slugify(p) for p in raw.split("/") if p]
return "/" + "/".join(parts) + "/"
class WikilinksPreprocessor(Preprocessor):
"""Preprocessor that converts [[wikilinks]] to [text](slug.md)."""
"""Preprocessor that converts [[wikilinks]] to root-relative [text](/url/)."""
def run(self, lines: list[str]) -> list[str]:
text = "\n".join(lines)
@ -69,15 +104,12 @@ class WikilinksPreprocessor(Preprocessor):
result: list[str] = []
cursor = 0
for m in _CODE_RE.finditer(text):
# Transform the non-code region before this match
before = text[cursor : m.start()]
if before:
result.append(_WIKILINK_RE.sub(self._replace, before))
# Pass through the code region unchanged
result.append(m.group(0))
cursor = m.end()
# Transform any remaining text after the last code region
tail = text[cursor:]
if tail:
result.append(_WIKILINK_RE.sub(self._replace, tail))
@ -94,17 +126,25 @@ class WikilinksPreprocessor(Preprocessor):
if not (link or text or anchor):
return match.group(0)
slug = _slugify(link) if link else ""
href = slug
# Build the href: root-relative URL for pages; relative for images
if is_image:
# Images: keep filename, strip docs/ prefix, make root-relative
raw = link.strip()
if raw.lower().startswith(_DOCS_PREFIX):
raw = raw[len(_DOCS_PREFIX) :]
# Non-image assets might have extensions; keep them
href = raw if "." in raw else _slugify(raw)
if not href.startswith("/"):
href = "/" + href
else:
href = _url_from_link(link)
# Append anchor if present
if anchor:
anchor_slug = _slugify(anchor)
if anchor_slug:
href = f"{slug}#{anchor_slug}" if slug else f"#{anchor_slug}"
href = href.rstrip("/") + "#" + anchor_slug
if not href:
return match.group(0)
# Build standard markdown link / image
if is_image:
return f"![{text}]({href})"
else:

View file

@ -5,7 +5,7 @@ icon: simple/markdown
## Introduction to Markdown Language
Markdown is a simple language to build web pages. It is easier to read and write than HTML (the language web browsers read) and so we use it to write articles. You can use this reference to help you write posts and pages directly in our repository where the source documents for this wiki are held. See [[Contributing]] for more.
Markdown is a simple language to build web pages. It is easier to read and write than HTML (the language web browsers read) and so we use it to write articles. You can use this reference to help you write posts and pages directly in our repository where the source documents for this wiki are held. See [[docs/contributing/index]] for more.
## Headers