Skip to main content

zensical-glossary

PyPI version Python versions License Documentation

Add hover tooltips and glossary links to a Zensical site from one or more Markdown glossary pages.

Write your terms once in docs/glossary.md — spread them across several domain-focused pages, or define them inline on any page with a comment marker. Everywhere else in your docs, matching words are automatically underlined, show a short definition on hover, and link back to the full definition.

Why Use It

  • Keep terminology consistent and easily accessible across docs.
  • Give readers quick definitions without interrupting the page.
  • Link every term back to a canonical glossary entry.
  • Organize large glossaries into sections without turning section headings into terms.
  • Spread terms across several glossary pages, organized by domain, and have them merged at build time.
  • Define terms inline on any page with a comment marker — no glossary file maintenance.
  • Add aliases to a term, so plural forms and alternative wordings also match and link back.
  • Use normal Python-Markdown and Zensical configuration.

Origin

This extension has its origin in the necessity of generating richer documentation for the POG Programming Language (still to be released). As the language has too many domain specific terms, it is better to have them at hand instead of jumping back-and-forth between a glossary and the page the reader is currently at.

We've decided to publish it before POG, since it has been proven extremely useful in our internal documentations.

Install

In a Zensical project:

uv add zensical-glossary

Or with pip:

pip install zensical-glossary

For local development in this repository:

uv pip install -e .

Quick Start

Create docs/glossary.md:

# Glossary

## Core concepts

### Zensical

Zensical is a modern static site generator with a Rust core and a Python
Markdown pipeline.

### Markdown

Markdown is a lightweight plain-text formatting syntax that is converted to
HTML.

Enable the extension in zensical.toml:

[project.markdown_extensions.zensical_glossary]
glossary_file = "glossary.md"
heading_level = 3
first_only = true

Now any page can simply mention Zensical or Markdown. The extension wraps those terms with a tooltip and a link to /glossary/#zensical or /glossary/#markdown.

Run the site:

uv run zensical serve

Build it:

uv run zensical build --clean

Glossary Format

By default, heading_level = 2, so every ## Term in the glossary file is a term.

For larger glossaries, use shallower headings for sections and set heading_level to the exact level that contains terms:

# Glossary

## Authoring

### Admonition

An admonition is a callout block such as a note, warning, or tip.

### Front matter

Front matter is metadata at the top of a Markdown file.
[project.markdown_extensions.zensical_glossary]
heading_level = 3

Deeper headings remain part of the current term definition instead of becoming separate glossary entries.

Multiple Glossary Pages

For bigger knowledge bases, spread terms across several pages — for example one page per domain — and list them with glossary_files:

[project.markdown_extensions.zensical_glossary]
glossary_files = [
  "glossary/core.md",
  "glossary/api.md",
]
heading_level = 3

Entries may also be glob patterns, expanded against docs_dir and sorted for deterministic builds:

glossary_files = ["glossary/**/*.md"]

All files are merged into a single term index at build time:

  • Files are processed in configuration order. If two pages define the same term, the first file wins.
  • Each term links to the page that defines it, e.g. /glossary/api/#widget.
  • Every glossary source page is skipped during annotation, so glossary pages never link to themselves.
  • Parsed pages are cached by modification time, and the merged index and term regex are built once per build, so watch-mode rebuilds stay fast.

glossary_files takes precedence over glossary_file when both are set, so a single-page setup keeps working unchanged.

Inline Definitions

For terms that are best explained where they are used, skip glossary files entirely and mark a definition directly on any regular page:

<!-- zensical-glossary: Widget -->

A widget is a reusable UI unit that...

