Skip to content

Commit 7cb3783

Browse files
committed
feat: use prism over manual highlighting
1 parent 2d853c2 commit 7cb3783

File tree

7 files changed

+518
-564
lines changed

7 files changed

+518
-564
lines changed

nix/proselint-web.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ in
3232
inherit (final) pname;
3333
src = ../website;
3434

35-
hash = "sha256-kxKZuowOGgxXKMyn66pqkPQv/xgJlnpVE5r5rYyuBOk=";
35+
hash = "sha256-ygq9WGXveRKZMum3kcyShrFrxafJasgZKKaae7jOQeQ=";
3636
fetcherVersion = 2;
3737
};
3838

website/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
"version": "1.0.0",
44
"type": "module",
55
"devDependencies": {
6-
"@tailwindcss/postcss": "^4.1.13",
7-
"autoprefixer": "^10.4.21",
6+
"@tailwindcss/postcss": "^4.1.18",
7+
"autoprefixer": "^10.4.23",
88
"postcss": "^8.5.6",
9-
"tailwindcss": "^4.1.13",
10-
"vite": "^7.1.9"
9+
"tailwindcss": "^4.1.18",
10+
"vite": "^7.3.1"
1111
},
1212
"scripts": {
1313
"prebuild": "node ./rules.mjs",
@@ -17,6 +17,7 @@
1717
"preview": "vite preview"
1818
},
1919
"dependencies": {
20+
"prismjs": "^1.30.0",
2021
"vite-plugin-ejs": "^1.7.0"
2122
}
2223
}

website/pnpm-lock.yaml

Lines changed: 412 additions & 422 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

website/src/help.html

Lines changed: 73 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -17,71 +17,71 @@ <h2>Install</h2>
1717

1818
<div>
1919
<p>Via <em>Pip</em></p>
20-
<pre><code><span class="blue">pip</span> <span class="purple">install</span> <span class="green">proselint</span></code></pre>
20+
<pre><code class="language-bash">pip install proselint</code></pre>
2121
</div>
2222

2323
<div>
2424
<p>Via <em>Apt</em> (Debian / Ubuntu)</p>
25-
<pre><code><span class="blue">apt</span> <span class="purple">install</span> <span class="green">python3-proselint</span></code></pre>
25+
<pre><code class="language-bash">apt install python3-proselint</code></pre>
2626
</div>
2727

2828
<div>
2929
<p>Via <em>Homebrew</em> (macOS / Linux)</p>
30-
<pre><code><span class="blue">brew</span> <span class="purple">install</span> <span class="green">proselint</span></code></pre>
30+
<pre><code class="language-bash">brew install proselint</code></pre>
3131
</div>
3232

3333
<div>
3434
<p>Via <em>Conda</em></p>
35-
<pre><code><span class="blue">conda</span> <span class="purple">install</span> <span class="green">conda-forge::proselint</span></code></pre>
35+
<pre><code class="language-bash">conda install conda-forge::proselint</code></pre>
3636
</div>
3737

