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 line breaks, 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

Math environments, tables, front matter, drawers, and non-source comments pass through unchanged. Fenced and delimited source blocks are Region::Code: fence/open/close lines stay structure, non-comment code stays verbatim, and comment lines reflow at sentence boundaries when the language has a [code.<lang>] entry in .snapperrc.toml (snapper init seeds common languages). Pass --format-code to also pipe each block body through an optional per-language formatter argv (missing binary, non-zero exit, and timeouts degrade to the reflowed body). 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.). Org emphasis (*bold*, /italic/, _underline_, +strike+) is kept atomic so splits cannot open a pseudo-headline mid-span.

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

MCP server (AI assistants)

Expose snapper's tools to Claude Desktop, Claude Code, and other MCP clients:

npx @turtletech/snapper-mcp

Or directly:

snapper mcp

Tools: format_text, detect_format, check_formatting, split_sentences. Configuration guide (org source in-tree): docs/orgmode/howto/mcp-integration.org; HTML docs: https://snapper.turtletech.us/docs/howto/mcp-integration/ .

Supported formats

Format Extensions Structure / code handling
Org-mode .org Drawers, tables, keywords; #+BEGIN_SRC comment reflow
LaTeX .tex, .latex Preamble, math; minted and lstlisting comment reflow
Markdown .md, .markdown Front matter, HTML; fenced blocks comment reflow when configured
RST .rst Directives, literals; .. code-block:: comment reflow
Plaintext everything else (none; all text treated as prose)

Pre-commit hook

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

Emacs (Apheleia)

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

VS Code

Install TurtleTech.snapper from the VS Code Marketplace. The extension uses the built-in LSP server for format-on-save, range formatting, diagnostics, and code actions.

Neovim

With lazy.nvim (rocks support):

{
  "TurtleTech-ehf/snapper",
  ft = { "org", "tex", "markdown", "rst" },
  config = function()
    vim.opt.runtimepath:append(
      vim.fn.stdpath("data") .. "/lazy/snapper/editors/nvim"
    )
    require("snapper").setup()
  end,
}

Or with rocks.nvim:

:Rocks install snapper.nvim

Vim

Plug 'TurtleTech-ehf/snapper', { 'rtp': 'editors/vim' }

This provides formatprg support for automatic formatting with the gq operator.

Obsidian

Install the snapper plugin from Community Plugins (search "Snapper"). Uses WebAssembly -- no binary installation required.

Microsoft Word

Install the snapper add-in from AppSource (Insert > Get Add-ins > search "Snapper"). Uses WebAssembly -- no binary installation required.

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.7.8.tar.gz (1.5 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.7.8-py3-none-win_amd64.whl (7.3 MB view details)

Uploaded Python 3Windows x86-64

snapper_fmt-0.7.8-py3-none-manylinux_2_28_aarch64.whl (6.4 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ ARM64

snapper_fmt-0.7.8-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.7.8-py3-none-macosx_11_0_arm64.whl (6.2 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

snapper_fmt-0.7.8-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.7.8.tar.gz.

File metadata

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

File hashes

Hashes for snapper_fmt-0.7.8.tar.gz
Algorithm Hash digest
SHA256 28a300307fe70a93bfd6adef6985bbae88099fd7a9bea7138dba4fb86e2e91b6
MD5 a2827417ab77271b5ae20d48e57a49d5
BLAKE2b-256 8cc461bd33c83c86306bd23bcd6d774fa18a07f4ca10b0ade1b2a10ea884ebbc

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.7.8.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.7.8-py3-none-win_amd64.whl.

File metadata

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

File hashes

Hashes for snapper_fmt-0.7.8-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 2c82ac8bcf25a249ac88fea5c77f8bbef19a7dde815b091322b4b8b7d72780d6
MD5 eb3f114cd3c5ef747332c36456e61482
BLAKE2b-256 cb76c7176e877d9c0928b02bf16b5e5453391fd4428c8776d7ebcae5cb5df810

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.7.8-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.7.8-py3-none-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.7.8-py3-none-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 a643b31db8fd9da50cd71212aa761652dc2e29f68c3c8054b322dcefd4045294
MD5 def5255840e3be8c6b6c3f4b98875144
BLAKE2b-256 91dda9cfd59ff2bd6014118a23613df0166598ac298271ee25a972d95f156489

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.7.8-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.7.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.7.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7992b4596b38c4564556f08681795b39ce569c35c142c5b4b70baf4c88e3acdb
MD5 420fdb6e626b240eb2ab3d377792ebde
BLAKE2b-256 ddb7966ca9433fbd4461867e7eddccb7da2afd0d8414661efcc5ff43d0013775

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.7.8-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.7.8-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.7.8-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 567b30f0b69f34ca26a9618adbb5f9d03373ceb858541b204bc13feac77c83db
MD5 f3d84f209a39c1951dfc5be18020a312
BLAKE2b-256 0e0e7a84e0b5c0b280a8f21b1e3680855d095c94b5b34a6a06e2a822cc3ca4a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.7.8-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.7.8-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for snapper_fmt-0.7.8-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 65b178cae0ca9f459662c1ecedfc141201757951a6d91bdd8c28369a63f1f09e
MD5 1c5cb9ca233c81de53969a95148cfb52
BLAKE2b-256 7340ae88eb4f47fb8aea5de9e01cff23805effdb31127a689f1be7fb7d145263

See more details on using hashes here.

Provenance

The following attestation bundles were made for snapper_fmt-0.7.8-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