The paragraphs after the marker — up to the next heading or the next marker — become the definition. The marker renders as an invisible anchor (#widget), and every other mention of the term on the site links to it.

Enable the mode with:

[project.markdown_extensions.zensical_glossary]
inline_definitions = true

All pages are scanned once per build (cached by modification time) and merged with any glossary files into a single index — a hybrid glossary. When a term is defined both inline and in a glossary file, the glossary file wins. A page never links to the terms it defines itself.

Aliases

Prose rarely uses the exact glossary wording — plural forms, alternative spellings, or a fuller name for an acronym. Add an alias marker inside a term's definition block and every comma-separated alias also matches in prose, showing the canonical definition and linking to the canonical anchor:

### API
<!-- zensical-glossary-aliases: Application Programming Interface -->

A set of rules that lets one program request services from another.

In inline mode, the marker goes right after the definition marker:

<!-- zensical-glossary: Widget -->
<!-- zensical-glossary-aliases: gadget, widgets -->

A widget is a reusable unit that...

The marker renders as an invisible HTML comment and never appears in the tooltip. Aliases follow the same matching rules as terms:

  • Case-insensitive by default (case_sensitive applies to both).
  • The longest surface wins: a multi-word alias matches as one unit instead of a shorter term inside it.
  • first_only counts the term and its aliases as one entry per page.
  • min_length filters out aliases that are too short.
  • On collision, the first definition wins: a real term always beats an alias, and among aliases the earliest one wins.

Configuration

All options live under [project.markdown_extensions.zensical_glossary].

Option Type Default Description
glossary_file str "glossary.md" Glossary source, relative to docs_dir.
glossary_files list [] Multiple glossary sources (paths or globs). Wins over glossary_file.
inline_definitions bool false Scan all pages for <!-- zensical-glossary: Term --> definitions.
heading_level int 2 Exact heading level treated as terms; shallower headings can be sections.
first_only bool true Annotate only the first occurrence of each term per page.
case_sensitive bool false Match terms case-sensitively.
min_length int 2 Ignore terms shorter than this.
max_definition int 280 Truncate tooltip text to this many characters.
base_url str derived Single file: override the glossary URL. Multiple files: URL prefix.
language str site language UI language for tooltip text: en, fr, es, pt.
labels table {} Override UI strings, e.g. labels = { more = "Read more" }.
docs_dir str "docs" Fallback docs directory if it cannot be read from Zensical config.

For GitHub Pages project sites, set base_url when your site is served from a repository subpath. With a single glossary file it is the full glossary URL; with glossary_files it is a prefix joined with each derived page URL:

[project.markdown_extensions.zensical_glossary]
# Single file:
base_url = "https://OWNER.github.io/REPOSITORY/glossary/"

# Multiple files (terms link to https://OWNER.github.io/REPOSITORY/glossary/api/#term):
glossary_files = ["glossary/*.md"]
base_url = "https://OWNER.github.io/REPOSITORY"

Example Project

This repository includes a complete Zensical example in docs/. It is the same site that can be published with the included GitHub Pages workflow.

uv run zensical serve
uv run zensical build --clean

The workflow at .github/workflows/docs.yml builds site/ and deploys it to GitHub Pages on pushes to master.

Local Development

This repository uses the drun automation language for local automation.

Use xdrun --list to see the available tasks.

xdrun test
xdrun build
xdrun rebuild
# xdrun ci is optimized for LLMs and MCPs, it only generates
# verbose output in the case an error is thrown. Saves input tokens.
xdrun ci
# For seeing everything the CI is outputting, use:
xdrun ci --task-mode normal
  • test runs the Python test suite.
  • build creates package artifacts and builds the example site.
  • rebuild removes generated outputs first, then builds everything again.
  • ci runs the full local verification lifecycle, including package metadata checks.

GitHub Actions runs the same xdrun ci pipeline in .github/workflows/ci.yml for pull requests and pushes.

Releasing

Releases are prepared with:

xdrun prepare-release version=X.Y.Z

This checks that the version is newer than the latest release, runs the full CI pipeline, promotes the unreleased changelog entries to the new version, syncs the version across the drun spec, pyproject.toml, and the package, and rebuilds the distribution artifacts. After reviewing the changes, commit, tag vX.Y.Z, and push the tag — the workflow at .github/workflows/release.yml builds and publishes to PyPI.

Internationalization

The tooltip UI text is localized separately from your glossary content. The language is resolved in this order:

  1. The extension's language option.
  2. The Zensical site language.
  3. English.

Supported built-in languages are English (en), French (fr), Spanish (es), and Portuguese (pt). Region subtags are ignored, so pt-BR resolves to pt.

Override a label directly:

[project.markdown_extensions.zensical_glossary]
language = "fr"
labels = { more = "Voir la definition complete" }

How It Works

The extension parses the glossary files and scans pages for inline definition markers, merges everything into one term index, and uses a treeprocessor to wrap matching text in rendered pages. Each term links to the page that defines it. It skips code, links, abbreviations, headings, the glossary pages themselves, and each term's own defining page. A postprocessor injects the tooltip CSS and JavaScript only on pages where at least one term was found. Source files are cached by modification time, so unchanged content is never re-parsed during a build or watch session.

License

MIT

Metadata

Release files for zensical-glossary 1.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zensical-glossary 1.2.1
File Size Uploaded
zensical_glossary-1.2.1.tar.gz 31.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for zensical-glossary 1.2.1
File Interpreter ABI Platform
zensical_glossary-1.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 49.3 kB

Release files / zensical_glossary-1.2.1.tar.gz

Download URL zensical_glossary-1.2.1.tar.gz
Size 31.1 kB
Tags Source
SHA-256 checksum
How to use checksums
8e8817d23d35014997070d72dc0d697978518e4574668827e634638733fbaee5
BLAKE2b-256 checksum
How to use checksums
228b255d1f4552f2e308611aa22db3f61fb83b0148b75c67cb92c2d207ff24b2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release files / zensical_glossary-1.2.1-py3-none-any.whl

Download URL zensical_glossary-1.2.1-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
05e637767dd4def1c109140cf34c89600d8f6f68c60a88dafa6c174689ecfb3d
BLAKE2b-256 checksum
How to use checksums
f722902eccdaa015e0a98e51e3222c30c458b182e3302e6e1ad37b7f301158c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release history Release notifications | RSS feed

This release

1.2.1 This release

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page