critique 0.1.75 → 0.1.78
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.
- package/CHANGELOG.md +45 -1
- package/LICENSE +21 -0
- package/README.md +15 -11
- package/critique-screenshot.png +0 -0
- package/package.json +3 -1
- package/parsers-config.ts +254 -0
- package/scripts/preview-review.tsx +52 -2
- package/src/ansi-html.ts +4 -1
- package/src/assets/favicon-dark.png +0 -0
- package/src/assets/favicon-light.png +0 -0
- package/src/cli.tsx +5 -0
- package/src/diff-utils.test.ts +3 -1
- package/src/diff-utils.ts +64 -5
- package/src/web-utils.tsx +1 -1
- package/src/worker.tsx +34 -2
- package/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
# 0.1.78
|
|
2
|
+
|
|
3
|
+
- **Breaking change:** Single positional argument now uses `git diff` instead of `git show`
|
|
4
|
+
- Aligns with `git diff` behavior: `critique <ref>` compares ref to working tree
|
|
5
|
+
- Before: `critique HEAD~1` showed what HEAD~1 commit introduced (just that commit)
|
|
6
|
+
- After: `critique HEAD~1` shows all changes since HEAD~1 (like `git diff HEAD~1`)
|
|
7
|
+
- Examples with `critique HEAD~N`:
|
|
8
|
+
```
|
|
9
|
+
history: ...---A---B---C <- HEAD
|
|
10
|
+
\
|
|
11
|
+
+ uncommitted (if any)
|
|
12
|
+
|
|
13
|
+
critique HEAD~2 = shows B + C + uncommitted
|
|
14
|
+
critique HEAD~1 = shows C + uncommitted
|
|
15
|
+
critique HEAD = shows only uncommitted (empty if none)
|
|
16
|
+
```
|
|
17
|
+
- Examples with `critique <branch>` (when on feature branch):
|
|
18
|
+
```
|
|
19
|
+
main: A---B---C
|
|
20
|
+
\
|
|
21
|
+
feature: D---E---F <- HEAD
|
|
22
|
+
\
|
|
23
|
+
+ uncommitted (if any)
|
|
24
|
+
|
|
25
|
+
critique main = shows D + E + F + uncommitted
|
|
26
|
+
```
|
|
27
|
+
- To get the previous behavior (view a specific commit only), use `--commit`:
|
|
28
|
+
```
|
|
29
|
+
critique --commit HEAD~1 = shows only what HEAD~1 introduced (just that commit)
|
|
30
|
+
critique --commit abc123 = shows only what abc123 introduced
|
|
31
|
+
```
|
|
32
|
+
- Two positional arguments unchanged: `critique main feature` still uses three-dot syntax
|
|
33
|
+
|
|
34
|
+
# 0.1.77
|
|
35
|
+
|
|
36
|
+
- Web previews:
|
|
37
|
+
- Add favicon support with automatic light/dark mode switching
|
|
38
|
+
- Dark mode shows white diff icon, light mode shows black diff icon
|
|
39
|
+
|
|
40
|
+
# 0.1.76
|
|
41
|
+
|
|
42
|
+
- Syntax highlighting:
|
|
43
|
+
- Add tree-sitter parsers for 21 additional languages: Python, Rust, Go, C++, C#, Bash, C, Java, Ruby, PHP, Scala, HTML, JSON, YAML, Haskell, CSS, Julia, OCaml, Clojure, Swift, Nix
|
|
44
|
+
|
|
1
45
|
# 0.1.75
|
|
2
46
|
|
|
3
47
|
- Web previews:
|
|
@@ -53,7 +97,7 @@
|
|
|
53
97
|
|
|
54
98
|
- Worker:
|
|
55
99
|
- Email the license command via Resend on successful checkout
|
|
56
|
-
- Success page shows the `npx
|
|
100
|
+
- Success page shows the `npx critique login <key>` command
|
|
57
101
|
|
|
58
102
|
# 0.1.60
|
|
59
103
|
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tommy D. Rossi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -27,14 +27,16 @@ critique
|
|
|
27
27
|
# View staged changes
|
|
28
28
|
critique --staged
|
|
29
29
|
|
|
30
|
-
# View
|
|
31
|
-
critique HEAD
|
|
30
|
+
# View changes since a ref (like git diff)
|
|
31
|
+
critique HEAD~1 # shows last 1 commit (changes since HEAD~1)
|
|
32
|
+
critique HEAD~3 # shows last 3 commits
|
|
33
|
+
critique main # shows changes since main (your branch's additions)
|
|
32
34
|
|
|
33
|
-
# View a specific commit
|
|
35
|
+
# View a specific commit only (what that commit introduced)
|
|
34
36
|
critique --commit HEAD~1
|
|
35
|
-
critique abc1234
|
|
37
|
+
critique --commit abc1234
|
|
36
38
|
|
|
37
|
-
#
|
|
39
|
+
# Compare two refs (PR-style, shows what head added since diverging from base)
|
|
38
40
|
critique HEAD~3 HEAD # shows all changes from 3 commits ago to now
|
|
39
41
|
|
|
40
42
|
# Compare two branches (PR-style, shows what head added since diverging from base)
|
|
@@ -109,10 +111,11 @@ critique review --agent claude
|
|
|
109
111
|
# Review staged changes
|
|
110
112
|
critique review --staged
|
|
111
113
|
|
|
112
|
-
# Review
|
|
113
|
-
critique review HEAD
|
|
114
|
+
# Review changes since a ref (like git diff)
|
|
115
|
+
critique review HEAD~1 # review last 1 commit
|
|
116
|
+
critique review main # review changes since main
|
|
114
117
|
|
|
115
|
-
# Review a specific commit
|
|
118
|
+
# Review a specific commit only (what that commit introduced)
|
|
116
119
|
critique review --commit HEAD~1
|
|
117
120
|
critique review --commit abc1234
|
|
118
121
|
|
|
@@ -169,10 +172,11 @@ critique web
|
|
|
169
172
|
# View staged changes
|
|
170
173
|
critique web --staged
|
|
171
174
|
|
|
172
|
-
# View
|
|
173
|
-
critique web HEAD
|
|
175
|
+
# View changes since a ref (like git diff)
|
|
176
|
+
critique web HEAD~1 # last 1 commit
|
|
177
|
+
critique web main # changes since main
|
|
174
178
|
|
|
175
|
-
# View a specific commit
|
|
179
|
+
# View a specific commit only (what that commit introduced)
|
|
176
180
|
critique web --commit HEAD~1
|
|
177
181
|
|
|
178
182
|
# Compare branches (PR-style diff)
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
"name": "critique",
|
|
3
3
|
"module": "src/diff.tsx",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.78",
|
|
6
|
+
"license": "MIT",
|
|
6
7
|
"private": false,
|
|
7
8
|
"bin": "./src/cli.tsx",
|
|
8
9
|
"scripts": {
|
|
@@ -19,6 +20,7 @@
|
|
|
19
20
|
"@types/bun": "1.3.5",
|
|
20
21
|
"@types/js-yaml": "^4.0.9",
|
|
21
22
|
"hono": "^4.7.10",
|
|
23
|
+
"sharp": "^0.34.5",
|
|
22
24
|
"stripe": "^20.2.0",
|
|
23
25
|
"typescript": "^5.9.3",
|
|
24
26
|
"wrangler": "^4.19.1"
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Tree-sitter parser configuration for syntax highlighting
|
|
2
|
+
// NOTE: For markdown, javascript and typescript, we use the opentui built-in parsers
|
|
3
|
+
// Warn: when taking queries from the nvim-treesitter repo, make sure to include the query dependencies as well
|
|
4
|
+
// marked with for example `; inherits: ecma` at the top of the file. Just put the dependencies before the actual query.
|
|
5
|
+
// ALSO: Some queries use breaking changes in the nvim-treesitter repo, that are not compatible with the (web-)tree-sitter parser.
|
|
6
|
+
export default {
|
|
7
|
+
parsers: [
|
|
8
|
+
{
|
|
9
|
+
filetype: "python",
|
|
10
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-python/releases/download/v0.23.6/tree-sitter-python.wasm",
|
|
11
|
+
queries: {
|
|
12
|
+
highlights: [
|
|
13
|
+
// NOTE: This nvim-treesitter query is currently broken, because the parser is not compatible with the query apparently.
|
|
14
|
+
// it is using "except" nodes that the parser is complaining about, but it has been in the query for 3+ years.
|
|
15
|
+
// Unclear.
|
|
16
|
+
// "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/python/highlights.scm",
|
|
17
|
+
"https://github.com/tree-sitter/tree-sitter-python/raw/refs/heads/master/queries/highlights.scm",
|
|
18
|
+
],
|
|
19
|
+
locals: [
|
|
20
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/python/locals.scm",
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
filetype: "rust",
|
|
26
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-rust/releases/download/v0.24.0/tree-sitter-rust.wasm",
|
|
27
|
+
queries: {
|
|
28
|
+
highlights: [
|
|
29
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/rust/highlights.scm",
|
|
30
|
+
],
|
|
31
|
+
locals: [
|
|
32
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/rust/locals.scm",
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
filetype: "go",
|
|
38
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-go/releases/download/v0.25.0/tree-sitter-go.wasm",
|
|
39
|
+
queries: {
|
|
40
|
+
highlights: [
|
|
41
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/go/highlights.scm",
|
|
42
|
+
],
|
|
43
|
+
locals: [
|
|
44
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/go/locals.scm",
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
filetype: "cpp",
|
|
50
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-cpp/releases/download/v0.23.4/tree-sitter-cpp.wasm",
|
|
51
|
+
queries: {
|
|
52
|
+
highlights: [
|
|
53
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/cpp/highlights.scm",
|
|
54
|
+
],
|
|
55
|
+
locals: [
|
|
56
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/cpp/locals.scm",
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
filetype: "csharp",
|
|
62
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-c-sharp/releases/download/v0.23.1/tree-sitter-c_sharp.wasm",
|
|
63
|
+
queries: {
|
|
64
|
+
highlights: [
|
|
65
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/c_sharp/highlights.scm",
|
|
66
|
+
],
|
|
67
|
+
locals: [
|
|
68
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/c_sharp/locals.scm",
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
filetype: "bash",
|
|
74
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-bash/releases/download/v0.25.0/tree-sitter-bash.wasm",
|
|
75
|
+
queries: {
|
|
76
|
+
highlights: [
|
|
77
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/bash/highlights.scm",
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
filetype: "c",
|
|
83
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-c/releases/download/v0.24.1/tree-sitter-c.wasm",
|
|
84
|
+
queries: {
|
|
85
|
+
highlights: [
|
|
86
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/c/highlights.scm",
|
|
87
|
+
],
|
|
88
|
+
locals: [
|
|
89
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/c/locals.scm",
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
filetype: "java",
|
|
95
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-java/releases/download/v0.23.5/tree-sitter-java.wasm",
|
|
96
|
+
queries: {
|
|
97
|
+
highlights: [
|
|
98
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/java/highlights.scm",
|
|
99
|
+
],
|
|
100
|
+
locals: [
|
|
101
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/java/locals.scm",
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
filetype: "ruby",
|
|
107
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-ruby/releases/download/v0.23.1/tree-sitter-ruby.wasm",
|
|
108
|
+
queries: {
|
|
109
|
+
highlights: [
|
|
110
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/ruby/highlights.scm",
|
|
111
|
+
],
|
|
112
|
+
locals: [
|
|
113
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/ruby/locals.scm",
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
filetype: "php",
|
|
119
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-php/releases/download/v0.24.2/tree-sitter-php.wasm",
|
|
120
|
+
queries: {
|
|
121
|
+
highlights: [
|
|
122
|
+
// NOTE: This nvim-treesitter query is currently broken, because the parser is not compatible with the query apparently.
|
|
123
|
+
// "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/php/highlights.scm",
|
|
124
|
+
"https://github.com/tree-sitter/tree-sitter-php/raw/refs/heads/master/queries/highlights.scm",
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
filetype: "scala",
|
|
130
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-scala/releases/download/v0.24.0/tree-sitter-scala.wasm",
|
|
131
|
+
queries: {
|
|
132
|
+
highlights: [
|
|
133
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/scala/highlights.scm",
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
filetype: "html",
|
|
139
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-html/releases/download/v0.23.2/tree-sitter-html.wasm",
|
|
140
|
+
queries: {
|
|
141
|
+
highlights: [
|
|
142
|
+
// NOTE: This nvim-treesitter query is currently broken, because the parser is not compatible with the query apparently.
|
|
143
|
+
// "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/html/highlights.scm",
|
|
144
|
+
"https://github.com/tree-sitter/tree-sitter-html/raw/refs/heads/master/queries/highlights.scm",
|
|
145
|
+
],
|
|
146
|
+
// TODO: Injections not working for some reason
|
|
147
|
+
// injections: [
|
|
148
|
+
// "https://github.com/tree-sitter/tree-sitter-html/raw/refs/heads/master/queries/injections.scm",
|
|
149
|
+
// ],
|
|
150
|
+
},
|
|
151
|
+
// injectionMapping: {
|
|
152
|
+
// nodeTypes: {
|
|
153
|
+
// script_element: "javascript",
|
|
154
|
+
// style_element: "css",
|
|
155
|
+
// },
|
|
156
|
+
// infoStringMap: {
|
|
157
|
+
// javascript: "javascript",
|
|
158
|
+
// css: "css",
|
|
159
|
+
// },
|
|
160
|
+
// },
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
filetype: "json",
|
|
164
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-json/releases/download/v0.24.8/tree-sitter-json.wasm",
|
|
165
|
+
queries: {
|
|
166
|
+
highlights: [
|
|
167
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/json/highlights.scm",
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
filetype: "yaml",
|
|
173
|
+
wasm: "https://github.com/tree-sitter-grammars/tree-sitter-yaml/releases/download/v0.7.2/tree-sitter-yaml.wasm",
|
|
174
|
+
queries: {
|
|
175
|
+
highlights: [
|
|
176
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/yaml/highlights.scm",
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
filetype: "haskell",
|
|
182
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-haskell/releases/download/v0.23.1/tree-sitter-haskell.wasm",
|
|
183
|
+
queries: {
|
|
184
|
+
highlights: [
|
|
185
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/haskell/highlights.scm",
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
filetype: "css",
|
|
191
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-css/releases/download/v0.25.0/tree-sitter-css.wasm",
|
|
192
|
+
queries: {
|
|
193
|
+
highlights: [
|
|
194
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/css/highlights.scm",
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
filetype: "julia",
|
|
200
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-julia/releases/download/v0.23.1/tree-sitter-julia.wasm",
|
|
201
|
+
queries: {
|
|
202
|
+
highlights: [
|
|
203
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/julia/highlights.scm",
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
filetype: "ocaml",
|
|
209
|
+
wasm: "https://github.com/tree-sitter/tree-sitter-ocaml/releases/download/v0.24.2/tree-sitter-ocaml.wasm",
|
|
210
|
+
queries: {
|
|
211
|
+
highlights: [
|
|
212
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/ocaml/highlights.scm",
|
|
213
|
+
],
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
filetype: "clojure",
|
|
218
|
+
wasm: "https://github.com/sogaiu/tree-sitter-clojure/releases/download/v0.0.13/tree-sitter-clojure.wasm",
|
|
219
|
+
queries: {
|
|
220
|
+
highlights: [
|
|
221
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/clojure/highlights.scm",
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
filetype: "swift",
|
|
227
|
+
wasm: "https://github.com/alex-pinkus/tree-sitter-swift/releases/download/0.7.1/tree-sitter-swift.wasm",
|
|
228
|
+
queries: {
|
|
229
|
+
highlights: [
|
|
230
|
+
// NOTE: Using parser repo queries instead of nvim-treesitter due to incompatible #lua-match? predicates
|
|
231
|
+
// "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/highlights.scm
|
|
232
|
+
"https://raw.githubusercontent.com/alex-pinkus/tree-sitter-swift/main/queries/highlights.scm",
|
|
233
|
+
],
|
|
234
|
+
locals: [
|
|
235
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/swift/locals.scm",
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
filetype: "nix",
|
|
241
|
+
// TODO: Replace with official tree-sitter-nix WASM when published
|
|
242
|
+
// See: https://github.com/nix-community/tree-sitter-nix/issues/66
|
|
243
|
+
wasm: "https://github.com/ast-grep/ast-grep.github.io/raw/40b84530640aa83a0d34a20a2b0623d7b8e5ea97/website/public/parsers/tree-sitter-nix.wasm",
|
|
244
|
+
queries: {
|
|
245
|
+
highlights: [
|
|
246
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/nix/highlights.scm",
|
|
247
|
+
],
|
|
248
|
+
locals: [
|
|
249
|
+
"https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/nix/locals.scm",
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
}
|
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
// Renders example hunks and review data to preview TUI appearance.
|
|
4
4
|
// Run with: bun run scripts/preview-review.tsx (TUI) or --web (HTML upload).
|
|
5
5
|
|
|
6
|
-
import { createCliRenderer } from "@opentui/core"
|
|
6
|
+
import { createCliRenderer, addDefaultParsers } from "@opentui/core"
|
|
7
|
+
import parsersConfig from "../parsers-config.ts"
|
|
8
|
+
|
|
9
|
+
// Register custom syntax highlighting parsers
|
|
10
|
+
addDefaultParsers(parsersConfig.parsers)
|
|
7
11
|
import { createRoot } from "@opentui/react"
|
|
8
12
|
import * as React from "react"
|
|
9
13
|
import { ReviewApp, ReviewAppView } from "../src/review/review-app.tsx"
|
|
10
14
|
import { createHunk } from "../src/review/hunk-parser.ts"
|
|
11
15
|
import type { ReviewYaml } from "../src/review/types.ts"
|
|
12
|
-
import { captureReviewResponsiveHtml, uploadHtml } from "../src/web-utils.
|
|
16
|
+
import { captureReviewResponsiveHtml, uploadHtml } from "../src/web-utils.tsx"
|
|
13
17
|
import fs from "fs"
|
|
14
18
|
import { tmpdir } from "os"
|
|
15
19
|
import { join } from "path"
|
|
@@ -89,6 +93,35 @@ const exampleHunks = [
|
|
|
89
93
|
" })",
|
|
90
94
|
" })",
|
|
91
95
|
]),
|
|
96
|
+
// Rust example
|
|
97
|
+
createHunk(5, "src/lib.rs", 0, 1, 1, [
|
|
98
|
+
"+use std::collections::HashMap;",
|
|
99
|
+
"+use std::sync::Arc;",
|
|
100
|
+
"+",
|
|
101
|
+
"+#[derive(Debug, Clone)]",
|
|
102
|
+
"+pub struct User {",
|
|
103
|
+
"+ pub id: u64,",
|
|
104
|
+
"+ pub name: String,",
|
|
105
|
+
"+ pub email: Option<String>,",
|
|
106
|
+
"+}",
|
|
107
|
+
"+",
|
|
108
|
+
"+impl User {",
|
|
109
|
+
"+ pub fn new(id: u64, name: impl Into<String>) -> Self {",
|
|
110
|
+
"+ Self {",
|
|
111
|
+
"+ id,",
|
|
112
|
+
"+ name: name.into(),",
|
|
113
|
+
"+ email: None,",
|
|
114
|
+
"+ }",
|
|
115
|
+
"+ }",
|
|
116
|
+
"+",
|
|
117
|
+
"+ pub fn with_email(mut self, email: impl Into<String>) -> Self {",
|
|
118
|
+
"+ self.email = Some(email.into());",
|
|
119
|
+
"+ self",
|
|
120
|
+
"+ }",
|
|
121
|
+
"+}",
|
|
122
|
+
"+",
|
|
123
|
+
"+pub type UserCache = Arc<HashMap<u64, User>>;",
|
|
124
|
+
]),
|
|
92
125
|
]
|
|
93
126
|
|
|
94
127
|
// Rich review data with multiple sections
|
|
@@ -206,6 +239,23 @@ Added test case for the new error handling behavior, ensuring that:
|
|
|
206
239
|
|
|
207
240
|
All tests pass and coverage is at 95%.`,
|
|
208
241
|
},
|
|
242
|
+
{
|
|
243
|
+
hunkIds: [5],
|
|
244
|
+
markdownDescription: `## Rust User Model
|
|
245
|
+
|
|
246
|
+
Added a Rust implementation of the User model with:
|
|
247
|
+
|
|
248
|
+
- **Derive macros**: \`Debug\` and \`Clone\` for easy debugging and copying
|
|
249
|
+
- **Builder pattern**: Fluent API with \`with_email()\` method
|
|
250
|
+
- **Type alias**: \`UserCache\` for thread-safe shared storage
|
|
251
|
+
|
|
252
|
+
\`\`\`rust
|
|
253
|
+
let user = User::new(1, "Alice")
|
|
254
|
+
.with_email("alice@example.com");
|
|
255
|
+
\`\`\`
|
|
256
|
+
|
|
257
|
+
This provides a type-safe, zero-cost abstraction for user data.`,
|
|
258
|
+
},
|
|
209
259
|
],
|
|
210
260
|
}
|
|
211
261
|
|
package/src/ansi-html.ts
CHANGED
|
@@ -170,7 +170,10 @@ export function frameToHtmlDocument(frame: CapturedFrame, options: ToHtmlOptions
|
|
|
170
170
|
<html>
|
|
171
171
|
<head>
|
|
172
172
|
<meta charset="utf-8">
|
|
173
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"
|
|
173
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
174
|
+
<link rel="icon" href="/favicon-dark.png" media="(prefers-color-scheme: dark)">
|
|
175
|
+
<link rel="icon" href="/favicon-light.png" media="(prefers-color-scheme: light)">
|
|
176
|
+
<link rel="icon" href="/favicon-dark.png">${ogTags}
|
|
174
177
|
<style>
|
|
175
178
|
@font-face {
|
|
176
179
|
font-family: 'JetBrains Mono Nerd';
|
|
Binary file
|
|
Binary file
|
package/src/cli.tsx
CHANGED
|
@@ -21,7 +21,12 @@ import {
|
|
|
21
21
|
MacOSScrollAccel,
|
|
22
22
|
ScrollBoxRenderable,
|
|
23
23
|
BoxRenderable,
|
|
24
|
+
addDefaultParsers,
|
|
24
25
|
} from "@opentui/core";
|
|
26
|
+
import parsersConfig from "../parsers-config.ts";
|
|
27
|
+
|
|
28
|
+
// Register custom syntax highlighting parsers
|
|
29
|
+
addDefaultParsers(parsersConfig.parsers);
|
|
25
30
|
import fs from "fs";
|
|
26
31
|
import { tmpdir } from "os";
|
|
27
32
|
import { join } from "path";
|
package/src/diff-utils.test.ts
CHANGED
|
@@ -520,9 +520,11 @@ describe("buildGitCommand with rename detection", () => {
|
|
|
520
520
|
expect(cmd).toContain("-M")
|
|
521
521
|
})
|
|
522
522
|
|
|
523
|
-
it("should
|
|
523
|
+
it("should use git diff for single base (compare to working tree)", () => {
|
|
524
524
|
const cmd = buildGitCommand({ base: "HEAD~1" })
|
|
525
525
|
expect(cmd).toContain("-M")
|
|
526
|
+
expect(cmd).toStartWith("git diff HEAD~1")
|
|
527
|
+
expect(cmd).not.toContain("git show")
|
|
526
528
|
})
|
|
527
529
|
|
|
528
530
|
it("should include -M flag in three-dot range", () => {
|
package/src/diff-utils.ts
CHANGED
|
@@ -256,9 +256,9 @@ export function buildGitCommand(options: GitCommandOptions): string {
|
|
|
256
256
|
return `git diff ${rangeBase}..${rangeHead} --no-prefix ${renameArg} ${submoduleArg} ${contextArg} ${filterArg}`.trim();
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
|
-
// Single ref:
|
|
259
|
+
// Single ref: compare ref to working tree (like git diff)
|
|
260
260
|
if (options.base) {
|
|
261
|
-
return `git
|
|
261
|
+
return `git diff ${options.base} --no-prefix ${renameArg} ${submoduleArg} ${contextArg} ${filterArg}`.trim();
|
|
262
262
|
}
|
|
263
263
|
return `git add -N . && git diff --no-prefix ${renameArg} ${submoduleArg} ${contextArg} ${filterArg}`.trim();
|
|
264
264
|
}
|
|
@@ -406,7 +406,7 @@ export function processFiles<T extends ParsedFile>(
|
|
|
406
406
|
|
|
407
407
|
/**
|
|
408
408
|
* Detect filetype from filename for syntax highlighting
|
|
409
|
-
* Maps to tree-sitter parsers available in @opentui/core
|
|
409
|
+
* Maps to tree-sitter parsers available in @opentui/core and parsers-config.ts
|
|
410
410
|
*/
|
|
411
411
|
export function detectFiletype(filePath: string): string | undefined {
|
|
412
412
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
@@ -421,14 +421,73 @@ export function detectFiletype(filePath: string): string | undefined {
|
|
|
421
421
|
case "mts":
|
|
422
422
|
case "cts":
|
|
423
423
|
return "typescript";
|
|
424
|
-
// JSON uses JavaScript parser (JSON is valid JS)
|
|
425
424
|
case "json":
|
|
426
|
-
return "
|
|
425
|
+
return "json";
|
|
427
426
|
case "md":
|
|
428
427
|
case "mdx":
|
|
429
428
|
return "markdown";
|
|
430
429
|
case "zig":
|
|
431
430
|
return "zig";
|
|
431
|
+
// Languages from parsers-config.ts
|
|
432
|
+
case "py":
|
|
433
|
+
case "pyw":
|
|
434
|
+
case "pyi":
|
|
435
|
+
return "python";
|
|
436
|
+
case "rs":
|
|
437
|
+
return "rust";
|
|
438
|
+
case "go":
|
|
439
|
+
return "go";
|
|
440
|
+
case "cpp":
|
|
441
|
+
case "cc":
|
|
442
|
+
case "cxx":
|
|
443
|
+
case "hpp":
|
|
444
|
+
case "hxx":
|
|
445
|
+
case "h":
|
|
446
|
+
return "cpp";
|
|
447
|
+
case "cs":
|
|
448
|
+
return "csharp";
|
|
449
|
+
case "sh":
|
|
450
|
+
case "bash":
|
|
451
|
+
case "zsh":
|
|
452
|
+
return "bash";
|
|
453
|
+
case "c":
|
|
454
|
+
return "c";
|
|
455
|
+
case "java":
|
|
456
|
+
return "java";
|
|
457
|
+
case "rb":
|
|
458
|
+
case "rake":
|
|
459
|
+
case "gemspec":
|
|
460
|
+
return "ruby";
|
|
461
|
+
case "php":
|
|
462
|
+
return "php";
|
|
463
|
+
case "scala":
|
|
464
|
+
case "sc":
|
|
465
|
+
return "scala";
|
|
466
|
+
case "html":
|
|
467
|
+
case "htm":
|
|
468
|
+
return "html";
|
|
469
|
+
case "yaml":
|
|
470
|
+
case "yml":
|
|
471
|
+
return "yaml";
|
|
472
|
+
case "hs":
|
|
473
|
+
case "lhs":
|
|
474
|
+
return "haskell";
|
|
475
|
+
case "css":
|
|
476
|
+
return "css";
|
|
477
|
+
case "jl":
|
|
478
|
+
return "julia";
|
|
479
|
+
case "ml":
|
|
480
|
+
case "mli":
|
|
481
|
+
return "ocaml";
|
|
482
|
+
case "clj":
|
|
483
|
+
case "cljs":
|
|
484
|
+
case "cljc":
|
|
485
|
+
case "edn":
|
|
486
|
+
return "clojure";
|
|
487
|
+
case "swift":
|
|
488
|
+
return "swift";
|
|
489
|
+
case "nix":
|
|
490
|
+
return "nix";
|
|
432
491
|
default:
|
|
433
492
|
return undefined;
|
|
434
493
|
}
|
package/src/web-utils.tsx
CHANGED
|
@@ -109,7 +109,7 @@ function renderExpiryNotice(options: { textColor: string; mutedColor: string })
|
|
|
109
109
|
<box style={{ flexDirection: "column", paddingBottom: 1, paddingLeft: 1 }}>
|
|
110
110
|
<box style={{ flexDirection: "row" }}>
|
|
111
111
|
<text fg={options.textColor}>This page will expire in 7 days. </text>
|
|
112
|
-
<text fg={options.
|
|
112
|
+
<text fg={options.textColor}>Get unlimited links: </text>
|
|
113
113
|
<text fg={options.textColor}>{buyUrl}</text>
|
|
114
114
|
</box>
|
|
115
115
|
</box>
|
package/src/worker.tsx
CHANGED
|
@@ -33,6 +33,11 @@ const app = new Hono<{ Bindings: Bindings }>()
|
|
|
33
33
|
const SEVEN_DAYS = 60 * 60 * 24 * 7
|
|
34
34
|
const LICENSE_HEADER = "X-Critique-License"
|
|
35
35
|
const STRIPE_YEARLY_PRICE_ID = "price_1Su9CZBekrVyz93iMIEnjPOk"
|
|
36
|
+
|
|
37
|
+
// Favicon PNGs (32x32) - dark (white icon for dark bg) and light (black icon for light bg)
|
|
38
|
+
const FAVICON_DARK_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAA8ElEQVR4nO2WPwrCMBhHSxVBvIR4CsHFQXsGt6KjJyiouOosOLgI7s4OjtrjODv450lLSjPFtjZRbB/8hi9pksdHCrGskgQAV95zAQaWDkjOHRjpEOgAPUX6gC8knsA4d4l3AA3gKHVj+slmfoq236LDgDpwkOZmWQWysBBra8BeGl+aEpAlKsCOmDVgmxAImEsSW2JWpgRkCRvYhCPwMCkQMBF7dcMKyFNgKKLiplOgKaLk7wRcoCVSFYlqtxACMsW8A2l/Q60Cifg7AUfxvWNCwFM8yTwTAqn5FYG2KK9fEcgEpQCcc2jCKVv/rYLxAsud37oBTmHeAAAAAElFTkSuQmCC"
|
|
39
|
+
const FAVICON_LIGHT_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAA8klEQVR4nO2WPQrCQBCFP1QE8RLiKQQbC/UMdqKlJxBUbLUWLGwEe2sLS/U41hb+jAgjTJXE1WzE+ODB5mV38mWWhYW/oukESIiPQIuYJBF9AbpxAFSBeoAbwEEhbkCPBFQEtqYbw3eKHV5o+9l8rABszLuRK4A4eKJr88Da5FNfAGIgssDK5HMg4wNAgLGBWJp85gtADMTjrxeaXX0CCDDQWjWTfQygow47HbEBlNRh834LoA2U1Tn187mdCgBJegvkmwA6EY5hrAAS0b8F0AyY3/QB0A+4kvVTsQXiCFDR8SkpACdJ6gH2H+jAzq35pEx3Rh7HfgGTRuMAAAAASUVORK5CYII="
|
|
40
|
+
|
|
36
41
|
const logger = {
|
|
37
42
|
log: (...args: unknown[]) => {
|
|
38
43
|
console.error(...args)
|
|
@@ -47,6 +52,33 @@ app.get("/", (c) => {
|
|
|
47
52
|
return c.redirect("https://github.com/remorses/critique")
|
|
48
53
|
})
|
|
49
54
|
|
|
55
|
+
// Serve favicon - dark version (white icon for dark backgrounds)
|
|
56
|
+
app.get("/favicon-dark.png", (c) => {
|
|
57
|
+
const bytes = Uint8Array.from(atob(FAVICON_DARK_BASE64), (c) => c.charCodeAt(0))
|
|
58
|
+
return c.body(bytes, 200, {
|
|
59
|
+
"Content-Type": "image/png",
|
|
60
|
+
"Cache-Control": "public, max-age=604800",
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// Serve favicon - light version (black icon for light backgrounds)
|
|
65
|
+
app.get("/favicon-light.png", (c) => {
|
|
66
|
+
const bytes = Uint8Array.from(atob(FAVICON_LIGHT_BASE64), (c) => c.charCodeAt(0))
|
|
67
|
+
return c.body(bytes, 200, {
|
|
68
|
+
"Content-Type": "image/png",
|
|
69
|
+
"Cache-Control": "public, max-age=604800",
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Default favicon.ico - returns dark version
|
|
74
|
+
app.get("/favicon.ico", (c) => {
|
|
75
|
+
const bytes = Uint8Array.from(atob(FAVICON_DARK_BASE64), (c) => c.charCodeAt(0))
|
|
76
|
+
return c.body(bytes, 200, {
|
|
77
|
+
"Content-Type": "image/png",
|
|
78
|
+
"Cache-Control": "public, max-age=604800",
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
50
82
|
function requireEnv(value: string | undefined, name: string): string {
|
|
51
83
|
if (!value) {
|
|
52
84
|
throw new Error(`Missing env var ${name}`)
|
|
@@ -176,7 +208,7 @@ function generateLicenseKey(): string {
|
|
|
176
208
|
}
|
|
177
209
|
|
|
178
210
|
function buildLicenseCommand(licenseKey: string): string {
|
|
179
|
-
return `npx
|
|
211
|
+
return `npx critique login ${licenseKey}`
|
|
180
212
|
}
|
|
181
213
|
|
|
182
214
|
async function sendLicenseEmail(
|
|
@@ -201,7 +233,7 @@ async function sendLicenseEmail(
|
|
|
201
233
|
<div style="font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif; color: #0f172a;">
|
|
202
234
|
<p>Thanks for subscribing to Critique.</p>
|
|
203
235
|
<p>Run this on any machine where you want to use critique:</p>
|
|
204
|
-
<pre style="background: #0b1117; color: #e6edf3; padding: 12px 14px; border-radius: 8px; font-family:
|
|
236
|
+
<pre style="background: #0b1117; color: #e6edf3; padding: 12px 14px; border-radius: 8px; font-family: 'Courier New', Courier, monospace;">${command}</pre>
|
|
205
237
|
<p>This unlocks permanent critique links.</p>
|
|
206
238
|
</div>
|
|
207
239
|
`
|
package/tsconfig.json
CHANGED