diff --git a/.github/workflows/semantic-line-breaks.yml b/.github/workflows/semantic-line-breaks.yml new file mode 100644 index 00000000..d6cc0a0c --- /dev/null +++ b/.github/workflows/semantic-line-breaks.yml @@ -0,0 +1,28 @@ +--- +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 + 'snapper-fmt==0.11.0' + snapper --max-width 0 --check diff --git a/.vale.ini b/.vale.ini index e502c137..68e95e9b 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/docs/source/unreleased.rst b/docs/source/unreleased.rst index 22ac7472..d297d197 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:: diff --git a/styles/snapper/LongProseLine.yml b/styles/snapper/LongProseLine.yml new file mode 100644 index 00000000..1f5029f7 --- /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 00000000..3f4edaf5 --- /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]']