Skip to main content

Semantic line break formatter for Org, LaTeX, Markdown, and plaintext

Project description

img

Table of Contents

About

A fast, format-aware semantic line break formatter. Reformats prose so each sentence occupies its own line, producing minimal and meaningful git diffs when collaborating on documents.

Why?

When multiple authors collaborate on a paper using Git, traditional line wrapping at a fixed column width causes problems. A single word change can trigger a diff that spans an entire paragraph. By breaking at sentence boundaries instead, each edit affects only the sentence that changed.

This convention, often called "semantic linefeeds," enjoys longstanding support from technical writers. Existing tools fall short: latexindent.pl only handles LaTeX, SemBr requires Python and neural networks, and most lack multi-format awareness. snapper solves this as a standalone Rust binary with no runtime dependencies, handling Org-mode, LaTeX, Markdown, and plaintext.

Design

snapper runs a three-stage pipeline:

  • Parse: Classify input into prose regions and structure regions
  • Split: Detect sentence boundaries in prose regions
  • Emit: Output each sentence on its own line

Structure regions (code blocks, math environments, tables, front matter, drawers, comments) pass through unchanged. Sentence detection relies on Unicode UAX #29 segmentation with abbreviation-aware post-processing that avoids false breaks at titles (Dr., Prof.), references (Fig., Eq.), and Latin terms (e.g., i.e., et al.).

Installation

Pre-built binary (fastest):

cargo binstall snapper-fmt

Shell one-liner (Linux/macOS):

curl -LsSf https://github.com/TurtleTech-ehf/snapper/releases/latest/download/snapper-fmt-installer.sh | sh

Homebrew:

brew install TurtleTech-ehf/tap/snapper-fmt

pip:

pip install snapper-fmt

Compile from source:

cargo install snapper-fmt

Nix:

nix build github:TurtleTech-ehf/snapper

The crate is snapper-fmt on all registries; the binary it installs is snapper.

Usage

Format a file (output to stdout):

snapper paper.org

Format in place:

snapper --in-place paper.org

Pipe through stdin (for editor integration):

cat draft.org | snapper --format org

Check formatting without modifying (for CI):

snapper --check paper.org paper.tex notes.md

Limit line width (wrap long sentences at word boundaries):

snapper --max-width 80 paper.org

Preview changes as a unified diff before committing:

snapper --diff paper.org

Compare two versions at the sentence level (whitespace reflow produces zero diff):

snapper sdiff paper_v1.org paper_v2.org

Watch files and auto-reformat on save:

snapper watch '*.org' 'sections/*.tex'

Initialize a project (generates config, pre-commit, gitattributes):

snapper init

Supported formats

Format Extensions Structure preserved
Org-mode .org Blocks, drawers, tables, keywords
LaTeX .tex, .latex Preamble, math, environments, comments
Markdown .md, .markdown Code blocks, front matter, HTML
Plaintext everything else (none; all text treated as prose)

Pre-commit hook

- repo: https://github.com/TurtleTech-ehf/snapper
  rev: v0.1.0
  hooks:
    - id: snapper

Emacs (Apheleia)