3838
<div>
3939
<p>Via <em>Nix</em></p>
40-
<pre><code><span class="purple">environment.systemPackages</span> <span class="green">=</span> <span class="blue">with pkgs;</span> [
41-
<span class="green">proselint</span>
40+
<pre><code class="language-nix">environment.systemPackages = with pkgs; [
41+
proselint
4242
];</code></pre>
4343
</div>
4444

4545
<div>
4646
<p>From <em>source</em></p>
47-
<pre><code><span class="blue">git</span> <span class="purple">clone</span> <span class="green">https://github.com/amperser/proselint.git</span>
48-
<span class="blue">cd</span> <span class="green">proselint</span>
47+
<pre><code class="language-bash">git clone https://github.com/amperser/proselint.git
48+
cd proselint
4949

50-
<span class="blue">uv</span> <span class="purple">pip install</span> <span class="green">.</span> # or, with Nix
51-
<span class="blue">nix</span> <span class="purple">profile install</span> <span class="green">.</span></code></pre>
50+
uv pip install . # or, with Nix
51+
nix profile install .</code></pre>
5252
</div>
5353

5454
<h2>Configuration</h2>
5555
<p>The default configuration is:</p>
5656

57-
<pre><code>{
58-
<span class="blue">"max_errors"</span>: <span class="green">1000</span>,
59-
<span class="blue">"checks"</span>: {
60-
<span class="blue">"annotations"</span>: <span class="green">true</span>,
61-
<span class="blue">"archaism"</span>: <span class="green">true</span>,
62-
<span class="blue">"cliches"</span>: <span class="green">true</span>,
63-
<span class="blue">"dates_times"</span>: <span class="green">true</span>,
64-
<span class="blue">"hedging"</span>: <span class="green">true</span>,
65-
<span class="blue">"industrial_language"</span>: <span class="green">true</span>,
66-
<span class="blue">"lexical_illusions"</span>: <span class="green">true</span>,
67-
<span class="blue">"malapropisms"</span>: <span class="green">true</span>,
68-
<span class="blue">"misc"</span>: <span class="green">true</span>,
69-
<span class="blue">"mixed_metaphors"</span>: <span class="green">true</span>,
70-
<span class="blue">"mondegreens"</span>: <span class="green">true</span>,
71-
<span class="blue">"needless_variants"</span>: <span class="green">true</span>,
72-
<span class="blue">"nonwords"</span>: <span class="green">true</span>,
73-
<span class="blue">"oxymorons"</span>: <span class="green">true</span>,
74-
<span class="blue">"psychology"</span>: <span class="green">true</span>,
75-
<span class="blue">"redundancy"</span>: <span class="green">true</span>,
76-
<span class="blue">"restricted"</span>: <span class="red">false</span>,
77-
<span class="blue">"skunked_terms"</span>: <span class="green">true</span>,
78-
<span class="blue">"social_awareness"</span>: <span class="green">true</span>,
79-
<span class="blue">"spelling"</span>: <span class="green">true</span>,
80-
<span class="blue">"terms"</span>: <span class="green">true</span>,
81-
<span class="blue">"typography"</span>: <span class="green">true</span>,
82-
<span class="blue">"uncomparables"</span>: <span class="green">true</span>,
83-
<span class="blue">"weasel_words"</span>: <span class="green">true</span>
84-
}
57+
<pre><code class="language-json">{
58+
"max_errors": 1000,
59+
"checks": {
60+
"annotations": true,
61+
"archaism": true,
62+
"cliches": true,
63+
"dates_times": true,
64+
"hedging": true,
65+
"industrial_language": true,
66+
"lexical_illusions": true,
67+
"malapropisms": true,
68+
"misc": true,
69+
"mixed_metaphors": true,
70+
"mondegreens": true,
71+
"needless_variants": true,
72+
"nonwords": true,
73+
"oxymorons": true,
74+
"psychology": true,
75+
"redundancy": true,
76+
"restricted": false,
77+
"skunked_terms": true,
78+
"social_awareness": true,
79+
"spelling": true,
80+
"terms": true,
81+
"typography": true,
82+
"uncomparables": true,
83+
"weasel_words": true
84+
}
8585
}</code></pre>
8686

8787
<p>
@@ -92,76 +92,72 @@ <h2>Configuration</h2>
9292
<li><code>.proselintrc.json</code> in the current working directory</li>
9393
<li><code>$XDG_CONFIG_HOME/proselint/config.json</code></li>
9494
<li><code>$HOME/.proselintrc.json</code></li>
95-
<li><code>/etc/proselintrc</code> (system-wide default)</li>
95+
<li><code>/etc/proselintrc</code></li>
9696
</ul>
9797

9898
<p>
99-
Thus, if you want to override any rule locally, all you'd need to do is
100-
create a <code>.proselintrc.json</code> and set the rule path to
101-
<code>false</code>. For example, to disable
102-
<code>typography.symbols.curly_quotes</code>:
99+
To override a rule locally, create <code>.proselintrc.json</code>. For
100+
example:
103101
</p>
104102

105-
<pre><code>{
106-
<span class="blue">"checks.typography.symbols.curly_quotes"</span>: <span class="red">false</span>
103+
<pre><code class="language-json">{
104+
"checks.typography.symbols.curly_quotes": false
107105
}</code></pre>
108106

109107
<h2>Wire Output</h2>
110108

111109
<p>
112-
<em>Proselint</em> supports structured output for programmatic usage
113-
with the <code>--output-format json</code> flag, like so:
110+
Structured output can be enabled with
111+
<code>--output-format json</code>:
114112
</p>
115113

116-
<pre><code><span class="blue">proselint</span> <span class="purple">--output-format</span> <span class="green">json</span> syllabus.md</code></pre>
114+
<pre><code class="language-bash">proselint --output-format json syllabus.md</code></pre>
117115

118116
<p>The output schema is:</p>
119117

120-
<pre><code><span class="purple">enum</span> <span class="blue">ErrorCode</span> {
121-
<span class="green">Unknown</span> = -31999,
122-
<span class="green">FileError</span> = -31998,
123-
<span class="green">LintError</span> = -31997,
118+
<pre><code class="language-typescript">enum ErrorCode {
119+
Unknown = -31999,
120+
FileError = -31998,
121+
LintError = -31997,
124122
}
125123

126-
<span class="purple">interface</span> <span class="blue">ResponseError</span> {
127-
<span class="green">code</span>: ErrorCode;
128-
<span class="green">message</span>: string;
129-
<span class="green">data</span>?: any;
124+
interface ResponseError {
125+
code: ErrorCode;
126+
message: string;
127+
data?: any;
130128
}
131129

132-
<span class="purple">interface</span> <span class="blue">CheckResult</span> {
133-
<span class="green">check_path</span>: string;
134-
<span class="green">message</span>: string;
135-
<span class="green">span</span>: [number, number];
136-
<span class="green">replacements</span>: string | null;
130+
interface CheckResult {
131+
check_path: string;
132+
message: string;
133+
span: [number, number];
134+
replacements: string | null;
137135
}
138136

139-
<span class="purple">interface</span> <span class="blue">LintResult</span> <span class="purple">extends</span> <span class="blue">CheckResult</span> {
140-
<span class="green">pos</span>: [number, number];
137+
interface LintResult extends CheckResult {
138+
pos: [number, number];
141139
}
142140

143-
<span class="purple">interface</span> <span class="blue">FileOutput</span> {
144-
<span class="green">diagnostics</span>?: LintResult[];
145-
<span class="green">error</span>?: ResponseError;
141+
interface FileOutput {
142+
diagnostics?: LintResult[];
143+
error?: ResponseError;
146144
}
147145

148-
<span class="purple">interface</span> <span class="blue">ProselintOutput</span> {
149-
<span class="green">result</span>?: Record&lt;string, FileOutput&gt;;
150-
<span class="green">error</span>?: ResponseError;
146+
interface ProselintOutput {
147+
result?: Record<string, FileOutput>;
148+
error?: ResponseError;
151149
}</code></pre>
152150

153151
<p>
154-
Every invocation of <em>proselint</em> produces exactly one
155-
<code>ProselintOutput</code> object. Both
156-
<code>ProselintOutput</code> and <code>FileOutput</code> are tagged
157-
unions. <br /><br />
158-
This means that <code>ProselintOutput</code> will always contain one of
159-
<code>result</code> or <code>error</code>, but never both, and the same
160-
applies to <code>diagnostics</code> and <code>error</code> for
161-
<code>FileOutput</code>.
152+
Each invocation produces exactly one
153+
<code>ProselintOutput</code>. Both
154+
<code>ProselintOutput</code> and
155+
<code>FileOutput</code> are tagged unions.
162156
</p>
163157
</main>
164158

165159
<%- include('partials/footer.ejs') %>
160+
161+
<script type="module" src="/main.js"></script>
166162
</body>
167163
</html>

website/src/index.html

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33
<head>
44
<meta charset="UTF-8" />
55
<title>Proselint</title>
6+
67
<link rel="stylesheet" href="styles.css" />
8+
<script type="module" src="/main.js"></script>
79
</head>
810
<body>
911
<main>
1012
<h1>Proselint</h1>
13+
1114
<p>
1215
<em>Proselint</em> is a linter for English prose. It highlights
1316
<em>clichés</em>, <em>jargon</em>, <em>illogical phrasing</em>, and
14-
other stylistic issues, much like a spellchecker for style. <br />
15-
<br />
16-
17+
other stylistic issues, much like a spellchecker for style. <br /><br />
1718
You can navigate the available <a href="rules.html">rules</a> or get
1819
further <a href="help.html">help</a>.
1920
</p>
@@ -22,36 +23,25 @@ <h2>Install</h2>
2223
<p>
2324
Install via <em>pip</em> and try a quick example from the command line.
2425
</p>
25-
<div>
26-
<pre title="Click to copy">
27-
<code><span class="blue">pip</span> <span class="purple">install</span> <span class="green">proselint</span></code>
28-
</pre>
29-
<pre title="Click to copy">
30-
<code><span class="blue">echo</span> <span class="green">"This is very unique and literally perfect."</span> <span class="red">|</span> <span class="blue">proselint</span> <span class="purple">check</span>
31-
<span class="blue">proselint</span> <span class="purple">check</span> <span class="amber">README.md</span></code>
32-
</pre>
33-
</div>
26+
27+
<pre><code class="language-bash">pip install proselint</code></pre>
28+
29+
<pre><code class="language-bash">echo "This is very unique and literally perfect." | proselint check
30+
proselint check README.md</code></pre>
31+
3432
<h2>Try it</h2>
3533
<p>Paste or type some text below.</p>
34+
3635
<div id="editor">
3736
<textarea id="input" rows="8">
3837
This is very unique and literally perfect.</textarea
3938
>
40-
<!-- prettier-ignore -->
41-
<div id="preview">This is <span class="highlight" title="Comparison of an uncomparable: 'very unique' is not comparable.">very unique</span> and literally perfect.</div>
39+
<div id="preview">This is very unique and literally perfect.</div>
4240
</div>
4341

4442
<h3>Issues</h3>
4543
<ul id="issues">
46-
<li>
47-
<em>uncomparables</em> Comparison of an uncomparable: 'very unique' is
48-
not comparable.
49-
</li>
50-
<li>
51-
<em>weasel_words.very</em> Substitute 'damn' every time you're
52-
inclined to write 'very'; your editor will delete it and the writing
53-
will be just as it should be.
54-
</li>
44+
<li>No issues found.</li>
5545
</ul>
5646
</main>
5747

@@ -72,18 +62,15 @@ <h3>Issues</h3>
7262

7363
for (const { span, message } of spans) {
7464
let [start, end] = span;
75-
7665
start--;
7766
end--;
7867

79-
if (start < cursor) {
80-
continue;
81-
}
68+
if (start < cursor) continue;
8269

8370
result += text.slice(cursor, start);
84-
result += `<span class="highlight" title="${message}">`;
71+
result += `<mark title="${message}">`;
8572
result += text.slice(start, end);
86-
result += `</span>`;
73+
result += `</mark>`;
8774

8875
cursor = end;
8976
}
@@ -94,7 +81,6 @@ <h3>Issues</h3>
9481

9582
function debounce(fn, delay) {
9683
let timer;
97-
9884
return function (...args) {
9985
clearTimeout(timer);
10086
timer = setTimeout(() => fn.apply(this, args), delay);
@@ -105,7 +91,6 @@ <h3>Issues</h3>
10591
if (input.value.trim() === "") {
10692
issues.innerHTML = "<li>No issues found.</li>";
10793
preview.textContent = input.value;
108-
10994
return;
11095
}
11196

@@ -124,6 +109,7 @@ <h3>Issues</h3>
124109

125110
if (json.data.length === 0) {
126111
issues.innerHTML = "<li>No issues found.</li>";
112+
preview.textContent = input.value;
127113
return;
128114
}
129115

website/src/main.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Prism from "prismjs";
2+
3+
import "prismjs/themes/prism.css";
4+
import "prismjs/components/prism-bash";
5+
import "prismjs/components/prism-json";
6+
import "prismjs/components/prism-typescript";
7+
8+
window.Prism = Prism;

0 commit comments

Comments
 (0)