Metadata-Version: 2.4
Name: typdiff
Version: 0.1.2
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
License-File: LICENSE
Summary: Python bindings for typdiff, a diff tool for Typst documents
License-Expression: Apache-2.0
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/imphil/typdiff-py
Project-URL: Readme, https://github.com/imphil/typdiff-py/blob/main/README.md
Project-URL: Repository, https://github.com/imphil/typdiff-py
Project-URL: typdiff (Rust CLI), https://github.com/sou1118/typdiff

# typdiff-py

![CI](https://github.com/imphil/typdiff-py/workflows/CI/badge.svg)
[![PyPI](https://img.shields.io/pypi/v/typdiff.svg)](https://pypi.org/project/typdiff)

Python bindings for [typdiff](https://github.com/sou1118/typdiff), a diff tool for [Typst](https://typst.app/) documents, similar to [latexdiff](https://github.com/ftilmann/latexdiff) for LaTeX.

`typdiff` compares two Typst source files and generates a new Typst document that visually highlights the differences — <ins>added text</ins> in blue with underline and <del>deleted text</del> in red with strikethrough. This package wraps the [`typdiff`](https://crates.io/crates/typdiff) Rust crate directly via [pyo3](https://pyo3.rs/) (no subprocess, no separate binary to install) and ships prebuilt wheels for Linux (x86_64/aarch64/armv7/s390x/ppc64le), macOS, and Windows.

This is an independent, standalone project — the `typdiff` maintainer preferred to keep Python bindings out of the main repository, so they live here instead.

## Installation

```sh
pip install typdiff
```

## Usage

```python
import typdiff

diff = typdiff.diff(old_bytes, new_bytes)  # from bytes
diff = typdiff.diff_files("old.typ", "new.typ")  # from file paths (str or Path)
```

`diff()` takes and returns `bytes`, matching how [`typst`](https://pypi.org/project/typst/)'s `compile()` treats `bytes` as inline source (a plain `str` argument is instead treated as a path to read) — so `typdiff`'s output can be passed straight into `compile()`. `diff_files()` still takes file paths as `str`/`Path`, since those are paths rather than document content.

## Producing a PDF

Combine `typdiff` with `typst` (Python bindings for the Typst compiler, `pip install typst`) to go straight from two Typst files to a diff PDF, without shelling out to either CLI:

```python
import typdiff
import typst

diff = typdiff.diff_files("old.typ", "new.typ")
pdf_bytes = typst.compile(diff)
```

## Example

Given an old document:

```typst
= Introduction

This is the old text.

- First item
- Second item

== Details

The quick brown fox jumps over the lazy dog.
```

And a new document:

```typst
= Background

This is the new text.

- First item
- Third item
- Fourth item

== Details

The quick red fox leaps over the lazy cat.
```

`typdiff.diff_files("old.typ", "new.typ")` produces:

```typst
= #diff-deleted[Introduction]

= #diff-added[Background]

This is the #diff-deleted[old]#diff-added[new] text.

- First item

- #diff-deleted[Second]#diff-added[Third] item

- #diff-added[Fourth item]

== Details

The quick #diff-deleted[brown]#diff-added[red] fox #diff-deleted[jumps]#diff-added[leaps] over the lazy #diff-deleted[dog]#diff-added[cat].
```

## See also

- [`typdiff`](https://github.com/sou1118/typdiff) — the underlying Rust CLI and library.
- [`typst-py`](https://github.com/messense/typst-py) — Python bindings for Typst itself, used above to compile the diff output to a PDF.

## License

Apache-2.0

