Obsługiwane formaty

snapper classifies text into prose regions (reflowed at sentence boundaries), structure regions (passed through unchanged), and code regions (fenced or delimited source blocks). Code regions keep fence/open/close lines as structure; the body reflows comment lines when [code.<lang>] is configured, and may run an external formatter when --format-code is set. The classification depends on the format.

Org-mode (--format org)

Regiony strukturalne (zachowane)

  • Non-source #+BEGIN_*

#+END_* fences, and the bodies of literal blocks (example, export, comment, verse). An unmatched #+BEGIN_EXPORT is a paragraph (org-element export-block-parser)

  • Dynamic blocks (#+BEGIN: NAME#+END:), including the generated body

  • Quote, center, and special-block (NOTE and other unknown NAME) open/close lines

  • Verse-block body (org-element verse-lines; leftover opaque walker, GitHub #395)

  • Special-block interiors (NOTE, ABSTRACT, WARNING, …) reflow as prose

  • :PROPERTIES:

szuflady :END:

  • #+KEYWORD: directives (TITLE, AUTHOR, DATE, OPTIONS, NAME, ATTR*, etc.); #+CAPTION: / #+CAPTION[short]: opener only

  • Standalone bracket-link lines ([[file:plot.png]])

  • Wiersze tabeli (linie zaczynające się od |)

  • Linie komentarzy (zaczynające się od #, ale nie #+)

  • Column-0 diary-sexp lines (%%(...); org-element-diary-sexp-parser)

  • Full headline lines (stars, optional TODO keyword, and title text)

  • List item markers (-, +, 1.); continuation sentences hang at the marker width

  • LaTeX environments (\begin{equation}\end{equation}, \begin{align}, etc.). An unmatched \begin{env} is a paragraph (org-element latex-environment-parser)

  • Display math (\[\])

  • Line breaks (org-element-line-break-parser: \\ plus optional spaces or tabs at end of line)

  • A line that is only an export snippet (@@latex:\newpage@@). Trailing prose after the closer stays Prose.

Code regions (#+BEGIN_SRC#+END_SRC)

  • An unmatched #+BEGIN_SRC is a paragraph (org-element src-block-parser)

  • Header and footer lines are structure

  • Body non-comment lines pass through verbatim

  • Body comment lines reflow at sentence boundaries when the language has line_comment and/or block_comment under [code.<lang>]

  • With --format-code, optional formatter argv runs on the body (graceful fallback on failure)

Regiony prozy (przeformatowywane)

  • Tekst akapitowy

  • List item text (after the marker); continuation sentences hang at the marker width so Org rejoins the item

  • Quote, center, and special-block inner text

  • #+CAPTION: value (org-element-parsed-keywords); continuation sentences hang at the opener width. Dual #+CAPTION[short]: keeps the short title on the opener

Tokeny inline (zachowane jako niepodzielne)

Te tokeny wewnątrz prozy nie są dzielone między liniami:

  • Linki: [[url][opis]]

  • Angular links: <file:fig. 1.png> (org-link-angle-re; spaces allowed)

  • Emphasis: \*bold*, /italic/, _underline_, +strike+

  • Kod inline: ~code~, ==verbatim==

  • A ~code~ or ==verbatim== span may contain the marker character; pairing matches pandoc’s org reader, so x = 1 stays one span

  • Markdown inline code: a run of n backticks closes on the next run of the same length (CommonMark / pandoc), so a double span can hold a single backtick

  • Inline export snippets: @@backend:value@@ (org-element-export-snippet-parser; backend [-A-Za-z0-9]+ so html5 and hyphen names stay one token)

  • Radio targets: <<<contents>>> (org-element-radio-target-parser)

  • Angle targets: <<contents>> (org-element-target-parser)

  • Macros: {{{name}}} / {{{name(args)}}} (org-element-macro-parser)

  • Inline source: src_lang{...} / src_lang[headers]{...} (org-element-inline-src-block-parser; \<src_ is word-start. After a word, _src_ is a subscript, so foo_src_python{...} is not an object; _src_python{...} after space is)

  • Inline babel call: call_name(...) / call_name[inside](...)[end] (org-element-inline-babel-call-parser; same \<call_ / subscript rule)

  • Inline footnotes: [fn:: def] / [fn:name: def] (org-element-footnote-reference-parser)

  • LaTeX fragments: \(...\), $...$, \cmd{arg}, \cmd[opt]{arg} (org-element-latex-fragment-parser; interior backslash and optional [arg] stay one token). Same-line \[...\] is Structure

  • Brace sub/superscripts: H_{2. 0} / x^{n. 1} (org-match-substring-regexp brace arm; interior punct stays one wrap token). Bare H_2 / x^n and no-space H_{2.0} are unchanged. Distinct from latex-fragment.

  • URLs: https://... (trailing sentence punctuation not swallowed)

LaTeX (--format latex)

Regiony strukturalne (zachowane)

  • Preambuła (wszystko przed \begin{document})

  • Non-prose environments: equation, align, tabular, tikzpicture, and their starred variants (plus other non-code envs)

  • Float chrome (\begin{figure} / \centering / \end{figure}, and table / starred variants): Structure. The \caption long argument is Prose.

  • Extra names from [latex].structure_envs in .snapperrc.toml (for example algorithm)

  • Wzory wyświetlane: \[...\]

  • \iffalse through \fi (tree-sitter block_comment)

  • Linie komentarzy (zaczynające się od %)

  • \end{document}

  • Full sectioning command lines (\section{...}, \subsection{...}, and friends, including title text)

Code regions (minted, lstlisting, verbatim, comment, Piton)

  • \\begin{...} / \\end{...} lines are structure

  • fancyvrb Verbatim / Verbatim* / BVerbatim / BVerbatim* / LVerbatim / LVerbatim* / SaveVerbatim / VerbatimOut / fvextra VerbatimWrite / VerbatimBuffer are built-in code regions (same FV@Scan class)

  • verbments.sty pyglist wraps fancyvrb VerbatimOut (raw listing body)

  • texments.sty / pygmentex.sty pygmented is VerbatimEnvironment plus VerbatimOut (raw listing body)

  • fvextra VerbEnv is the environment form of \Verb (raw body through matching \end{VerbEnv})

  • moreverb verbatimtab is a built-in code region (tab-expanding verbatim; same raw class as boxedverbatim)

  • moreverb verbatimwrite writes the env body raw via verbatim@start (same class as VerbatimOut / tcbverbatimwrite)

  • leftover sverb.sty verbwrite / ignore / demo / demo* are the same sv@readenv raw grab

  • moreverb listing / listingcont / listing* / listingcont* are built-in code regions (verbatim@start raw body; starred twins do not expand tabs)

  • alltt (standard alltt.sty) is a built-in code region (raw line breaks)

  • listings.sty lstlisting* is the same raw body scan as lstlisting

  • pythonhighlight.sty python (`lstnewenvironment{python}`) is the same listings raw scan as lstlisting

  • pyluatex.sty pythonq / pythonrepl are verbatim python / REPL bodies (landed python stays Code)

  • showexpl.sty LTXexample (`lstnewenvironment{LTXexample}`) is the same listings raw scan as lstlisting

  • luamplib.dtx mplibcode is the same raw grab class as luacode

  • luacode.sty leftover luaexec is the same raw grab class as luacode

  • codehigh.sty codehigh / demohigh / codehigh* / demohigh* (`NewCodeHighEnv`) are leftover listing envs

  • minted.sty minted* is the starred twin of minted (same raw minted body)

  • tcolorbox listings tcblisting* is the starred twin of tcblisting (same raw listing body)

  • tcolorbox tcbverbatimwrite / tcbwritetemp write the env body raw to a file (same class as VerbatimOut)

  • tcolorbox leftover write/listing envs tcboutputlisting / tcbexternal / dispExample / dispExample* / dispListing / dispListing* are the same raw grab (tcblistingscore / tcbexternal / tcbdocumentation)

  • latexindent filecontents / filecontents* write the env body raw to a file

  • filecontentsdef.sty filecontentsdef writes the env body verbatim into a macro (same raw grab as filecontents)

  • filecontentsdef.sty leftover siblings filecontentsgdef / filecontentsdefmacro / filecontentsgdefmacro / filecontentshere and starred twins filecontentsdef* / filecontentsgdef* / filecontentshere* are the same raw grab

  • scontents.sty scontents stores the env body verbatim into a sequence; verbatimsc is the package verbatim display env

  • spverbatim.sty spverbatim is a built-in code region (raw line breaks)

  • pythontex.sty pyblock / pyverbatim / pyconsole / pycode* / pyblock* / pyverbatim* / pyconsole* / pygments / sympycode / sympyblock / sympyverbatim / sympyconsole / pylabcode / pylabblock / pylabverbatim / pylabconsole and starred twins, plus leftover default-family pyconcode / pyconverbatim / pysub / pyconsub / sympyconcode / sympyconverbatim / sympysub / sympyconsub / pylabconcode / pylabconverbatim / pylabsub / pylabconsub / pythontexcustomcode, plus option-family usefamily leftovers (rubycode representative; ruby / rb / julia / juliacon / jl / matlab / octave / bash / sage / rust / rs / R / Rcon / perl / pl / perlsix / psix / javascript / js), are the same VerbatimEnvironment class as pycode

  • sagetex.sty sageverbatim / sageexample / sagecommandline are the same verbatim@start class as tree-sitter-latex sagesilent / sageblock

  • piton.sty Piton is a built-in code region (verbatim listing env)

  • Extra names from [latex].verbatim_envs are code regions too

  • Body follows the same comment-reflow and optional --format-code rules as other formats when language is known (minted / minted* language arg, lstlisting / lstlisting* language= option)

  • Inline leftover \verb / \verb* / leftover \lstinline / leftover \spverb / leftover \mintinline / leftover \mint / leftover fancyvrb \Verb / \Verb* / leftover \SaveVerb / leftover \UseVerb / leftover \UseVerbatim / leftover \LUseVerbatim / leftover \BUseVerbatim / leftover \DefineShortVerb / \UndefineShortVerb / leftover fvextra \EscVerb / leftover fvextra \VerbatimInsertBuffer / \VerbatimClearBuffer / \InsertBuffer / \IterateBuffer / \VerbatimInput / \BVerbatimInput / \LVerbatimInput / piton.sty leftover \piton / \PitonInputFile / \PitonInputFileT / \PitonInputFileF / \PitonInputFileTF / listings.sty \lstinputlisting / minted.sty \inputminted / tools/verbatim.sty \verbatiminput / tcolorbox \tcbinputlisting / pythontex.sty \inputpy / \inputpycon / leftover inline \py / \pyc / \pys / \pyb / \pyv / \pycon and twins / \sympy / \pylab and twins / leftover usefamily \ruby / \rb / \julia / \jl / \matlab / \octave / \bash / \sage / \rust / \rs / \R / \perl / \pl / \perlsix / \psix / \javascript / \js and twins / \inputpygments / \pygment / leftover \pythontexcustomc / pythonhighlight.sty \inputpython / \inputpythonfile / leftover \pyth / catchfilebetweentags.sty \CatchFileBetweenTags / \CatchFileBetweenDelims / \ExecuteMetaData / catchfile.sty leftover \CatchFileDef / \CatchFileEdef / moreverb \listinginput / leftover \verbatimtabinput / \verbatimtabinput* / leftover \verbatimwrite / \verbatimwrite* / leftover \listingcont / sagetex \sageinput / leftover inline \sageplot / \sagestr / scontents leftover \Scontents / \Scontents* / \typestored / \getstored / \mergesc / \meaningsc / \foreachsc (and extra [latex].verbatim_commands) stay atomic; inner .!?% do not split or comment. leftover \verb / \verb* / \lstinline / \spverb take a delimiter or, for \lstinline, optional [...] then a delimiter or {...}; a flush following sentence stays on its own line leftover \mintinline / \mint take optional [...], {lang}, then a delimiter or {...} body; a flush following sentence stays on its own line leftover \SaveVerb takes optional [...], a {name}, then the same delimiter body as \Verb; a flush following sentence stays on its own line leftover \UseVerb / \UseVerb* take optional [...] then a {name}; leftover \UseVerbatim / \LUseVerbatim / \BUseVerbatim take optional [...] then a {name}; a flush following sentence stays on its own line leftover \DefineShortVerb takes optional [...] then a {char}; leftover \UndefineShortVerb takes a {char}; a flush following sentence stays on its own line leftover \Verb takes a delimiter like \verb; leftover \EscVerb takes a delimiter or {code}; a flush following sentence stays on its own line leftover \VerbatimInsertBuffer / \InsertBuffer take optional [...]; leftover \VerbatimClearBuffer takes no args; leftover \IterateBuffer takes optional [...] then a {cmd}; a flush following sentence stays on its own line leftover \piton|...| is verb-like; leftover \piton{...} stays one token via the generic command argument; a flush following sentence stays on its own line \lstinputlisting / \lstinputlisting* take optional [...] then a {filename}; a flush following sentence stays on its own line \inputminted / \inputminted* take optional [...], {lang}, then a {filename}; a flush following sentence stays on its own line \VerbatimInput / \BVerbatimInput / \LVerbatimInput take optional [...] then a {filename}; a flush following sentence stays on its own line \verbatiminput / \verbatiminput* take a {filename}; a flush following sentence stays on its own line \PitonInputFile takes optional <...>, optional [...], then a {filename}; a flush following sentence stays on its own line \PitonInputFileT / \PitonInputFileF take the same optional args then {file} and one extra required brace; \PitonInputFileTF takes two extra braces; a flush following sentence stays on its own line \tcbinputlisting takes one required {keyval} group; a flush following sentence stays on its own line \inputpy / \inputpycon take optional [...] then a {filename}; a flush following sentence stays on its own line \py / \pyc / \pys / \pyb / \pyv / \pycon and twins / \sympy / \pylab and twins take optional [...] then a delimiter or {body}; a flush following sentence stays on its own line \inputpygments takes optional [...], {lang}, then a {filename}; \pygment takes {lang} then a delimiter or {code} body; a flush following sentence stays on its own line \inputpython takes {file} {first} {last}; \inputpythonfile takes {file} then optional [first] [last]; a flush following sentence stays on its own line \pyth takes a delimiter or {code} body; a flush following sentence stays on its own line \CatchFileBetweenTags takes {macro} {file} {tag}; \CatchFileBetweenDelims takes {macro} {file} {start} {end}; \ExecuteMetaData takes optional [file] then {tag}; a flush following sentence stays on its own line leftover \CatchFileDef / \CatchFileEdef take {macro} {file} {setup}; a flush following sentence stays on its own line \listinginput takes optional [interval] then {start} and {filename}; a flush following sentence stays on its own line \verbatimtabinput / \verbatimtabinput* take optional [tabwidth] then a {filename}; a flush following sentence stays on its own line leftover \verbatimwrite / \verbatimwrite* take a {filename}; a flush following sentence stays on its own line leftover \listingcont takes no args; a flush following sentence stays on its own line \sageinput takes optional [...] then a {filename}; a flush following sentence stays on its own line \sageplot takes optional [ltx opts] [fmt] then a {graphics}; \sagestr takes a {code}; a flush following sentence stays on its own line \inputsc takes optional [...] then a {name}; a flush following sentence stays on its own line \pythontexcustomc takes optional [begin|end], a required {type}, then a delimiter or {code} body; a flush following sentence stays on its own line \Scontents / \Scontents* take optional [...] then a standard or verbatim arg; \typestored / \getstored / \mergesc / \meaningsc / \foreachsc take optional [...] then a {seq}; a flush following sentence stays on its own line

Regiony prozy (przeformatowywane)

  • Tekst główny pomiędzy elementami strukturalnymi

  • \caption{...} long argument inside figure/table (tree-sitter caption curlygroup)

Markdown (--format markdown)

Regiony strukturalne (zachowane)

  • Front matter (--- lub +++ na początku pliku)

  • Full ATX heading lines (####### including title text)

  • Puste nagłówki ATX (linia znacznika bez tekstu tytułu) pozostają Structure

  • Setext headings (title line plus ==== or —— underline)

  • List item markers (-, \*, +, 1.); continuation sentences hang at the marker width

  • Puste znaczniki listy (także w cytacie) pozostają Structure

  • Definition-list terms and : = markers (pulldown =ENABLE_DEFINITION_LIST); the body hangs at the marker width

  • Blockquote markers (> / nested => > =); continuation sentences repeat the quote prefix

  • GFM alert type markers ([!NOTE] / [!TIP] / [!WARNING] / [!CAUTION] / [!IMPORTANT]); the body hangs and splits like a quote

  • Definicje odwołań do łączy ([label]: dest); cel może być w następnej linii. Definicja wewnątrz akapitu pozostaje Prose

  • Definicje przypisów GFM ([^label]:); znacznik jest Structure, a treść wisi

  • Hard line breaks (two trailing spaces, or a trailing backslash)

  • HTML comments (<!-- ... -->, including multiline); <!-- snapper:off --> / <!-- snapper:on --> remain pragmas

  • Zamknięte bloki HTML typu 6 i 7 kończą się na pasującym tagu zamykającym; następująca proza pozostaje Prose

  • Void type-6 tags (<hr> / <col> / <link> / <base>) end on the tag line; they have no closer, so leftover following prose stays Prose even without a blank

  • Pipe tables

Code regions (fenced ``` / ~~~)

  • Opening and closing fence lines are structure

  • Indented fence bodies preserve indentation on reflowed comment lines

  • Language from the fence info string selects [code.<lang>]; unknown or missing lang passes the body through unchanged (unless --format-code is not applicable without a formatter entry)

Regiony prozy (przeformatowywane)

  • Tekst akapitowy

  • List item text (after the marker); continuation sentences hang at the marker width

  • Definition-list body (after the =: = marker); continuation sentences hang at the marker width

  • Treść definicji przypisu GFM (po [^label]:); kolejne zdania wiszą na szerokości znacznika

  • Blockquote inner text (after the > marker); continuation sentences repeat the quote prefix

Tokeny inline (zachowane jako niepodzielne)

  • Emphasis: \*em*, \*\*strong** (CommonMark flanking; a period inside the span does not split)

  • Strikethrough: ~~strike~~ (GFM)

  • Inline code: a run of n backticks closes on the next run of the same length

  • Links and images: [text](url), ![alt](url)

  • Inline math: $...$ / $$...$$

reStructuredText (--format rst)

Regiony strukturalne (zachowane)

  • Non-code opaque directives (.. math::, .. image::, .. raw::, .. include::, .. csv-table::) and their indented bodies

  • Container directive openers (.. note::, .. warning::, .. figure::, .. topic::, .. sidebar::, .. container::, leftover .. parsed-literal::, .. epigraph::, .. highlights::, .. pull-quote::, .. compound::, .. header::, .. footer::) and their :option: fields; the indented body is prose

  • Treść w tej samej linii po :: na tych kontenerach, leftover .. parsed-literal::, .. header::, .. footer::, .. |name| replace:: oraz pola .. meta:: wisi i dzieli się. Wyrównane pola bibliograficzne zamykają leftover meta

  • Literal blocks (text after :: with indented or line-prefix-quoted content)

  • Section titles and underlines (===, -----, etc.). A wrap cut that would park a solid Docutils Body.line adornment at column 0 skip-cuts the token onto the previous line (snapper-7xd3)

  • Field lists (:Author:, :Date:, etc.)

  • Puste elementy listy, puste otwarcia doctest i puste znaczniki field-list na EOL pozostają Structure

  • Comments (.. without a directive)

  • Grid and simple tables (lines starting with | or +)

Code regions (.. code-block:: LANG)

  • Directive line and trailing blank handling stay structure

  • Indented body uses the language token for [code.<lang>] comment reflow and optional --format-code

Regiony prozy (przeformatowywane)

  • Paragraph text between structural elements

  • Indented bodies of container directives (admonitions, figure captions, topic, sidebar, container, leftover parsed-literal, epigraph, highlights, pull-quote, compound); hang spaces stay structure

Tokeny inline (zachowane jako niepodzielne)

  • Substitution references: |fig. 1| / |version| / |name|_ / |name|__ (Docutils Inliner.substitutionref). Interior punctuation is not a sentence or wrap boundary. The use stays Prose, not Structure (line-block is | plus space or EOL)

Auto-detection

Extensions: .rst, .rest

Zwykły tekst (--format plaintext)

Całość traktowana jako proza. Puste linie są zachowane jako separatory akapitów.

Wykrywanie zdań

snapper uses Unicode UAX #29 sentence boundary detection as a baseline (or optional --neural / nnsplit), then applies the same post-pipeline: abbreviation merges, then delimiter-span rejoin so dialogue and balanced ()[]{} spans are not fractured.

Delimiter-span policy (residual cases)

  • Balanced ASCII/curly/guillemet quotes, LaTeX double-backtick quotes, and ()[]{} must not gain a semantic line break mid-span (see tests/sentence_delim_props.rs).

  • Unclosed " (or open without ) glues the rest of the paragraph; snapper does not invent closers.

  • Nested semantic ASCII quotes (say "hi" now with an inner pair) remain toggle-ambiguous; prefer typographic quotes or escapes in source.

  • Apostrophes in contractions (don't, it's) are not treated as dialogue openers.

  • Markdown fences (three backticks) are not treated as LaTeX double-backtick openers.

  • --neural runs the same abbreviation + span post-pipeline after the model proposes cuts (English papers can still prefer the rules path for fully offline, deterministic CI).

snapper merges false splits caused by known abbreviations:

Tytuły

Mr., Mrs., Ms., Dr., Prof., Sr., Jr., St., Rev., Gen. itp.

Naukowe

Fig., Figs., Eq., Eqs., Ref., Refs., Tab., Sec., Ch., Vol., No., Thm., Lem., Prop., Def., Cor., Rem., Ex.

Łacińskie

e.g., i.e., et al., cf., etc., viz., ibid., ca., approx.

Pojedyncze inicjały

A., B., C., … Z.

Data i czas

Jan., Feb., …, Dec., Mon., Tue., …, Sun., a.m., p.m.

Quoted and parenthesized punctuation

Sentence punctuation inside quotes or parentheses does not trigger a false split when the next word starts lowercase. For example, He said "wow!" and left. stays on one line because "!" followed by lowercase and signals a continuation, not a new sentence. Patterns handled: !", ?", .", !), ?), .), and similar combinations with single quotes or brackets.