(with-eval-after-load 'apheleia
  (push '(snapper . ("snapper" "--format" "org")) apheleia-formatters)
  (push '(org-mode . snapper) apheleia-mode-alist))

Git smudge/clean filter

Auto-format on commit, transparent to collaborators:

git config filter.snapper.clean "snapper --format org"
git config filter.snapper.smudge cat

Then add to .gitattributes:

*.org filter=snapper

Vale integration

snapper ships a vale style package for editor hints. Add to your .vale.ini:

StylesPath = /path/to/snapper/vale
[*.org]
BasedOnStyles = snapper

For precise CI checks, use snapper --check directly.

Project config

Drop a .snapperrc.toml in your project root:

extra_abbreviations = ["GROMACS", "LAMMPS", "DFT"]
ignore = ["*.bib", "*.cls"]
format = "org"
max_width = 0

snapper walks up from the current directory to find it.

Documentation

Build the docs site with:

pixi run docbld

Development

Key dependencies

  • Clap 4 (derive): CLI argument parsing
  • unicode-segmentation: UAX #29 sentence boundaries
  • regex: Abbreviation and format pattern matching
  • textwrap: Optional line width limiting
  • thiserror: Typed error handling

Conventions

We use cocogitto via cog to handle commit conventions.

Readme

Construct the readme via:

./scripts/org_to_md.sh readme_src.org README.md

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

snapper_fmt-0.6.0.tar.gz (1.4 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

snapper_fmt-0.6.0-py3-none-win_amd64.whl (7.2 MB view details)

Uploaded Python 3Windows x86-64

snapper_fmt-0.6.0-py3-none-manylinux_2_28_aarch64.whl (6.3 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ ARM64

snapper_fmt-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

snapper_fmt-0.6.0-py3-none-macosx_11_0_arm64.whl (6.1 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

snapper_fmt-0.6.0-py3-none-macosx_10_12_x86_64.whl (6.7 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file snapper_fmt-0.6.0.tar.gz.

File metadata

  • Download URL: snapper_fmt-0.6.0.tar.gz
  • Upload date:
  • Size: 1.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snapper_fmt-0.6.0.tar.gz
Algorithm Hash digest
SHA256 422c6d80f77d0fc60654e5b912ffb32253b1534dc6431deccb6a4f7f85ff15bf
MD5 56af3ef2d92d51bd72774ec24ead3ae3
BLAKE2b-256 8a68a328c8beff29305f84a739b7126f3ad6f9845844704e94b88e46534b853c

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.6.0.tar.gz:

Publisher: pypi.yml on TurtleTech-ehf/snapper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snapper_fmt-0.6.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: snapper_fmt-0.6.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 7.2 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snapper_fmt-0.6.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 ac32f24ec2584e31183d0694b6fda82d4e6044a2cb032da363e81fc7ff6423c7
MD5 ef8f223aee06230a4af10844a83b4906
BLAKE2b-256 f59730f1bc68ca94173877f46c9b1e4ad87f2fdf64f0f751ddcddd16673984e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.6.0-py3-none-win_amd64.whl:

Publisher: pypi.yml on TurtleTech-ehf/snapper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snapper_fmt-0.6.0-py3-none-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.6.0-py3-none-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 479856dad68db1f6d12d6e07313aa84b750c6ebebd1dc1bf7413eee6c2b5dbd5
MD5 40a06f172866667cdac8f1c90922250c
BLAKE2b-256 cf10a9df30a72fa23c959f6645e656ed153634207c91c575aeedaaf4765bc5ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.6.0-py3-none-manylinux_2_28_aarch64.whl:

Publisher: pypi.yml on TurtleTech-ehf/snapper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snapper_fmt-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 34794efc106dd44c942d017ba071d5e8933dd910c5efa9822c63b7143ba756ed
MD5 798afa1d72b2ae8d79c57ecd46bf470c
BLAKE2b-256 9048fdca7622faadaaf649501ea4f6cfed5ed697d69eb1659755582f199526b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.6.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: pypi.yml on TurtleTech-ehf/snapper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snapper_fmt-0.6.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.6.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4b54ec12ff328cdfcf4598462dc5ebd9f7b4aae5516b1c7c845bf59f21f57d63
MD5 f02f2a58d6c1fa95953ee1690021f09d
BLAKE2b-256 a9e740014dda3dc7ae8399f74c68a01e208ee8f322b2c9c66c1097a431243989

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.6.0-py3-none-macosx_11_0_arm64.whl:

Publisher: pypi.yml on TurtleTech-ehf/snapper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snapper_fmt-0.6.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.6.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 247b59af68ec2e565c48a15abbaac3f8f4cb21e9071543c21b7d64d46a5d09be
MD5 a8d1b6bcb6cc6f31ff8d49b9b03a69fc
BLAKE2b-256 be93b6c34f972922e79201b5edd1a6d1dd08a094f9fe1f9f81d4098e59f74c91

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.6.0-py3-none-macosx_10_12_x86_64.whl:

Publisher: pypi.yml on TurtleTech-ehf/snapper

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page