# TeXSmith

[![CI](https://github.com/yves-chevallier/texsmith/actions/workflows/ci.yml/badge.svg)](https://github.com/yves-chevallier/texsmith/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/yves-chevallier/texsmith/branch/main/graph/badge.svg)](https://codecov.io/gh/yves-chevallier/texsmith)
[![PyPI](https://img.shields.io/pypi/v/texsmith.svg)](https://pypi.org/project/texsmith/)
[![Repo Size](https://img.shields.io/github/repo-size/yves-chevallier/texsmith.svg)](https://github.com/yves-chevallier/texsmith)
[![Python Versions](https://img.shields.io/pypi/pyversions/texsmith.svg?logo=python)](https://pypi.org/project/texsmith/)
[![License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md)

![MkDocs](https://img.shields.io/badge/MkDocs-1.6+-blue.svg?logo=mkdocs)
![MkDocs Material](https://img.shields.io/badge/MkDocs%20Material-supported-success.svg?logo=materialdesign)
![Python](https://img.shields.io/badge/Python-typed-blue.svg?logo=python)

TeXSmith is a [Python](https://www.python.org/) package and CLI tool to convert **Markdown** or **HTML** documents into **LaTeX** or **Typst**. It is designed to be extensible via templates and integrates with [MkDocs](https://www.mkdocs.org/) for generating printable documents from documentation sites.

<p align="center">
<!-- Absolute link for compatibility with PyPi -->
<img src="https://raw.githubusercontent.com/yves-chevallier/texsmith/master/docs/assets/ts-logo.svg" width="70%" />
</p>

## TL;DR

```bash
pip install texsmith
texsmith input.md input.bib -o build/ --build
```

Check the installed version with `texsmith --version` or in Python with `texsmith.get_version()`.

## Key features

- **MkDocs-native Markdown** – Ships with the same Material + pymdown extension stack you use in MkDocs, so tabs, callouts, annotations, tooltips, and data tables survive the conversion.
- **Typed IR with multiple backends** – Documents are lowered into a typed intermediate representation (`read(HTML) → IR → write(IR)`), then emitted as **LaTeX** (default) or **Typst** (experimental) via `--format`.
- **Template-first runtime** – Bundle multiple fragments into slots, merge front matter metadata, and emit LaTeX projects ready for Tectonic or latexmk with Docker-friendly manifests.
- **CLI and Python parity** – The Typer-powered CLI wraps the same ConversionService you can consume as a library, making CI/CD and notebooks behave like local runs.
- **Actionable diagnostics** – Structured emitters, verbosity switches, and `--debug` traces keep build issues debuggable even in automated pipelines.
- **Extensible converters** – Override Markdown parsers, add reader lowerings (`@reads`) and writer emitters (`@writes`), or ship diagram transformers (Mermaid, Draw.io, Svgbob) that plug directly into the pipeline.

## Installation

```bash
# uv (recommended for isolated CLI installs)
uv tool install texsmith

# pip / pipx
pip install texsmith
pipx install texsmith
```

TeXSmith targets Python 3.10+ and expects a LaTeX distribution (TeX Live, MiKTeX, or MacTeX) when you pass `--build` with the default LaTeX backend. Optional converters such as Mermaid rely on Docker (`minlag/mermaid-cli`) unless you register custom handlers.

To build with the **Typst** backend (`--format typst`), install the embedded compiler as an extra:

```bash
pip install "texsmith[typst]"
# or with uv
uv tool install "texsmith[typst]"
```

This bundles the `typst` PyPI package, so no system binary is required. A system `typst` on `PATH` (Homebrew, `cargo install typst-cli`, or a GitHub release) is detected automatically as a fallback. See the [Output backends guide](docs/guide/plumbing/backends.md) for details.

### Platform notes

- **Linux** – Install TeX Live (full) via your package manager or `install-tl`. When running inside CI containers, cache `~/.texliveYY` so repeated latexmk runs stay fast—or use the default Tectonic engine to minimise setup.
- **macOS** – Use [MacTeX](https://www.tug.org/mactex/) or `BasicTeX` plus the tlmgr packages reported by `texsmith --template <name> --template-info`. Homebrew’s `mactex` cask works well when paired with `uv`.
- **Windows** – TeXSmith runs via native Python or WSL. For PDF builds we recommend [MiKTeX](https://miktex.org/) + PowerShell, or WSL2 with TeX Live and Docker Desktop (needed for Mermaid).
- **Docker workflows** – Run `texsmith --build` inside a TeX Live container, mounting your project plus the template directory. Copy tlmgr prerequisites from `--template-info` so images compile without network access.

See the [Getting Started guide](docs/guide/getting-started.md) for a step-by-step walkthrough, verification commands, and Python API examples.

## Documentation

Browse the full documentation at [yves-chevallier.github.io/texsmith](https://yves-chevallier.github.io/texsmith) for:

- [Getting Started](docs/guide/getting-started.md): installation, prerequisites, and API snippets.
- [CLI Reference](docs/cli/index.md): every flag, including the template inspector.
- [Markdown Directory](docs/markdown/supported.md): exhaustive syntax coverage.
- [API Reference](docs/api/index.md): ConversionService, TemplateSession, handlers, and plugins.
- [Template Cookbook](docs/guide/template-cookbook.md): practical recipes for slots, overrides, packaging, and testing.
- [Release Notes & Compatibility](docs/guide/release-notes.md): TeXSmith feature history plus template/TeX Live requirements.

## Template catalog

Inspect templates by name or path to understand their slots, metadata attributes, TeX Live requirements, and declared assets:

```bash
texsmith --template article --template-info
# or inspect a local path
texsmith --template ./templates/nature --template-info
texsmith templates  # view discovery order across built-ins/packages/local/home
```

Use this command before wiring slots or when you need to confirm which tlmgr packages to preinstall in CI.

## Examples

The `examples/` directory includes reproducible demos:

- `examples/paper` – end-to-end render with bibliographies and latexmk (or Tectonic with `--engine tectonic`).
- `examples/diagrams` – Mermaid and Draw.io conversions.
- `examples/markdown` – exhaustive Markdown showcase with diagram/front-matter overrides.

Each example ships build instructions inside [`docs/examples/index.md`](docs/examples/index.md).

## Project layout

The source tree is organised around three top-level namespaces:

- `texsmith.core` contains the conversion pipeline, document models, diagnostics, and template helpers.
- `texsmith.adapters` hosts infrastructure integrations such as Markdown parsing, LaTeX rendering, Docker helpers, and transformer utilities.
- `texsmith.ui` provides end-user interfaces, including the Typer-powered CLI.

## Core architecture highlights

- `ConversionService` encapsulates the orchestration that previously lived in `texsmith.api.service` helpers. Provide a `ConversionRequest` and receive a `ConversionResponse` with rendered bundles and diagnostics.
- `TemplateRenderer` now owns slot aggregation and LaTeX assembly. `TemplateSession` focuses on session state, template options, and bibliography tracking.
- `DocumentSlots` unify slot directives from front matter, CLI flags, and programmatic overrides. Every entry point now speaks the same data model.
- `DiagnosticEmitter` replaces ad-hoc callback bags so warnings, errors, and structured events flow through a predictable interface (CLI uses `CliEmitter`; libraries can plug in their own).
- Fragments use a `BaseFragment` + config dataclass model (`fragment = YourFragment()` export referenced by `fragment.toml` entrypoints). No legacy factories remain.

### Programmatic conversions with `ConversionService`

```python
from pathlib import Path

from texsmith import ConversionRequest, ConversionService

service = ConversionService()
request = ConversionRequest(
    documents=[Path("docs/index.html")],
    bibliography_files=[Path("references.bib")],
    template="article",
    render_dir=Path("build"),
)
prepared = service.prepare_documents(request)
response = service.execute(request, prepared=prepared)

print("Main TeX:", response.render_result.main_tex_path)
print("Diagnostics:", [event.name for event in response.diagnostics])
```

If you only need a quick conversion, the high-level helpers (`texsmith.Document`, `texsmith.convert_documents`, `texsmith.TemplateSession`) continue to work, but they now reuse the same ConversionService plumbing as the CLI.

> Refer to `UPGRADE.md` for release notes and migration guidance from earlier builds.

## Render pipeline

TeXSmith lowers every document into a typed intermediate representation (IR)
and then emits a backend from that IR:

```
read(HTML) → IR (texsmith.ir) → write(IR) → LaTeX | Typst
```

- **Readers** (`texsmith.readers.html`) turn BeautifulSoup nodes into
  backend-agnostic IR nodes. A reader lowering is a callable decorated with
  `@reads(*tags, level, priority, name)`; it *returns* an IR node and never
  mutates the tree.
- **IR** (`texsmith.ir`) is a typed, backend-neutral node tree. Semantic hints
  travel as `Span`/`Div` attributes rather than backend strings.
- **Writers** emit a backend from the IR. `texsmith.writers.latex.LaTeXWriter`
  (default) and `texsmith.writers.typst.TypstWriter` register emitters with
  `@writes(NodeType)`, dispatched by node class along the MRO. A node without
  an emitter raises a clear, localised error naming the node and backend.

Select the backend with `--format {latex,typst}`. See the
[Output backends guide](docs/guide/plumbing/backends.md) and the
[Readers & Writers reference](docs/api/handlers.md) for the decorators and a
runnable extension example.
