simple_english 0.9.0-aarch64-linux → 0.11.0-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +40 -9
- data/docs/RULES.md +1 -1
- data/lib/simple_english/client/language_tool.rb +4 -12
- data/lib/simple_english/lint/annotated_text.rb +7 -20
- data/lib/simple_english/lint/markdown.rb +4 -7
- data/lib/simple_english/lint/utf16.rb +33 -0
- data/lib/simple_english/version.rb +1 -1
- data/lib/simple_english.rb +1 -0
- data/libexec/simple_english/languagetool-server +1 -1
- data/libexec/simple_english/languagetool-server.sbom.json +1 -1
- data/rules/simple-english.xml +26 -2
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd3dbf80f63e4a6586d0c1b9ab24cd843994cbac8e73927cf2a7242d030b9d31
|
|
4
|
+
data.tar.gz: dab8d658d20ab00c39d44a7610fc20cb020ef86c222ec3d1e05c281a7d569e6d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6671ad97fa056f5a1714ce074a146823a45b0b554ac0252dda25f7d1d037c411a3e7e572ea51303a6345a0d62b80065bc24c855527285ae07cc96b77fd7b1af0
|
|
7
|
+
data.tar.gz: 06e1f94e2e0c904861713691e0d62d3f21a8d975593244e7a6acd1e19ade0612b0e536436e614ab61aecd431f21e68c1437ba03403eee35d940c912af64d0b74
|
data/README.md
CHANGED
|
@@ -49,6 +49,7 @@ the first pass and checks its own draft before you read the file.
|
|
|
49
49
|
| `codex` | plugin `simple-english` | [README](integrations/codex/README.md) |
|
|
50
50
|
| `cursor` | plugin folder `simple-english` | [README](integrations/cursor/README.md) |
|
|
51
51
|
| `opencode` | plugin `simple-english` | [README](integrations/opencode/README.md) |
|
|
52
|
+
| `vscode-copilot` | config wiring | [README](integrations/vscode-copilot/README.md) |
|
|
52
53
|
|
|
53
54
|
If your agent is not on the list, [open an issue](https://github.com/TonyCTHsu/simple-english/issues).
|
|
54
55
|
|
|
@@ -132,29 +133,59 @@ se mcp
|
|
|
132
133
|
|
|
133
134
|
### CI
|
|
134
135
|
|
|
135
|
-
Gate the prose in
|
|
136
|
-
fails the build on findings, and the SARIF report puts them inline:
|
|
136
|
+
Gate the pull request's prose in GitHub Actions. The lint fails the build on findings:
|
|
137
137
|
|
|
138
138
|
```yaml
|
|
139
139
|
name: lint-docs
|
|
140
140
|
on: [pull_request]
|
|
141
|
-
permissions:
|
|
142
|
-
security-events: write
|
|
143
141
|
jobs:
|
|
144
142
|
lint:
|
|
145
143
|
runs-on: ubuntu-latest
|
|
146
144
|
steps:
|
|
147
145
|
- uses: actions/checkout@v7
|
|
148
|
-
- uses:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
- uses: TonyCTHsu/simple-english@v0.11.0
|
|
147
|
+
with:
|
|
148
|
+
files: |
|
|
149
|
+
docs/
|
|
150
|
+
README.md
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To see the findings inline in the pull request, lint with
|
|
154
|
+
`format: sarif` and upload the report. Add
|
|
155
|
+
`permissions: {security-events: write}` to the workflow:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
- uses: TonyCTHsu/simple-english@v0.11.0
|
|
159
|
+
with:
|
|
160
|
+
format: sarif
|
|
152
161
|
- uses: github/codeql-action/upload-sarif@v3
|
|
153
162
|
with:
|
|
154
|
-
sarif_file:
|
|
163
|
+
sarif_file: simple-english.sarif
|
|
155
164
|
if: always()
|
|
156
165
|
```
|
|
157
166
|
|
|
167
|
+
Any CI can run the lint. Install the gem, run `se lint .`, and fail the
|
|
168
|
+
build on exit code 1.
|
|
169
|
+
|
|
170
|
+
### Git hooks
|
|
171
|
+
|
|
172
|
+
Install the gem once, then wire your hook runner. The command to run
|
|
173
|
+
is `se lint`.
|
|
174
|
+
|
|
175
|
+
#### Pre-commit framework
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
# .pre-commit-config.yaml
|
|
179
|
+
repos:
|
|
180
|
+
- repo: https://github.com/TonyCTHsu/simple-english
|
|
181
|
+
rev: v0.11.0
|
|
182
|
+
hooks:
|
|
183
|
+
- id: se-lint
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
For Husky with lint-staged, map every staged file to `se lint`. For
|
|
187
|
+
Lefthook, run `se lint {staged_files}` in a `pre-commit` command.
|
|
188
|
+
|
|
158
189
|
## Config and suppressions
|
|
159
190
|
|
|
160
191
|
### Config file
|
data/docs/RULES.md
CHANGED
|
@@ -50,7 +50,7 @@ Use the simple past. Say when it happened.
|
|
|
50
50
|
|
|
51
51
|
### SE_ING_AFTER_COMMA: No -ing after a comma
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Write a new sentence, or put the condition first. A trailing -ing phrase hides who does what and when.
|
|
54
54
|
|
|
55
55
|
- Wrong: The tool runs, making it easy.
|
|
56
56
|
- Right: The tool runs. It is easy.
|
|
@@ -14,6 +14,7 @@ require "net/http"
|
|
|
14
14
|
require "uri"
|
|
15
15
|
|
|
16
16
|
require_relative "../lint/plain_text"
|
|
17
|
+
require_relative "../lint/utf16"
|
|
17
18
|
|
|
18
19
|
module SimpleEnglish
|
|
19
20
|
module LanguageTool
|
|
@@ -71,25 +72,16 @@ module SimpleEnglish
|
|
|
71
72
|
end
|
|
72
73
|
|
|
73
74
|
def utf16_slice(text, offset, length)
|
|
74
|
-
first =
|
|
75
|
-
last =
|
|
75
|
+
first = UTF16.index(text, offset)
|
|
76
|
+
last = UTF16.index(text, offset + length)
|
|
76
77
|
text[first...last]
|
|
77
78
|
end
|
|
78
79
|
|
|
79
|
-
def utf16_index(text, offset)
|
|
80
|
-
units = 0
|
|
81
|
-
text.each_char.with_index do |char, index|
|
|
82
|
-
return index if units >= offset
|
|
83
|
-
units += (char.ord > 0xFFFF) ? 2 : 1
|
|
84
|
-
end
|
|
85
|
-
text.length
|
|
86
|
-
end
|
|
87
|
-
|
|
88
80
|
def to_payload(payload)
|
|
89
81
|
payload.is_a?(String) ? PlainText.new(payload) : payload
|
|
90
82
|
end
|
|
91
83
|
|
|
92
|
-
private_class_method :to_payload, :with_context, :utf16_slice
|
|
84
|
+
private_class_method :to_payload, :with_context, :utf16_slice
|
|
93
85
|
end
|
|
94
86
|
end
|
|
95
87
|
end
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
require_relative "extractor"
|
|
10
10
|
require_relative "segment"
|
|
11
11
|
require_relative "result"
|
|
12
|
+
require_relative "utf16"
|
|
12
13
|
|
|
13
14
|
module SimpleEnglish
|
|
14
15
|
module AnnotatedText
|
|
@@ -21,10 +22,12 @@ module SimpleEnglish
|
|
|
21
22
|
def build(source, spans)
|
|
22
23
|
segments = []
|
|
23
24
|
cursor = 0 # byte offset into source
|
|
25
|
+
stream_start = 0 # character offset into the annotation stream
|
|
24
26
|
emit = lambda do |text:, content:, file_char:, interpret_as: nil|
|
|
25
27
|
next if content.empty?
|
|
26
28
|
segments << Segment.new(text: text, content: content, file_char: file_char,
|
|
27
|
-
stream_start:
|
|
29
|
+
stream_start: stream_start, interpret_as: interpret_as)
|
|
30
|
+
stream_start += content.length
|
|
28
31
|
end
|
|
29
32
|
spans = spans.sort_by(&:start_byte)
|
|
30
33
|
spans.each do |span|
|
|
@@ -66,14 +69,14 @@ module SimpleEnglish
|
|
|
66
69
|
|
|
67
70
|
# -> [line, column], both 1-based. Column in UTF-16 code units.
|
|
68
71
|
def locate(result, utf16_offset)
|
|
69
|
-
char =
|
|
72
|
+
char = UTF16.index(result.stream, utf16_offset)
|
|
70
73
|
segment = result.segments.find do |s|
|
|
71
74
|
char >= s.stream_start && char < s.stream_start + s.content.length
|
|
72
75
|
end || result.segments.last
|
|
73
76
|
file_char = segment.file_char + (char - segment.stream_start)
|
|
74
77
|
starts = line_starts(result.source)
|
|
75
78
|
line = starts.rindex { |start| start <= file_char } + 1
|
|
76
|
-
[line,
|
|
79
|
+
[line, UTF16.column(result.source, starts[line - 1], file_char)]
|
|
77
80
|
end
|
|
78
81
|
|
|
79
82
|
def split(comment)
|
|
@@ -96,22 +99,6 @@ module SimpleEnglish
|
|
|
96
99
|
starts
|
|
97
100
|
end
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
units = 0
|
|
101
|
-
stream.each_char.with_index do |char, index|
|
|
102
|
-
return index if units >= offset
|
|
103
|
-
units += (char.ord > 0xFFFF) ? 2 : 1
|
|
104
|
-
end
|
|
105
|
-
stream.length
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def utf16_column(source, from, to)
|
|
109
|
-
units = 1
|
|
110
|
-
source[from...to].each_char { |c| units += (c.ord > 0xFFFF) ? 2 : 1 }
|
|
111
|
-
units
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
private_class_method :split, :char_index, :line_starts,
|
|
115
|
-
:utf16_to_char, :utf16_column
|
|
102
|
+
private_class_method :split, :char_index, :line_starts
|
|
116
103
|
end
|
|
117
104
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "paragraph"
|
|
4
|
+
require_relative "utf16"
|
|
4
5
|
|
|
5
6
|
# Markdown stripping and paragraph splitting. Block structure comes
|
|
6
7
|
# from the tree-sitter Markdown grammar shipped with the pack the
|
|
@@ -42,16 +43,12 @@ module SimpleEnglish
|
|
|
42
43
|
# Width-preserving replacements keep LanguageTool positions aligned
|
|
43
44
|
# with the source.
|
|
44
45
|
line
|
|
45
|
-
.gsub(/`[^`]*`/) { |code| "X" *
|
|
46
|
+
.gsub(/`[^`]*`/) { |code| "X" * UTF16.length(code) }
|
|
46
47
|
.sub(/\A\#{1,6} /) { |marker| " " * marker.length }
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def spaces_for(text)
|
|
50
|
-
" " *
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def utf16_length(text)
|
|
54
|
-
text.each_char.sum { |char| (char.ord > 0xFFFF) ? 2 : 1 }
|
|
51
|
+
" " * UTF16.length(text)
|
|
55
52
|
end
|
|
56
53
|
|
|
57
54
|
# A vertical list is not one paragraph: each list item is its own.
|
|
@@ -115,7 +112,7 @@ module SimpleEnglish
|
|
|
115
112
|
TreeSitterLanguagePack.get_parser("markdown").parse(text).root_node
|
|
116
113
|
end
|
|
117
114
|
|
|
118
|
-
private_class_method :strip_line, :spaces_for, :
|
|
115
|
+
private_class_method :strip_line, :spaces_for, :node_rows,
|
|
119
116
|
:blank_rows, :each_node, :inside_list_item?, :parse
|
|
120
117
|
end
|
|
121
118
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# UTF-16 code-unit arithmetic. LanguageTool is a Java service, and
|
|
4
|
+
# Java strings count UTF-16 code units: an astral-plane character
|
|
5
|
+
# counts as two. Every offset crossing the LT wire goes through
|
|
6
|
+
# here.
|
|
7
|
+
|
|
8
|
+
module SimpleEnglish
|
|
9
|
+
module UTF16
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# The character index in text where the offsetth code unit
|
|
13
|
+
# falls.
|
|
14
|
+
def index(text, offset)
|
|
15
|
+
units = 0
|
|
16
|
+
text.each_char.with_index do |char, index|
|
|
17
|
+
return index if units >= offset
|
|
18
|
+
units += (char.ord > 0xFFFF) ? 2 : 1
|
|
19
|
+
end
|
|
20
|
+
text.length
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# The code-unit length of text.
|
|
24
|
+
def length(text)
|
|
25
|
+
text.each_char.sum { |char| (char.ord > 0xFFFF) ? 2 : 1 }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The 1-based code-unit column of the character at index to.
|
|
29
|
+
def column(source, from, to)
|
|
30
|
+
length(source[from...to]) + 1
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/simple_english.rb
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
require_relative "simple_english/version"
|
|
9
9
|
require_relative "simple_english/lint/finding"
|
|
10
10
|
require_relative "simple_english/lint/paragraph"
|
|
11
|
+
require_relative "simple_english/lint/utf16"
|
|
11
12
|
require_relative "simple_english/lint/markdown"
|
|
12
13
|
require_relative "simple_english/lint/counts"
|
|
13
14
|
require_relative "simple_english/setup/languagetool"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/libexec/simple_english/languagetool-server
|
|
3
3
|
size: 127207544 bytes
|
|
4
|
-
sha256:
|
|
4
|
+
sha256: 90096407bc281ca375f61588bba5cb60a0906aac6b0ff37e19822a635e212620
|
data/rules/simple-english.xml
CHANGED
|
@@ -2,13 +2,21 @@
|
|
|
2
2
|
<rules lang="en">
|
|
3
3
|
<category id="SIMPLE_ENGLISH" name="Simple English">
|
|
4
4
|
|
|
5
|
+
<!-- LanguageTool splits "you're" into "you" + "'re", so the
|
|
6
|
+
regex matches the apostrophe-initial tokens: "'re", "'ve",
|
|
7
|
+
"'ll", "'d", "'m", and the "n't" token of "don't". The
|
|
8
|
+
apostrophe-s form stays out: it is both the contraction
|
|
9
|
+
"it is" and the possessive, and the tagger does not tell
|
|
10
|
+
them apart reliably. -->
|
|
5
11
|
<rule id="SE_NO_CONTRACTIONS" name="No contractions">
|
|
6
12
|
<pattern>
|
|
7
|
-
<token regexp="yes">[a-z]
|
|
13
|
+
<token regexp="yes">[a-z]*['’](t|re|ve|ll|d|m)</token>
|
|
8
14
|
</pattern>
|
|
9
15
|
<message>Write the words in full. No contractions.</message>
|
|
10
16
|
<example type="incorrect">You <marker>don't</marker> need this file.</example>
|
|
17
|
+
<example type="incorrect">If <marker>you're</marker> connecting, use TCP.</example>
|
|
11
18
|
<example type="correct">You do not need this file.</example>
|
|
19
|
+
<example type="correct">sqlpipe's IP is in the config.</example>
|
|
12
20
|
</rule>
|
|
13
21
|
|
|
14
22
|
<rule id="SE_NO_SEMICOLON" name="No semicolons">
|
|
@@ -45,6 +53,11 @@
|
|
|
45
53
|
<example type="correct">The worker wrote the log.</example>
|
|
46
54
|
</rule>
|
|
47
55
|
|
|
56
|
+
<!-- A passive agent changes the finding, not the rule match:
|
|
57
|
+
"has been read by X" also matches SE_ACTIVE_VOICE, and
|
|
58
|
+
LanguageTool reports only the first of two overlapping
|
|
59
|
+
matches, so this rule stays silent there. The active-voice
|
|
60
|
+
finding names the fix. -->
|
|
48
61
|
<rule id="SE_PRESENT_PERFECT" name="Simple tenses only">
|
|
49
62
|
<pattern>
|
|
50
63
|
<token regexp="yes">have|has|had</token>
|
|
@@ -55,11 +68,22 @@
|
|
|
55
68
|
<example type="correct">The job completed.</example>
|
|
56
69
|
</rule>
|
|
57
70
|
|
|
71
|
+
<!-- Spirit: a participle clause after a comma leaves the subject
|
|
72
|
+
and the time relation implicit, so the reader must guess. Two
|
|
73
|
+
escapes exist: write a new sentence, or, when the phrase
|
|
74
|
+
states a condition, put the condition first
|
|
75
|
+
(SE_CONDITION_FIRST). No word-list carve-outs: this tool ships
|
|
76
|
+
no approved dictionary, so every comma-plus-ing participle
|
|
77
|
+
fires, including the preposition-like ones. -->
|
|
58
78
|
<rule id="SE_ING_AFTER_COMMA" name="No -ing after a comma">
|
|
59
79
|
<pattern><token>,</token><token postag="VBG"><exception scope="next" regexp="yes">[,)]|and|or</exception></token></pattern>
|
|
60
|
-
<message>
|
|
80
|
+
<message>Write a new sentence, or put the condition first. A trailing -ing phrase hides who does what and when.</message>
|
|
61
81
|
<example type="incorrect">The tool runs<marker>, making</marker> it easy.</example>
|
|
82
|
+
<example type="incorrect">Open the valve<marker>, depending</marker> on the pressure.</example>
|
|
83
|
+
<example type="incorrect">Remove the cover<marker>, making</marker> sure not to damage the seal.</example>
|
|
62
84
|
<example type="correct">The tool runs. It is easy.</example>
|
|
85
|
+
<example type="correct">If the pressure is more than 300 kPa, open the valve.</example>
|
|
86
|
+
<example type="correct">Remove the cover. Make sure that you do not damage the seal.</example>
|
|
63
87
|
<example type="correct">The walkthrough (accounts, VPC, secrets, troubleshooting) is in the guide.</example>
|
|
64
88
|
<example type="correct">The guide covers billing, troubleshooting, and support for each environment.</example>
|
|
65
89
|
<example type="correct">The guide covers billing, troubleshooting and support for each environment.</example>
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: simple_english
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- TonyCTHsu
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: tree_sitter_language_pack
|
|
@@ -154,6 +154,7 @@ files:
|
|
|
154
154
|
- lib/simple_english/lint/segment.rb
|
|
155
155
|
- lib/simple_english/lint/span.rb
|
|
156
156
|
- lib/simple_english/lint/suppressions.rb
|
|
157
|
+
- lib/simple_english/lint/utf16.rb
|
|
157
158
|
- lib/simple_english/model_context_protocol.rb
|
|
158
159
|
- lib/simple_english/setup/config.rb
|
|
159
160
|
- lib/simple_english/setup/fingerprint.rb
|
|
@@ -177,7 +178,7 @@ licenses:
|
|
|
177
178
|
metadata:
|
|
178
179
|
homepage_uri: https://github.com/TonyCTHsu/simple-english
|
|
179
180
|
source_code_uri: https://github.com/TonyCTHsu/simple-english
|
|
180
|
-
changelog_uri: https://github.com/TonyCTHsu/simple-english/blob/v0.
|
|
181
|
+
changelog_uri: https://github.com/TonyCTHsu/simple-english/blob/v0.11.0/CHANGELOG.md
|
|
181
182
|
post_install_message:
|
|
182
183
|
rdoc_options: []
|
|
183
184
|
require_paths:
|