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

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

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. See MCP Integration for configuration.

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.7.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))

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.6.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.6-py3-none-win_amd64.whl (7.3 MB view details)

Uploaded Python 3Windows x86-64

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

Uploaded Python 3manylinux: glibc 2.28+ ARM64

snapper_fmt-0.7.6-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.6-py3-none-macosx_11_0_arm64.whl (6.1 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

snapper_fmt-0.7.6-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.6.tar.gz.

File metadata

  • Download URL: snapper_fmt-0.7.6.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.6.tar.gz
Algorithm Hash digest
SHA256 33b0f6b7421406b61f7e9f2b56f3f95c95dc3fe294f977289c368ad250ee5cb4
MD5 15b95e3bad017f619435f768c5ec1eb0
BLAKE2b-256 281b052ff66f244462519aed816f9c59730c6ee313432ff76cff19f4d1a041ef

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: snapper_fmt-0.7.6-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.6-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 89cbd086d217342a0d6a0ce9d2fcc5b1f0b12ebf91ff6e8dabd7d68fc8d43760
MD5 8d35ca33ba065c638ef7c0cfe0859f8e
BLAKE2b-256 9196d1ca1e41664411f5557855b09db0f4274bb23d3a21703107a50ec9f3bf94

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for snapper_fmt-0.7.6-py3-none-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 9ae2f4f44f997fc8eb1c16891804b57d886afffef0c81418e08bf4d18b7db514
MD5 5ef1a0bfb03fd264e972067f8c87158e
BLAKE2b-256 d4f44b2caba219e8d7f1a5713665387bc4b94e2b1dde8f6a42f8b0844e419733

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for snapper_fmt-0.7.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 60753641969bf62aa70747b22f5fb336a1edfcb8aa3f4bf6bb576741a2dbd166
MD5 ecc3d5f7669e76d4740eeb69a64f57ba
BLAKE2b-256 f0b07cf4cde7a5d1ef66968c208eaefa78f2681bef525b08e9e742a4c4ccd12e

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for snapper_fmt-0.7.6-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 383a72796c366d56a0adb3c9f4d495ef584b4a964bb37d53ae5706b926b17af5
MD5 0c566483542d90ab0fff787d61c5e765
BLAKE2b-256 2ca358dbf9ceb4db907c4a85672cab08765de857ed705187091a1c3818d45a47

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for snapper_fmt-0.7.6-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 30c87c8be390849b57f0507cecd67690469e6e1db850c6cb70778afa677d6ec4
MD5 70f5bc009e5d8d6ce315cefc22dbed35
BLAKE2b-256 db7f61f58aabb59ff513cddd7ac38ccf13eded873ad9bcee13cdd8af91dc0066

See more details on using hashes here.

Provenance

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