11import { text } from "node:stream/consumers"
2+ import { Npm } from "@/npm"
23import { Instance } from "../project/instance"
34import { Filesystem } from "../util/filesystem"
45import { Process } from "../util/process"
@@ -7,33 +8,33 @@ import { Flag } from "@/flag/flag"
78
89export interface Info {
910 name : string
10- command : string [ ]
1111 environment ?: Record < string , string >
1212 extensions : string [ ]
13- enabled ( ) : Promise < boolean >
13+ enabled ( ) : Promise < string [ ] | false >
1414}
1515
1616export const gofmt : Info = {
1717 name : "gofmt" ,
18- command : [ "gofmt" , "-w" , "$FILE" ] ,
1918 extensions : [ ".go" ] ,
2019 async enabled ( ) {
21- return which ( "gofmt" ) !== null
20+ const match = which ( "gofmt" )
21+ if ( ! match ) return false
22+ return [ match , "-w" , "$FILE" ]
2223 } ,
2324}
2425
2526export const mix : Info = {
2627 name : "mix" ,
27- command : [ "mix" , "format" , "$FILE" ] ,
2828 extensions : [ ".ex" , ".exs" , ".eex" , ".heex" , ".leex" , ".neex" , ".sface" ] ,
2929 async enabled ( ) {
30- return which ( "mix" ) !== null
30+ const match = which ( "mix" )
31+ if ( ! match ) return false
32+ return [ match , "format" , "$FILE" ]
3133 } ,
3234}
3335
3436export const prettier : Info = {
3537 name : "prettier" ,
36- command : [ "bun" , "x" , "prettier" , "--write" , "$FILE" ] ,
3738 environment : {
3839 BUN_BE_BUN : "1" ,
3940 } ,
@@ -72,16 +73,17 @@ export const prettier: Info = {
7273 dependencies ?: Record < string , string >
7374 devDependencies ?: Record < string , string >
7475 } > ( item )
75- if ( json . dependencies ?. prettier ) return true
76- if ( json . devDependencies ?. prettier ) return true
76+ if ( json . dependencies ?. prettier || json . devDependencies ?. prettier ) {
77+ const bin = await Npm . which ( "prettier" )
78+ if ( bin ) return [ bin , "--write" , "$FILE" ]
79+ }
7780 }
7881 return false
7982 } ,
8083}
8184
8285export const oxfmt : Info = {
8386 name : "oxfmt" ,
84- command : [ "bun" , "x" , "oxfmt" , "$FILE" ] ,
8587 environment : {
8688 BUN_BE_BUN : "1" ,
8789 } ,
@@ -94,16 +96,17 @@ export const oxfmt: Info = {
9496 dependencies ?: Record < string , string >
9597 devDependencies ?: Record < string , string >
9698 } > ( item )
97- if ( json . dependencies ?. oxfmt ) return true
98- if ( json . devDependencies ?. oxfmt ) return true
99+ if ( json . dependencies ?. oxfmt || json . devDependencies ?. oxfmt ) {
100+ const bin = await Npm . which ( "oxfmt" )
101+ if ( bin ) return [ bin , "$FILE" ]
102+ }
99103 }
100104 return false
101105 } ,
102106}
103107
104108export const biome : Info = {
105109 name : "biome" ,
106- command : [ "bun" , "x" , "@biomejs/biome" , "check" , "--write" , "$FILE" ] ,
107110 environment : {
108111 BUN_BE_BUN : "1" ,
109112 } ,
@@ -140,7 +143,8 @@ export const biome: Info = {
140143 for ( const config of configs ) {
141144 const found = await Filesystem . findUp ( config , Instance . directory , Instance . worktree )
142145 if ( found . length > 0 ) {
143- return true
146+ const bin = await Npm . which ( "@biomejs/biome" )
147+ if ( bin ) return [ bin , "check" , "--write" , "$FILE" ]
144148 }
145149 }
146150 return false
@@ -149,35 +153,39 @@ export const biome: Info = {
149153
150154export const zig : Info = {
151155 name : "zig" ,
152- command : [ "zig" , "fmt" , "$FILE" ] ,
153156 extensions : [ ".zig" , ".zon" ] ,
154157 async enabled ( ) {
155- return which ( "zig" ) !== null
158+ const match = which ( "zig" )
159+ if ( ! match ) return false
160+ return [ match , "fmt" , "$FILE" ]
156161 } ,
157162}
158163
159164export const clang : Info = {
160165 name : "clang-format" ,
161- command : [ "clang-format" , "-i" , "$FILE" ] ,
162166 extensions : [ ".c" , ".cc" , ".cpp" , ".cxx" , ".c++" , ".h" , ".hh" , ".hpp" , ".hxx" , ".h++" , ".ino" , ".C" , ".H" ] ,
163167 async enabled ( ) {
164168 const items = await Filesystem . findUp ( ".clang-format" , Instance . directory , Instance . worktree )
165- return items . length > 0
169+ if ( items . length > 0 ) {
170+ const match = which ( "clang-format" )
171+ if ( match ) return [ match , "-i" , "$FILE" ]
172+ }
173+ return false
166174 } ,
167175}
168176
169177export const ktlint : Info = {
170178 name : "ktlint" ,
171- command : [ "ktlint" , "-F" , "$FILE" ] ,
172179 extensions : [ ".kt" , ".kts" ] ,
173180 async enabled ( ) {
174- return which ( "ktlint" ) !== null
181+ const match = which ( "ktlint" )
182+ if ( ! match ) return false
183+ return [ match , "-F" , "$FILE" ]
175184 } ,
176185}
177186
178187export const ruff : Info = {
179188 name : "ruff" ,
180- command : [ "ruff" , "format" , "$FILE" ] ,
181189 extensions : [ ".py" , ".pyi" ] ,
182190 async enabled ( ) {
183191 if ( ! which ( "ruff" ) ) return false
@@ -187,9 +195,9 @@ export const ruff: Info = {
187195 if ( found . length > 0 ) {
188196 if ( config === "pyproject.toml" ) {
189197 const content = await Filesystem . readText ( found [ 0 ] )
190- if ( content . includes ( "[tool.ruff]" ) ) return true
198+ if ( content . includes ( "[tool.ruff]" ) ) return [ "ruff" , "format" , "$FILE" ]
191199 } else {
192- return true
200+ return [ "ruff" , "format" , "$FILE" ]
193201 }
194202 }
195203 }
@@ -198,7 +206,7 @@ export const ruff: Info = {
198206 const found = await Filesystem . findUp ( dep , Instance . directory , Instance . worktree )
199207 if ( found . length > 0 ) {
200208 const content = await Filesystem . readText ( found [ 0 ] )
201- if ( content . includes ( "ruff" ) ) return true
209+ if ( content . includes ( "ruff" ) ) return [ "ruff" , "format" , "$FILE" ]
202210 }
203211 }
204212 return false
@@ -207,7 +215,6 @@ export const ruff: Info = {
207215
208216export const rlang : Info = {
209217 name : "air" ,
210- command : [ "air" , "format" , "$FILE" ] ,
211218 extensions : [ ".R" ] ,
212219 async enabled ( ) {
213220 const airPath = which ( "air" )
@@ -226,132 +233,141 @@ export const rlang: Info = {
226233 const firstLine = output . split ( "\n" ) [ 0 ]
227234 const hasR = firstLine . includes ( "R language" )
228235 const hasFormatter = firstLine . includes ( "formatter" )
229- return hasR && hasFormatter
230- } catch ( error ) {
236+ if ( hasR && hasFormatter ) return [ "air" , "format" , "$FILE" ]
237+ } catch {
231238 return false
232239 }
240+ return false
233241 } ,
234242}
235243
236244export const uvformat : Info = {
237245 name : "uv" ,
238- command : [ "uv" , "format" , "--" , "$FILE" ] ,
239246 extensions : [ ".py" , ".pyi" ] ,
240247 async enabled ( ) {
241248 if ( await ruff . enabled ( ) ) return false
242249 if ( which ( "uv" ) !== null ) {
243250 const proc = Process . spawn ( [ "uv" , "format" , "--help" ] , { stderr : "pipe" , stdout : "pipe" } )
244251 const code = await proc . exited
245- return code === 0
252+ if ( code === 0 ) return [ "uv" , "format" , "--" , "$FILE" ]
246253 }
247254 return false
248255 } ,
249256}
250257
251258export const rubocop : Info = {
252259 name : "rubocop" ,
253- command : [ "rubocop" , "--autocorrect" , "$FILE" ] ,
254260 extensions : [ ".rb" , ".rake" , ".gemspec" , ".ru" ] ,
255261 async enabled ( ) {
256- return which ( "rubocop" ) !== null
262+ const match = which ( "rubocop" )
263+ if ( ! match ) return false
264+ return [ match , "--autocorrect" , "$FILE" ]
257265 } ,
258266}
259267
260268export const standardrb : Info = {
261269 name : "standardrb" ,
262- command : [ "standardrb" , "--fix" , "$FILE" ] ,
263270 extensions : [ ".rb" , ".rake" , ".gemspec" , ".ru" ] ,
264271 async enabled ( ) {
265- return which ( "standardrb" ) !== null
272+ const match = which ( "standardrb" )
273+ if ( ! match ) return false
274+ return [ match , "--fix" , "$FILE" ]
266275 } ,
267276}
268277
269278export const htmlbeautifier : Info = {
270279 name : "htmlbeautifier" ,
271- command : [ "htmlbeautifier" , "$FILE" ] ,
272280 extensions : [ ".erb" , ".html.erb" ] ,
273281 async enabled ( ) {
274- return which ( "htmlbeautifier" ) !== null
282+ const match = which ( "htmlbeautifier" )
283+ if ( ! match ) return false
284+ return [ match , "$FILE" ]
275285 } ,
276286}
277287
278288export const dart : Info = {
279289 name : "dart" ,
280- command : [ "dart" , "format" , "$FILE" ] ,
281290 extensions : [ ".dart" ] ,
282291 async enabled ( ) {
283- return which ( "dart" ) !== null
292+ const match = which ( "dart" )
293+ if ( ! match ) return false
294+ return [ match , "format" , "$FILE" ]
284295 } ,
285296}
286297
287298export const ocamlformat : Info = {
288299 name : "ocamlformat" ,
289- command : [ "ocamlformat" , "-i" , "$FILE" ] ,
290300 extensions : [ ".ml" , ".mli" ] ,
291301 async enabled ( ) {
292302 if ( ! which ( "ocamlformat" ) ) return false
293303 const items = await Filesystem . findUp ( ".ocamlformat" , Instance . directory , Instance . worktree )
294- return items . length > 0
304+ if ( items . length > 0 ) return [ "ocamlformat" , "-i" , "$FILE" ]
305+ return false
295306 } ,
296307}
297308
298309export const terraform : Info = {
299310 name : "terraform" ,
300- command : [ "terraform" , "fmt" , "$FILE" ] ,
301311 extensions : [ ".tf" , ".tfvars" ] ,
302312 async enabled ( ) {
303- return which ( "terraform" ) !== null
313+ const match = which ( "terraform" )
314+ if ( ! match ) return false
315+ return [ match , "fmt" , "$FILE" ]
304316 } ,
305317}
306318
307319export const latexindent : Info = {
308320 name : "latexindent" ,
309- command : [ "latexindent" , "-w" , "-s" , "$FILE" ] ,
310321 extensions : [ ".tex" ] ,
311322 async enabled ( ) {
312- return which ( "latexindent" ) !== null
323+ const match = which ( "latexindent" )
324+ if ( ! match ) return false
325+ return [ match , "-w" , "-s" , "$FILE" ]
313326 } ,
314327}
315328
316329export const gleam : Info = {
317330 name : "gleam" ,
318- command : [ "gleam" , "format" , "$FILE" ] ,
319331 extensions : [ ".gleam" ] ,
320332 async enabled ( ) {
321- return which ( "gleam" ) !== null
333+ const match = which ( "gleam" )
334+ if ( ! match ) return false
335+ return [ match , "format" , "$FILE" ]
322336 } ,
323337}
324338
325339export const shfmt : Info = {
326340 name : "shfmt" ,
327- command : [ "shfmt" , "-w" , "$FILE" ] ,
328341 extensions : [ ".sh" , ".bash" ] ,
329342 async enabled ( ) {
330- return which ( "shfmt" ) !== null
343+ const match = which ( "shfmt" )
344+ if ( ! match ) return false
345+ return [ match , "-w" , "$FILE" ]
331346 } ,
332347}
333348
334349export const nixfmt : Info = {
335350 name : "nixfmt" ,
336- command : [ "nixfmt" , "$FILE" ] ,
337351 extensions : [ ".nix" ] ,
338352 async enabled ( ) {
339- return which ( "nixfmt" ) !== null
353+ const match = which ( "nixfmt" )
354+ if ( ! match ) return false
355+ return [ match , "$FILE" ]
340356 } ,
341357}
342358
343359export const rustfmt : Info = {
344360 name : "rustfmt" ,
345- command : [ "rustfmt" , "$FILE" ] ,
346361 extensions : [ ".rs" ] ,
347362 async enabled ( ) {
348- return which ( "rustfmt" ) !== null
363+ const match = which ( "rustfmt" )
364+ if ( ! match ) return false
365+ return [ match , "$FILE" ]
349366 } ,
350367}
351368
352369export const pint : Info = {
353370 name : "pint" ,
354- command : [ "./vendor/bin/pint" , "$FILE" ] ,
355371 extensions : [ ".php" ] ,
356372 async enabled ( ) {
357373 const items = await Filesystem . findUp ( "composer.json" , Instance . directory , Instance . worktree )
@@ -360,36 +376,38 @@ export const pint: Info = {
360376 require ?: Record < string , string >
361377 "require-dev" ?: Record < string , string >
362378 } > ( item )
363- if ( json . require ?. [ "laravel/pint" ] ) return true
364- if ( json [ "require-dev" ] ?. [ "laravel/pint" ] ) return true
379+ if ( json . require ?. [ "laravel/pint" ] || json [ "require-dev" ] ?. [ "laravel/pint" ] ) return [ "./vendor/bin/pint" , "$FILE" ]
365380 }
366381 return false
367382 } ,
368383}
369384
370385export const ormolu : Info = {
371386 name : "ormolu" ,
372- command : [ "ormolu" , "-i" , "$FILE" ] ,
373387 extensions : [ ".hs" ] ,
374388 async enabled ( ) {
375- return which ( "ormolu" ) !== null
389+ const match = which ( "ormolu" )
390+ if ( ! match ) return false
391+ return [ match , "-i" , "$FILE" ]
376392 } ,
377393}
378394
379395export const cljfmt : Info = {
380396 name : "cljfmt" ,
381- command : [ "cljfmt" , "fix" , "--quiet" , "$FILE" ] ,
382397 extensions : [ ".clj" , ".cljs" , ".cljc" , ".edn" ] ,
383398 async enabled ( ) {
384- return which ( "cljfmt" ) !== null
399+ const match = which ( "cljfmt" )
400+ if ( ! match ) return false
401+ return [ match , "fix" , "--quiet" , "$FILE" ]
385402 } ,
386403}
387404
388405export const dfmt : Info = {
389406 name : "dfmt" ,
390- command : [ "dfmt" , "-i" , "$FILE" ] ,
391407 extensions : [ ".d" ] ,
392408 async enabled ( ) {
393- return which ( "dfmt" ) !== null
409+ const match = which ( "dfmt" )
410+ if ( ! match ) return false
411+ return [ match , "-i" , "$FILE" ]
394412 } ,
395413}
0 commit comments