From 5d1d06d666daaf25d8bb6572545a9d7c06f04476 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 20:25:39 +0100 Subject: [PATCH 1/6] Enforce semantic line breaks with Snapper --- .github/workflows/semantic-line-breaks.yml | 29 ++++++++++++++++++++++ docs/source/unreleased.rst | 4 +-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/semantic-line-breaks.yml diff --git a/.github/workflows/semantic-line-breaks.yml b/.github/workflows/semantic-line-breaks.yml new file mode 100644 index 000000000..16647cd2d --- /dev/null +++ b/.github/workflows/semantic-line-breaks.yml @@ -0,0 +1,29 @@ +name: Semantic line breaks + +on: + pull_request: + push: + branches: + - main + +permissions: {} + +jobs: + semantic-line-breaks: + name: Snapper + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 + - name: Check semantic line breaks + run: >- + git ls-files -z -- '*.md' '*.rst' ':(exclude)vendored/**' + | xargs -0 --no-run-if-empty + uvx + --from + 'git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1' + snapper --max-width 0 --check + diff --git a/docs/source/unreleased.rst b/docs/source/unreleased.rst index 22ac74723..d297d1976 100644 --- a/docs/source/unreleased.rst +++ b/docs/source/unreleased.rst @@ -1,8 +1,8 @@ Unreleased changes ================== -Changes that have landed on the main branch but are not yet part of a -tagged release. These entries are assembled into the +Changes that have landed on the main branch but are not yet part of a tagged release. +These entries are assembled into the :doc:`changelog` when the next release is published. .. towncrier-draft-entries:: From ab0aa2ceeaff777cb45e5a81cd6ebc1a7e99d1a7 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 20:53:55 +0100 Subject: [PATCH 2/6] Run Snapper through Prek --- .github/workflows/semantic-line-breaks.yml | 29 ---------------------- prek.toml | 13 ++++++++++ pyproject.toml | 1 + 3 files changed, 14 insertions(+), 29 deletions(-) delete mode 100644 .github/workflows/semantic-line-breaks.yml diff --git a/.github/workflows/semantic-line-breaks.yml b/.github/workflows/semantic-line-breaks.yml deleted file mode 100644 index 16647cd2d..000000000 --- a/.github/workflows/semantic-line-breaks.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Semantic line breaks - -on: - pull_request: - push: - branches: - - main - -permissions: {} - -jobs: - semantic-line-breaks: - name: Snapper - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 - - name: Check semantic line breaks - run: >- - git ls-files -z -- '*.md' '*.rst' ':(exclude)vendored/**' - | xargs -0 --no-run-if-empty - uvx - --from - 'git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1' - snapper --max-width 0 --check - diff --git a/prek.toml b/prek.toml index c013e7e46..9869ba179 100644 --- a/prek.toml +++ b/prek.toml @@ -364,6 +364,19 @@ hooks = [ additional_dependencies = ["uv==0.11.7"], stages = ["pre-commit"] }, + { + id = "snapper", + name = "snapper", + entry = "uv run --group=dev snapper --max-width 0 --in-place", + language = "python", + types_or = [ + "rst", + "markdown" + ], + require_serial = true, + additional_dependencies = ["uv==0.11.7"], + stages = ["pre-commit"] + }, { id = "vale", name = "vale", diff --git a/pyproject.toml b/pyproject.toml index d764b3dcd..db2eb3378 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,6 +75,7 @@ dev = [ # use it to lint shell commands in GitHub workflow files. "shellcheck-py==0.11.0.1", "shfmt-py==4.1.0", + "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", "sphinx-lint==1.0.2", From aeb67c94b11ba9ae65edc661e176425882b1ac77 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:15:47 +0100 Subject: [PATCH 3/6] Isolate the Snapper dependency group --- prek.toml | 2 +- pyproject.toml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/prek.toml b/prek.toml index 9869ba179..9b3f03f22 100644 --- a/prek.toml +++ b/prek.toml @@ -367,7 +367,7 @@ hooks = [ { id = "snapper", name = "snapper", - entry = "uv run --group=dev snapper --max-width 0 --in-place", + entry = "uv run --group=snapper snapper --max-width 0 --in-place", language = "python", types_or = [ "rst", diff --git a/pyproject.toml b/pyproject.toml index db2eb3378..acaacc07a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,6 @@ dev = [ # use it to lint shell commands in GitHub workflow files. "shellcheck-py==0.11.0.1", "shfmt-py==4.1.0", - "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", "sphinx-lint==1.0.2", @@ -98,6 +97,9 @@ dev = [ "zizmor==1.30.0", ] release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ] +snapper = [ + "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", +] [tool.setuptools] packages.find.where = [ From aa02fe7428246f2f7bbf19368455f8b7765ef0e9 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:33:43 +0100 Subject: [PATCH 4/6] Enable Snapper Vale rules --- .vale.ini | 3 ++- styles/snapper/LongProseLine.yml | 11 +++++++++++ styles/snapper/SemanticLineBreaks.yml | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 styles/snapper/LongProseLine.yml create mode 100644 styles/snapper/SemanticLineBreaks.yml diff --git a/.vale.ini b/.vale.ini index 250e9b2dd..547f93b8a 100644 --- a/.vale.ini +++ b/.vale.ini @@ -4,7 +4,8 @@ MinAlertLevel = error Packages = https://github.com/tbhb/vale-ai-tells/releases/download/v1.29.0/ai-tells.zip [*.{rst,md}] -BasedOnStyles = ai-tells +BasedOnStyles = ai-tells, snapper +snapper.SemanticLineBreaks = error # These rules misclassify established technical, example, or release-note prose # in this repository. All other ai-tells rules remain enforced. diff --git a/styles/snapper/LongProseLine.yml b/styles/snapper/LongProseLine.yml new file mode 100644 index 000000000..1f5029f7d --- /dev/null +++ b/styles/snapper/LongProseLine.yml @@ -0,0 +1,11 @@ +--- +# Vale style rule: flag prose lines that are suspiciously long. +# Likely indicates wrapped text that should use semantic line breaks. +extends: existence +message: Prose line exceeds 120 characters. Consider running 'snapper' to break at + sentence boundaries. +level: suggestion +scope: paragraph +# This catches lines > 120 chars that contain a period followed by a space. +# Pure code or URLs are less likely to match. +tokens: ['.{120,}'] diff --git a/styles/snapper/SemanticLineBreaks.yml b/styles/snapper/SemanticLineBreaks.yml new file mode 100644 index 000000000..3f4edaf55 --- /dev/null +++ b/styles/snapper/SemanticLineBreaks.yml @@ -0,0 +1,11 @@ +--- +# Vale style rule: flag lines containing multiple sentences. +# These should be broken at sentence boundaries. +extends: existence +message: Line contains multiple sentences. Run 'snapper --check' or reformat with + 'snapper --in-place'. +level: warning +scope: paragraph +# Match a sentence-ending punctuation followed by a space and a capital letter +# on the same line (indicating two sentences on one line). +tokens: ['[.!?]\\s+[A-Z]'] From 8ed531b5303c9945355fa78455405e63446d6882 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:57:20 +0100 Subject: [PATCH 5/6] Use the Snapper 0.11.0 release --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index acaacc07a..5953bde45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ dev = [ ] release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ] snapper = [ - "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", + "snapper-fmt==0.11.0", ] [tool.setuptools] From 5a99a71b3330636fd820e68c8700ad2c4eacc957 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 22:05:01 +0100 Subject: [PATCH 6/6] Use the development dependency group for Snapper --- prek.toml | 2 +- pyproject.toml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/prek.toml b/prek.toml index 9b3f03f22..9869ba179 100644 --- a/prek.toml +++ b/prek.toml @@ -367,7 +367,7 @@ hooks = [ { id = "snapper", name = "snapper", - entry = "uv run --group=snapper snapper --max-width 0 --in-place", + entry = "uv run --group=dev snapper --max-width 0 --in-place", language = "python", types_or = [ "rst", diff --git a/pyproject.toml b/pyproject.toml index 5953bde45..57d650a43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,6 +75,7 @@ dev = [ # use it to lint shell commands in GitHub workflow files. "shellcheck-py==0.11.0.1", "shfmt-py==4.1.0", + "snapper-fmt==0.11.0", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", "sphinx-lint==1.0.2", @@ -97,9 +98,6 @@ dev = [ "zizmor==1.30.0", ] release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ] -snapper = [ - "snapper-fmt==0.11.0", -] [tool.setuptools] packages.find.where = [