Metadata-Version: 2.4
Name: doxtr-hugo
Version: 0.1.0
Summary: Sphinx builder that generates Hugo-ready Markdown and assets from a Sphinx project.
Author: Jens Frey
License-Expression: MIT
Project-URL: Homepage, https://github.com/doxtr/doxtr-hugo
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Framework :: Sphinx :: Extension
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: sphinx>=5.0
Provides-Extra: diagrams
Requires-Dist: sphinxcontrib-plantuml>=0.9; extra == "diagrams"
Requires-Dist: sphinxcontrib-mermaid>=0.9; extra == "diagrams"
Requires-Dist: doxtr-d2>=0.1; extra == "diagrams"
Requires-Dist: diagrams>=0.23; extra == "diagrams"
Provides-Extra: yaml
Requires-Dist: PyYAML>=6.0; extra == "yaml"
Provides-Extra: all
Requires-Dist: doxtr-hugo[diagrams]; extra == "all"
Requires-Dist: doxtr-hugo[yaml]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: doxtr-hugo[all]; extra == "dev"
Dynamic: license-file

# doxtr-hugo

A [Sphinx](https://www.sphinx-doc.org/) builder for the
[doxtr](https://github.com/doxtr) ecosystem that turns a Sphinx documentation
source into content for the [Hugo](https://gohugo.io/) static site generator.

Author in reStructuredText/Sphinx and deploy the result as a Hugo site: the
extension adds a `hugo` builder (`sphinx-build -b hugo`) that walks the resolved
doctree and emits one Markdown file per document plus co-located assets, laid
out as a buildable Hugo site. It emits only formats Hugo renders natively
(CommonMark/Goldmark Markdown with front matter, and diagrams/figures
pre-rendered to static images — SVG preferred, PNG fallback), so no Hugo
modules, render-hook JavaScript, or the asset pipeline are required on the
consumer side.

> Status: early development. See `doxtr-hugo-implementation-guide.md` for the
> full specification and `IMPLEMENTATION_STATUS.md` for progress.

## Features

Supported constructs and capabilities:

- **Content translation** — section headings, paragraphs, inline markup
  (emphasis/strong/literal), bullet and enumerated lists (nested), line blocks,
  block quotes, definition lists, field lists, images and figures, and
  `.. rubric::`.
- **Code blocks** — literal/`.. code-block::` blocks emitted as fenced Goldmark
  code blocks with language hints.
- **Tables** — GFM pipe tables by default, with a raw-HTML fallback for cells
  that span rows/columns (`doxtr_hugo_tables`).
- **Admonitions** — typed directives (note, warning, tip, caution, danger,
  error, hint, important, attention, seealso) and generic `.. admonition::`
  titles, emitted as a Hugo shortcode by default or portable raw HTML
  (`doxtr_hugo_admonitions`).
- **Cross-references** — `:doc:`/`:ref:` and internal references emitted as Hugo
  `{{< relref >}}` (build-time validated) by default, or plain relative links
  (`doxtr_hugo_link_style`); external links and raw-HTML passthrough.
- **toctree → sections** — toctree drives the Hugo section/weight model (branch
  vs. leaf pages, deterministic per-parent weights, `_index.md` generation) and
  on-page navigation lists, with no hand-written front matter.
- **Diagrams** — five backends pre-rendered to static images: PlantUML,
  Graphviz, Mermaid, d2 (`doxtr_d2`), and sphinx_diagrams (the `diagrams`
  Python library, PNG-only). SVG is preferred, PNG is the portable fallback,
  and a missing backend degrades gracefully (`doxtr_hugo_on_missing_backend`).
  Custom backends register via `doxtr_hugo.register_backend`.
- **Math** — pre-rendered to transparent PNG by default (zero extra binary via
  matplotlib mathtext), with `mathjax` and `mathml-passthrough` opt-in
  (`doxtr_hugo_math`).
- **Invisible nodes** — RST comments (`.. a comment`), substitution
  *definitions*, docutils system messages, `.. meta::`, and transform
  `pending` placeholders are stripped from the output (their text never leaks
  into the page); resolved substitution *usages* still render.

## Installation

```bash
pip install doxtr-hugo
```

The diagram backends are optional. To pull in the Sphinx-side extensions that
provide diagram directives (PlantUML, Mermaid, d2, and the `diagrams` library),
install the `diagrams` extra:

```bash
pip install "doxtr-hugo[diagrams]"
```

To install every optional feature at once (all diagram backends plus PyYAML for
YAML front matter), use the `all` extra:

```bash
pip install "doxtr-hugo[all]"
```

The external rendering binaries (`plantuml`, `dot`, `mmdc`, `d2`) are **not**
Python dependencies — the builder only invokes them when present on `PATH` and
degrades gracefully otherwise (`doxtr_hugo_on_missing_backend`).

## Usage

Enable the extension in your Sphinx `conf.py`:

```python
extensions = [
    "doxtr_hugo",
]
```

Then build the Hugo site:

```bash
# Either form works:
make hugo                               # -> build/hugo/
# or:
sphinx-build -b hugo source build/hugo
```

## Previewing locally

The extension does **not** ship or modify any `Makefile`. Registering the
builder via `app.add_builder()` is the entire integration surface; the
`Makefile` generated by `sphinx-quickstart` already forwards unknown targets to
`sphinx-build`, so `make hugo` works without any extension-side change.

With the default `doxtr_hugo_emit_skeleton = "full"`, the output in
`build/hugo/` is a self-contained, runnable Hugo site:

```bash
# Build the Hugo site (either form works)
make hugo                               # -> build/hugo/
# or:
sphinx-build -b hugo source build/hugo

# Preview it (requires the default emit_skeleton = "full")
cd build/hugo
hugo server
```

Notes:

- The output lands in **`build/hugo/`** (the `make`/`sphinx-build` BUILDDIR),
  which is a self-contained, runnable Hugo site because the builder's
  `finish()` emitted `hugo.toml` + `layouts/`.
- `hugo server` requires `emit_skeleton = "full"` (the default). In
  `"content-only"` mode there is no `hugo.toml`/`layouts/`, so preview must
  happen from within the consumer's own Hugo project.
- Drafts: pages are emitted with `draft = false`, so plain `hugo server` shows
  them; `hugo server -D` is only needed if the consumer later sets pages to
  draft.

## Using with a third-party Hugo theme

The default `emit_skeleton = "full"` output ships doxtr-hugo's own
`layouts/_default/` so the site builds standalone. Those layouts **override a
theme**: Hugo's template precedence puts a site-level `layouts/_default/` above
any `--theme`, so building the full output under a theme makes every theme
render the skeleton's HTML rather than its own. To deploy under a third-party
theme, emit the **theme-portable** form instead:

```bash
sphinx-build -b hugo \
  -D doxtr_hugo_emit_skeleton=content-only \
  source build/hugo-content
```

- `doxtr_hugo_emit_skeleton = "content-only"` writes only `content/**` (section
  `_index.md` files + co-located assets) — no `hugo.toml`, no `layouts/`. Drop
  that `content/**` into your own themed Hugo site.
- In `content-only` mode the builder defaults `doxtr_hugo_admonitions` to
  `"html"` automatically (portable raw HTML), because a third-party theme does
  **not** ship doxtr-hugo's `admonition` shortcode — shortcode admonitions would
  fail there with `template for shortcode 'admonition' not found`. Set
  `doxtr_hugo_admonitions` explicitly to override (e.g. `"shortcode"` if your
  site provides its own `admonition` shortcode).
- If you instead keep the default `"full"` emit and add a theme, be aware the
  emitted `layouts/` will shadow the theme; use `"content-only"` (above) for
  real theme deployment.

See the configuration knobs `doxtr_hugo_emit_skeleton` and
`doxtr_hugo_admonitions` for the full surface.

## Configuring a theme (ready-to-serve output)

Instead of hand-assembling a themed site from the `content-only` output, you
can configure the theme **once in your Sphinx `conf.py`** and have
`sphinx-build -b hugo` emit a complete, version-controllable Hugo site under
`build/hugo/` whose `hugo.toml` is correctly configured for that theme:

```python
# conf.py
doxtr_hugo_theme = "docsy"            # a shipped profile, or any theme name

doxtr_hugo_theme_config = {           # deep-merged into hugo.toml (you win)
    "params": {"github_repo": "https://github.com/me/docs"},
}

# Optional: override how the theme is obtained (defaults to a Hugo Module).
doxtr_hugo_theme_source = {"kind": "module", "url": "github.com/google/docsy"}
```

Building then produces, in `build/hugo/`:

- a merged `hugo.toml` = **core defaults** (goldmark `unsafe` + extensions) +
  the **theme profile** (e.g. docsy's `type="docs"` cascade, hugo-book's
  `BookSection="*"`) + **your** `doxtr_hugo_theme_config` (highest precedence);
- a `README-hugo.md` listing the exact one-time commands still needed for that
  theme (e.g. `hugo mod get`, installing Dart Sass, `npm install`) before
  `hugo server` — the extension documents these, it never runs them;
- the image render hook so math/diagram images resolve under any theme.

Shipped profiles (edition/toolchain/config captured so the output just works):
`archie`, `hugo-terminal`, `hyde`, `risotto`, `notepadium`, `hugo-book`,
`docsy`. A theme with no shipped profile still works — it is emitted with core
defaults plus your `doxtr_hugo_theme_config`, and you supply the theme + config.

The emitted `build/hugo/` is Hugo **input**: commit it, then run the README's
commands and `hugo server`. For light themes vendored into `themes/` nothing
extra is needed; SCSS themes like docsy require the documented extended
Hugo + Dart Sass + npm steps.

### Overlay (escape hatch) and hooks

Anything the declarative config cannot express goes in a **sidecar overlay**
directory, copied verbatim into `build/hugo/` on top of the emitted site (your
files win):

```
source/.doxtr/hugo/            # doxtr_hugo_theme_overlay_dir (confdir-relative)
  config/overlay.toml          # extra raw Hugo config fragments
  layouts/partials/head.html   # custom/partial template overrides
  assets/scss/_variables_project.scss
  static/img/logo.png
```

The extension auto-excludes `.doxtr/**` from Sphinx's document scan, so overlay
files are never parsed as reStructuredText. For programmatic post-processing,
`doxtr_hugo_theme_hook = "mypkg.mymod:callable"` runs your own project code last
(called with `outdir`, `config`, `app`), after all files are written.

Configuration keys: `doxtr_hugo_theme`, `doxtr_hugo_theme_config`,
`doxtr_hugo_theme_source`, `doxtr_hugo_theme_overlay_dir`,
`doxtr_hugo_theme_hook`.

### Page titles (no duplicate heading)

By default (`doxtr_hugo_title_heading = "frontmatter"`) the page's leading
top-level heading is **not** emitted into the Markdown body — it is carried by
the `title` front matter, which every Hugo theme (and the built-in skeleton)
renders. Emitting it in the body too would show the title twice. Deeper headings
(`##` and below) are always kept. Set `doxtr_hugo_title_heading = "body"` to
restore the legacy behavior of writing the leading `# Title` into the body (for
a theme that does not render `.Title` itself).

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for the release history.

## License

MIT — see [LICENSE](LICENSE).
