Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.

- - -
## v0.11.9 - 2026-10-04
#### Bug Fixes
- (**pandoc**) keep org file keywords and add no heading drawers - (18520c0) - *HaoZeke*
- (**site**) pin the homepage to v0.11.8 - (783e674) - *HaoZeke*

## v0.11.8 - 2026-10-03
#### Tests
- (**markdown**) accept the line-block terminator on the structure span - (6f3cd8c) - *HaoZeke*
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "snapper-fmt"
version = "0.11.8"
version = "0.11.9"
edition = "2024"
autotests = false
rust-version = "1.85"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ Configuration guide (org source in-tree): `docs/orgmode/howto/mcp-integration.or
## Pre-commit hook

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

Expand Down
2 changes: 1 addition & 1 deletion conda/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
schema_version: 1

context:
version: "0.11.8"
version: "0.11.9"

package:
name: snapper-fmt
Expand Down
6 changes: 3 additions & 3 deletions docs/orgmode/howto/ci-enforcement.org
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The easiest way to enforce semantic line breaks in CI.
Add to your workflow:

#+begin_src yaml
- uses: TurtleTech-ehf/snapper@v0.11.8
- uses: TurtleTech-ehf/snapper@v0.11.9
with:
files: '**/*.org **/*.tex **/*.md'
#+end_src
Expand All @@ -20,7 +20,7 @@ This installs snapper and runs =--check= on the specified files.
For GitHub Code Scanning integration (SARIF annotations on PRs):

#+begin_src yaml
- uses: TurtleTech-ehf/snapper@v0.11.8
- uses: TurtleTech-ehf/snapper@v0.11.9
with:
files: '**/*.org **/*.tex **/*.md'
sarif: 'true'
Expand All @@ -35,7 +35,7 @@ Add to =.pre-commit-config.yaml=:

#+begin_src yaml
- repo: https://github.com/TurtleTech-ehf/snapper
rev: v0.11.8
rev: v0.11.9
hooks:
- id: snapper
#+end_src
Expand Down
2 changes: 1 addition & 1 deletion docs/orgmode/howto/vale-integration.org
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ A typical workflow:

#+begin_src yaml
- repo: https://github.com/TurtleTech-ehf/snapper
rev: v0.11.8
rev: v0.11.9
hooks:
- id: snapper
- repo: https://github.com/errata-ai/vale
Expand Down
2 changes: 1 addition & 1 deletion docs/orgmode/tutorials/quickstart.org
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ Add to your =.pre-commit-config.yaml=:

#+begin_src yaml
- repo: https://github.com/TurtleTech-ehf/snapper
rev: v0.11.8
rev: v0.11.9
hooks:
- id: snapper
#+end_src
Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
project = "snapper"
copyright = '2026--present, <a href="https://rgoswami.me">Rohit Goswami</a>'
author = "Rohit Goswami"
release = "0.11.8"
release = "0.11.9"
html_logo = "../../branding/logo/snapper_logo.png"

extensions = [
Expand Down
2 changes: 1 addition & 1 deletion editors/obsidian/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "snapper",
"name": "Snapper - Semantic Line Breaks",
"version": "0.11.8",
"version": "0.11.9",
"minAppVersion": "1.0.0",
"description": "Format prose with semantic line breaks for clean git diffs. Supports Org-mode, LaTeX, Markdown, and plaintext.",
"author": "TurtleTech",
Expand Down
6 changes: 3 additions & 3 deletions editors/obsidian/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion editors/obsidian/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-snapper",
"version": "0.11.8",
"version": "0.11.9",
"private": true,
"description": "Obsidian plugin for snapper semantic line break formatter",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions editors/vscode/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# snapper - Semantic Line Breaks

Requires the **snapper** / **snapper-fmt** CLI **0.11.8+** on your PATH (or set `snapper.path`).
Requires the **snapper** / **snapper-fmt** CLI **0.11.9+** on your PATH (or set `snapper.path`).
The crate is `snapper-fmt`; installers ship both names.
If [openSUSE snapper](https://github.com/openSUSE/snapper) already owns `/usr/bin/snapper`, call `snapper-fmt` or set `snapper.path`.
Install: `cargo install snapper-fmt` or the [release installer](https://github.com/TurtleTech-ehf/snapper/releases/tag/v0.11.8).
Install: `cargo install snapper-fmt` or the [release installer](https://github.com/TurtleTech-ehf/snapper/releases/tag/v0.11.9).


Format prose so each sentence occupies its own line, producing clean git diffs for collaborative writing.
Expand Down
2 changes: 1 addition & 1 deletion editors/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "snapper",
"displayName": "snapper - Semantic Line Breaks",
"description": "Format prose with semantic line breaks for clean git diffs",
"version": "0.11.8",
"version": "0.11.9",
"publisher": "TurtleTech",
"license": "MIT",
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions editors/word/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Office add-in that formats document prose with **semantic line breaks** (one sentence per line) using the **snapper WASM** build (`@snapper/wasm`). Useful when drafting in Word and exporting to Org, Markdown, or LaTeX for git-friendly diffs.

**Version:** 0.11.8 (tracks snapper-fmt)
**Version:** 0.11.9 (tracks snapper-fmt)

Development preview; not published in AppSource.

Expand Down Expand Up @@ -34,7 +34,7 @@ CI builds the Word add-in in `.github/workflows/wasm.yml` (`build-word` job).

## Relationship to the CLI

Word uses the **plaintext** format path in WASM. For Org/LaTeX fidelity, prefer the CLI or VS Code extension (LSP). Delimiter-span and abbreviation behavior matches the current WASM API (requires snapper **0.11.8+**).
Word uses the **plaintext** format path in WASM. For Org/LaTeX fidelity, prefer the CLI or VS Code extension (LSP). Delimiter-span and abbreviation behavior matches the current WASM API (requires snapper **0.11.9+**).

## License

Expand Down
2 changes: 1 addition & 1 deletion editors/word/manifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
xsi:type="TaskPaneApp">
<Id>a8f3c2e1-9b4d-4e7a-8c5f-1d2e3f4a5b6c</Id>
<Version>0.11.8</Version>
<Version>0.11.9</Version>
<ProviderName>TurtleTech ehf</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="Snapper — Semantic Line Breaks"/>
Expand Down
6 changes: 3 additions & 3 deletions editors/word/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion editors/word/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "word-snapper",
"version": "0.11.8",
"version": "0.11.9",
"private": true,
"description": "Microsoft Word add-in for snapper semantic line break formatter",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion editors/word/src/taskpane/taskpane.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<body>
<div class="snapper-taskpane">
<h2>Snapper</h2>
<p class="tagline">Semantic line breaks for Word (v0.11.8)</p>
<p class="tagline">Semantic line breaks for Word (v0.11.9)</p>
<p class="hint">Formats paragraphs as plaintext. Use the CLI or VS Code for Org/LaTeX structure awareness.</p>
<div class="actions">
<button type="button" id="format-doc">Format Document</button>
Expand Down
2 changes: 1 addition & 1 deletion npm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@turtletech/snapper-mcp",
"version": "0.11.8",
"version": "0.11.9",
"private": true,
"description": "MCP server for snapper semantic line break formatter",
"main": "bin/run.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/snapper-wasm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/snapper-wasm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@snapper/wasm",
"version": "0.11.8",
"version": "0.11.9",
"description": "WebAssembly build of snapper semantic line break formatter",
"type": "module",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion readme_src.org
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ Configuration guide (org source in-tree): =docs/orgmode/howto/mcp-integration.or
:END:
#+begin_src yaml
- repo: https://github.com/TurtleTech-ehf/snapper
rev: v0.11.8
rev: v0.11.9
hooks:
- id: snapper
#+end_src
Expand Down
2 changes: 1 addition & 1 deletion site-svelte/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"operatingSystem": "Linux, macOS, Windows",
"url": "https://snapper.turtletech.us",
"downloadUrl": "https://crates.io/crates/snapper-fmt",
"softwareVersion": "0.11.8",
"softwareVersion": "0.11.9",
"license": "https://opensource.org/licenses/MIT",
"author": { "@type": "Organization", "name": "TurtleTech ehf", "url": "https://turtletech.us" },
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" }
Expand Down
2 changes: 1 addition & 1 deletion site-svelte/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
lines: [
{ text: '# .pre-commit-config.yaml', type: 'comment' as const },
{ text: '- repo: https://github.com/TurtleTech-ehf/snapper', type: 'flag' as const },
{ text: ' rev: v0.11.8', type: 'flag' as const },
{ text: ' rev: v0.11.9', type: 'flag' as const },
{ text: ' hooks:', type: 'flag' as const },
{ text: ' - id: snapper', type: 'flag' as const },
],
Expand Down
4 changes: 2 additions & 2 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"operatingSystem": "Linux, macOS, Windows",
"url": "https://snapper.turtletech.us",
"downloadUrl": "https://crates.io/crates/snapper-fmt",
"softwareVersion": "0.11.8",
"softwareVersion": "0.11.9",
"license": "https://opensource.org/licenses/MIT",
"author": {
"@type": "Organization",
Expand Down Expand Up @@ -934,7 +934,7 @@ <h2 class="section-title" data-i18n="install_title">Install in seconds</h2>
<div class="install-card-header">Pre-commit</div>
<pre><span class="comment"># .pre-commit-config.yaml</span>
- <span class="flag">repo</span>: https://github.com/TurtleTech-ehf/snapper
<span class="flag">rev</span>: v0.11.8
<span class="flag">rev</span>: v0.11.9
<span class="flag">hooks</span>:
- <span class="flag">id</span>: snapper</pre>
</div>
Expand Down
65 changes: 65 additions & 0 deletions src/parser/pandoc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ pub fn format_via_pandoc(
let json = json_with_backend(&shield.source, format, backend)?;
let mut doc: pandoc_ast::Pandoc =
serde_json::from_str(&json).map_err(|e| PandocError::Ast(e.to_string()))?;
if shield::is_org_pandoc_format(format) {
drop_generated_org_ids(&mut doc.blocks, &authored_org_ids(input));
}
reflow_pandoc(&mut doc, splitter, reflow_config);
let out_json =
serde_json::to_string(&doc).map_err(|e| PandocError::Ast(format!("serialize AST: {e}")))?;
Expand All @@ -259,6 +262,44 @@ pub fn format_via_pandoc(
Ok(written)
}

/// `CUSTOM_ID` values the org source sets on its headings.
fn authored_org_ids(input: &str) -> std::collections::HashSet<String> {
input
.lines()
.filter_map(|l| l.trim().strip_prefix(":CUSTOM_ID:"))
.map(|id| id.trim().to_string())
.filter(|id| !id.is_empty())
.collect()
}

/// The org reader gives every heading an identifier, and the org writer
/// prints each one as a `:PROPERTIES:` drawer. Keep only the identifiers the
/// source set itself, so a reflow never adds drawers the author did not write.
fn drop_generated_org_ids(
blocks: &mut [pandoc_ast::Block],
authored: &std::collections::HashSet<String>,
) {
use pandoc_ast::Block;
for block in blocks {
match block {
Block::Header(_, attr, _) => {
if !authored.contains(&attr.0) {
attr.0.clear();
}
}
Block::BlockQuote(inner) | Block::Div(_, inner) | Block::Figure(_, _, inner) => {
drop_generated_org_ids(inner, authored);
}
Block::BulletList(items) | Block::OrderedList(_, items) => {
for item in items {
drop_generated_org_ids(item, authored);
}
}
_ => {}
}
}
}

/// Parser that uses pandoc for universal format support.
pub struct PandocParser {
/// Pandoc input format (e.g. "latex", "markdown", "org", "rst", "typst")
Expand Down Expand Up @@ -580,6 +621,30 @@ mod tests {
);
}

#[test]
fn format_via_pandoc_org_keeps_keywords_and_adds_no_drawers() {
if !pandoc_default_available() {
return;
}
let src = "#+TITLE: t\n#+DATE: 2026\n#+DESCRIPTION: d\n#+FILETAGS: :x:\n\n* A\n:PROPERTIES:\n:CUSTOM_ID: keep-me\n:END:\n\nOne. Two.\n\n* B\n\nThree. Four.\n";
let splitter = crate::sentence::unicode::UnicodeSentenceSplitter::new();
let out = format_via_pandoc(
src,
"org",
PandocBackend::Auto,
&splitter,
&crate::reflow::ReflowConfig::default(),
)
.unwrap();
assert!(
out.starts_with("#+TITLE: t\n#+DATE: 2026\n#+DESCRIPTION: d\n#+FILETAGS: :x:\n"),
"{out}"
);
assert!(out.contains(":CUSTOM_ID: keep-me"), "{out}");
assert_eq!(out.matches(":CUSTOM_ID:").count(), 1, "{out}");
assert!(out.contains("Three.\nFour."), "{out}");
}

#[test]
fn refuse_if_comments_missing_catches_restore_miss() {
let err = refuse_if_comments_missing(
Expand Down
Loading
Loading