practicode 0.1.6 → 0.1.7
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/Cargo.lock +241 -152
- package/Cargo.toml +2 -2
- package/README.md +49 -11
- package/assets/i18n/en.json +1 -0
- package/assets/i18n/es.json +1 -0
- package/assets/i18n/ja.json +1 -0
- package/assets/i18n/ko.json +1 -0
- package/assets/i18n/zh.json +1 -0
- package/package.json +1 -1
- package/src/lib.rs +44 -1
- package/src/tui/commands.rs +7 -0
- package/src/tui.rs +38 -26
package/Cargo.lock
CHANGED
|
@@ -14,6 +14,21 @@ version = "1.0.103"
|
|
|
14
14
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
15
|
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
|
|
16
16
|
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "approx"
|
|
19
|
+
version = "0.5.1"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"num-traits",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "autocfg"
|
|
28
|
+
version = "1.5.1"
|
|
29
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
30
|
+
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|
31
|
+
|
|
17
32
|
[[package]]
|
|
18
33
|
name = "bitflags"
|
|
19
34
|
version = "2.13.0"
|
|
@@ -21,10 +36,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
21
36
|
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
|
22
37
|
|
|
23
38
|
[[package]]
|
|
24
|
-
name = "
|
|
25
|
-
version = "
|
|
39
|
+
name = "by_address"
|
|
40
|
+
version = "1.2.1"
|
|
26
41
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
|
-
checksum = "
|
|
42
|
+
checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
|
|
28
43
|
|
|
29
44
|
[[package]]
|
|
30
45
|
name = "castaway"
|
|
@@ -43,9 +58,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
|
43
58
|
|
|
44
59
|
[[package]]
|
|
45
60
|
name = "compact_str"
|
|
46
|
-
version = "0.
|
|
61
|
+
version = "0.9.1"
|
|
47
62
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
-
checksum = "
|
|
63
|
+
checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab"
|
|
49
64
|
dependencies = [
|
|
50
65
|
"castaway",
|
|
51
66
|
"cfg-if",
|
|
@@ -64,22 +79,6 @@ dependencies = [
|
|
|
64
79
|
"unicode-segmentation",
|
|
65
80
|
]
|
|
66
81
|
|
|
67
|
-
[[package]]
|
|
68
|
-
name = "crossterm"
|
|
69
|
-
version = "0.28.1"
|
|
70
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
71
|
-
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
|
72
|
-
dependencies = [
|
|
73
|
-
"bitflags",
|
|
74
|
-
"crossterm_winapi",
|
|
75
|
-
"mio",
|
|
76
|
-
"parking_lot",
|
|
77
|
-
"rustix 0.38.44",
|
|
78
|
-
"signal-hook",
|
|
79
|
-
"signal-hook-mio",
|
|
80
|
-
"winapi",
|
|
81
|
-
]
|
|
82
|
-
|
|
83
82
|
[[package]]
|
|
84
83
|
name = "crossterm"
|
|
85
84
|
version = "0.29.0"
|
|
@@ -92,7 +91,7 @@ dependencies = [
|
|
|
92
91
|
"document-features",
|
|
93
92
|
"mio",
|
|
94
93
|
"parking_lot",
|
|
95
|
-
"rustix
|
|
94
|
+
"rustix",
|
|
96
95
|
"signal-hook",
|
|
97
96
|
"signal-hook-mio",
|
|
98
97
|
"winapi",
|
|
@@ -141,6 +140,12 @@ dependencies = [
|
|
|
141
140
|
"syn",
|
|
142
141
|
]
|
|
143
142
|
|
|
143
|
+
[[package]]
|
|
144
|
+
name = "deranged"
|
|
145
|
+
version = "0.5.8"
|
|
146
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
147
|
+
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
148
|
+
|
|
144
149
|
[[package]]
|
|
145
150
|
name = "derive_more"
|
|
146
151
|
version = "2.1.1"
|
|
@@ -191,20 +196,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
191
196
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
|
192
197
|
dependencies = [
|
|
193
198
|
"libc",
|
|
194
|
-
"windows-sys
|
|
199
|
+
"windows-sys",
|
|
195
200
|
]
|
|
196
201
|
|
|
202
|
+
[[package]]
|
|
203
|
+
name = "fast-srgb8"
|
|
204
|
+
version = "1.0.0"
|
|
205
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
206
|
+
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
|
|
207
|
+
|
|
197
208
|
[[package]]
|
|
198
209
|
name = "foldhash"
|
|
199
|
-
version = "0.
|
|
210
|
+
version = "0.2.0"
|
|
200
211
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
201
|
-
checksum = "
|
|
212
|
+
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
|
202
213
|
|
|
203
214
|
[[package]]
|
|
204
215
|
name = "hashbrown"
|
|
205
|
-
version = "0.
|
|
216
|
+
version = "0.16.1"
|
|
206
217
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
207
|
-
checksum = "
|
|
218
|
+
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
|
219
|
+
dependencies = [
|
|
220
|
+
"allocator-api2",
|
|
221
|
+
"equivalent",
|
|
222
|
+
"foldhash",
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
[[package]]
|
|
226
|
+
name = "hashbrown"
|
|
227
|
+
version = "0.17.1"
|
|
228
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
229
|
+
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
|
208
230
|
dependencies = [
|
|
209
231
|
"allocator-api2",
|
|
210
232
|
"equivalent",
|
|
@@ -247,9 +269,9 @@ dependencies = [
|
|
|
247
269
|
|
|
248
270
|
[[package]]
|
|
249
271
|
name = "itertools"
|
|
250
|
-
version = "0.
|
|
272
|
+
version = "0.14.0"
|
|
251
273
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
252
|
-
checksum = "
|
|
274
|
+
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
|
253
275
|
dependencies = [
|
|
254
276
|
"either",
|
|
255
277
|
]
|
|
@@ -260,6 +282,17 @@ version = "1.0.18"
|
|
|
260
282
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
261
283
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
262
284
|
|
|
285
|
+
[[package]]
|
|
286
|
+
name = "kasuari"
|
|
287
|
+
version = "0.4.12"
|
|
288
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
289
|
+
checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899"
|
|
290
|
+
dependencies = [
|
|
291
|
+
"hashbrown 0.16.1",
|
|
292
|
+
"portable-atomic",
|
|
293
|
+
"thiserror",
|
|
294
|
+
]
|
|
295
|
+
|
|
263
296
|
[[package]]
|
|
264
297
|
name = "libc"
|
|
265
298
|
version = "0.2.186"
|
|
@@ -267,10 +300,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
267
300
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
268
301
|
|
|
269
302
|
[[package]]
|
|
270
|
-
name = "
|
|
271
|
-
version = "0.
|
|
303
|
+
name = "libm"
|
|
304
|
+
version = "0.2.16"
|
|
305
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
306
|
+
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
|
307
|
+
|
|
308
|
+
[[package]]
|
|
309
|
+
name = "line-clipping"
|
|
310
|
+
version = "0.3.7"
|
|
272
311
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
273
|
-
checksum = "
|
|
312
|
+
checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8"
|
|
313
|
+
dependencies = [
|
|
314
|
+
"bitflags",
|
|
315
|
+
]
|
|
274
316
|
|
|
275
317
|
[[package]]
|
|
276
318
|
name = "linux-raw-sys"
|
|
@@ -301,11 +343,11 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
|
|
301
343
|
|
|
302
344
|
[[package]]
|
|
303
345
|
name = "lru"
|
|
304
|
-
version = "0.
|
|
346
|
+
version = "0.18.0"
|
|
305
347
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
306
|
-
checksum = "
|
|
348
|
+
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
|
|
307
349
|
dependencies = [
|
|
308
|
-
"hashbrown",
|
|
350
|
+
"hashbrown 0.17.1",
|
|
309
351
|
]
|
|
310
352
|
|
|
311
353
|
[[package]]
|
|
@@ -323,7 +365,55 @@ dependencies = [
|
|
|
323
365
|
"libc",
|
|
324
366
|
"log",
|
|
325
367
|
"wasi",
|
|
326
|
-
"windows-sys
|
|
368
|
+
"windows-sys",
|
|
369
|
+
]
|
|
370
|
+
|
|
371
|
+
[[package]]
|
|
372
|
+
name = "num-conv"
|
|
373
|
+
version = "0.2.2"
|
|
374
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
375
|
+
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
|
376
|
+
|
|
377
|
+
[[package]]
|
|
378
|
+
name = "num-traits"
|
|
379
|
+
version = "0.2.19"
|
|
380
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
381
|
+
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
382
|
+
dependencies = [
|
|
383
|
+
"autocfg",
|
|
384
|
+
]
|
|
385
|
+
|
|
386
|
+
[[package]]
|
|
387
|
+
name = "num_threads"
|
|
388
|
+
version = "0.1.7"
|
|
389
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
390
|
+
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
|
391
|
+
dependencies = [
|
|
392
|
+
"libc",
|
|
393
|
+
]
|
|
394
|
+
|
|
395
|
+
[[package]]
|
|
396
|
+
name = "palette"
|
|
397
|
+
version = "0.7.6"
|
|
398
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
399
|
+
checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
|
|
400
|
+
dependencies = [
|
|
401
|
+
"approx",
|
|
402
|
+
"fast-srgb8",
|
|
403
|
+
"libm",
|
|
404
|
+
"palette_derive",
|
|
405
|
+
]
|
|
406
|
+
|
|
407
|
+
[[package]]
|
|
408
|
+
name = "palette_derive"
|
|
409
|
+
version = "0.7.6"
|
|
410
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
411
|
+
checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
|
|
412
|
+
dependencies = [
|
|
413
|
+
"by_address",
|
|
414
|
+
"proc-macro2",
|
|
415
|
+
"quote",
|
|
416
|
+
"syn",
|
|
327
417
|
]
|
|
328
418
|
|
|
329
419
|
[[package]]
|
|
@@ -350,21 +440,27 @@ dependencies = [
|
|
|
350
440
|
]
|
|
351
441
|
|
|
352
442
|
[[package]]
|
|
353
|
-
name = "
|
|
354
|
-
version = "1.
|
|
443
|
+
name = "portable-atomic"
|
|
444
|
+
version = "1.13.1"
|
|
355
445
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
356
|
-
checksum = "
|
|
446
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
447
|
+
|
|
448
|
+
[[package]]
|
|
449
|
+
name = "powerfmt"
|
|
450
|
+
version = "0.2.0"
|
|
451
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
452
|
+
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
|
357
453
|
|
|
358
454
|
[[package]]
|
|
359
455
|
name = "practicode"
|
|
360
|
-
version = "0.1.
|
|
456
|
+
version = "0.1.7"
|
|
361
457
|
dependencies = [
|
|
362
458
|
"anyhow",
|
|
363
|
-
"crossterm
|
|
459
|
+
"crossterm",
|
|
364
460
|
"ratatui",
|
|
365
461
|
"serde",
|
|
366
462
|
"serde_json",
|
|
367
|
-
"unicode-width
|
|
463
|
+
"unicode-width",
|
|
368
464
|
"wait-timeout",
|
|
369
465
|
]
|
|
370
466
|
|
|
@@ -388,23 +484,68 @@ dependencies = [
|
|
|
388
484
|
|
|
389
485
|
[[package]]
|
|
390
486
|
name = "ratatui"
|
|
391
|
-
version = "0.
|
|
487
|
+
version = "0.30.2"
|
|
392
488
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
393
|
-
checksum = "
|
|
489
|
+
checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d"
|
|
490
|
+
dependencies = [
|
|
491
|
+
"instability",
|
|
492
|
+
"ratatui-core",
|
|
493
|
+
"ratatui-crossterm",
|
|
494
|
+
"ratatui-widgets",
|
|
495
|
+
"serde",
|
|
496
|
+
]
|
|
497
|
+
|
|
498
|
+
[[package]]
|
|
499
|
+
name = "ratatui-core"
|
|
500
|
+
version = "0.1.2"
|
|
501
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
502
|
+
checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c"
|
|
394
503
|
dependencies = [
|
|
395
504
|
"bitflags",
|
|
396
|
-
"cassowary",
|
|
397
505
|
"compact_str",
|
|
398
|
-
"
|
|
399
|
-
"indoc",
|
|
400
|
-
"instability",
|
|
506
|
+
"hashbrown 0.17.1",
|
|
401
507
|
"itertools",
|
|
508
|
+
"kasuari",
|
|
402
509
|
"lru",
|
|
403
|
-
"
|
|
510
|
+
"palette",
|
|
511
|
+
"serde",
|
|
404
512
|
"strum",
|
|
513
|
+
"thiserror",
|
|
405
514
|
"unicode-segmentation",
|
|
406
515
|
"unicode-truncate",
|
|
407
|
-
"unicode-width
|
|
516
|
+
"unicode-width",
|
|
517
|
+
]
|
|
518
|
+
|
|
519
|
+
[[package]]
|
|
520
|
+
name = "ratatui-crossterm"
|
|
521
|
+
version = "0.1.2"
|
|
522
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
523
|
+
checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0"
|
|
524
|
+
dependencies = [
|
|
525
|
+
"cfg-if",
|
|
526
|
+
"crossterm",
|
|
527
|
+
"instability",
|
|
528
|
+
"ratatui-core",
|
|
529
|
+
]
|
|
530
|
+
|
|
531
|
+
[[package]]
|
|
532
|
+
name = "ratatui-widgets"
|
|
533
|
+
version = "0.3.2"
|
|
534
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
535
|
+
checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1"
|
|
536
|
+
dependencies = [
|
|
537
|
+
"bitflags",
|
|
538
|
+
"hashbrown 0.17.1",
|
|
539
|
+
"indoc",
|
|
540
|
+
"instability",
|
|
541
|
+
"itertools",
|
|
542
|
+
"line-clipping",
|
|
543
|
+
"ratatui-core",
|
|
544
|
+
"serde",
|
|
545
|
+
"strum",
|
|
546
|
+
"time",
|
|
547
|
+
"unicode-segmentation",
|
|
548
|
+
"unicode-width",
|
|
408
549
|
]
|
|
409
550
|
|
|
410
551
|
[[package]]
|
|
@@ -425,19 +566,6 @@ dependencies = [
|
|
|
425
566
|
"semver",
|
|
426
567
|
]
|
|
427
568
|
|
|
428
|
-
[[package]]
|
|
429
|
-
name = "rustix"
|
|
430
|
-
version = "0.38.44"
|
|
431
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
432
|
-
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
|
433
|
-
dependencies = [
|
|
434
|
-
"bitflags",
|
|
435
|
-
"errno",
|
|
436
|
-
"libc",
|
|
437
|
-
"linux-raw-sys 0.4.15",
|
|
438
|
-
"windows-sys 0.59.0",
|
|
439
|
-
]
|
|
440
|
-
|
|
441
569
|
[[package]]
|
|
442
570
|
name = "rustix"
|
|
443
571
|
version = "1.1.4"
|
|
@@ -447,8 +575,8 @@ dependencies = [
|
|
|
447
575
|
"bitflags",
|
|
448
576
|
"errno",
|
|
449
577
|
"libc",
|
|
450
|
-
"linux-raw-sys
|
|
451
|
-
"windows-sys
|
|
578
|
+
"linux-raw-sys",
|
|
579
|
+
"windows-sys",
|
|
452
580
|
]
|
|
453
581
|
|
|
454
582
|
[[package]]
|
|
@@ -569,23 +697,22 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|
|
569
697
|
|
|
570
698
|
[[package]]
|
|
571
699
|
name = "strum"
|
|
572
|
-
version = "0.
|
|
700
|
+
version = "0.28.0"
|
|
573
701
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
574
|
-
checksum = "
|
|
702
|
+
checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
|
|
575
703
|
dependencies = [
|
|
576
704
|
"strum_macros",
|
|
577
705
|
]
|
|
578
706
|
|
|
579
707
|
[[package]]
|
|
580
708
|
name = "strum_macros"
|
|
581
|
-
version = "0.
|
|
709
|
+
version = "0.28.0"
|
|
582
710
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
583
|
-
checksum = "
|
|
711
|
+
checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
|
|
584
712
|
dependencies = [
|
|
585
713
|
"heck",
|
|
586
714
|
"proc-macro2",
|
|
587
715
|
"quote",
|
|
588
|
-
"rustversion",
|
|
589
716
|
"syn",
|
|
590
717
|
]
|
|
591
718
|
|
|
@@ -600,6 +727,47 @@ dependencies = [
|
|
|
600
727
|
"unicode-ident",
|
|
601
728
|
]
|
|
602
729
|
|
|
730
|
+
[[package]]
|
|
731
|
+
name = "thiserror"
|
|
732
|
+
version = "2.0.18"
|
|
733
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
734
|
+
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
|
735
|
+
dependencies = [
|
|
736
|
+
"thiserror-impl",
|
|
737
|
+
]
|
|
738
|
+
|
|
739
|
+
[[package]]
|
|
740
|
+
name = "thiserror-impl"
|
|
741
|
+
version = "2.0.18"
|
|
742
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
743
|
+
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|
744
|
+
dependencies = [
|
|
745
|
+
"proc-macro2",
|
|
746
|
+
"quote",
|
|
747
|
+
"syn",
|
|
748
|
+
]
|
|
749
|
+
|
|
750
|
+
[[package]]
|
|
751
|
+
name = "time"
|
|
752
|
+
version = "0.3.53"
|
|
753
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
754
|
+
checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
|
|
755
|
+
dependencies = [
|
|
756
|
+
"deranged",
|
|
757
|
+
"libc",
|
|
758
|
+
"num-conv",
|
|
759
|
+
"num_threads",
|
|
760
|
+
"powerfmt",
|
|
761
|
+
"serde_core",
|
|
762
|
+
"time-core",
|
|
763
|
+
]
|
|
764
|
+
|
|
765
|
+
[[package]]
|
|
766
|
+
name = "time-core"
|
|
767
|
+
version = "0.1.9"
|
|
768
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
769
|
+
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
|
770
|
+
|
|
603
771
|
[[package]]
|
|
604
772
|
name = "unicode-ident"
|
|
605
773
|
version = "1.0.24"
|
|
@@ -614,21 +782,15 @@ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
|
|
614
782
|
|
|
615
783
|
[[package]]
|
|
616
784
|
name = "unicode-truncate"
|
|
617
|
-
version = "
|
|
785
|
+
version = "2.0.1"
|
|
618
786
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
619
|
-
checksum = "
|
|
787
|
+
checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5"
|
|
620
788
|
dependencies = [
|
|
621
789
|
"itertools",
|
|
622
790
|
"unicode-segmentation",
|
|
623
|
-
"unicode-width
|
|
791
|
+
"unicode-width",
|
|
624
792
|
]
|
|
625
793
|
|
|
626
|
-
[[package]]
|
|
627
|
-
name = "unicode-width"
|
|
628
|
-
version = "0.1.14"
|
|
629
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
630
|
-
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
|
631
|
-
|
|
632
794
|
[[package]]
|
|
633
795
|
name = "unicode-width"
|
|
634
796
|
version = "0.2.0"
|
|
@@ -678,15 +840,6 @@ version = "0.2.1"
|
|
|
678
840
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
679
841
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
680
842
|
|
|
681
|
-
[[package]]
|
|
682
|
-
name = "windows-sys"
|
|
683
|
-
version = "0.59.0"
|
|
684
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
685
|
-
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
|
686
|
-
dependencies = [
|
|
687
|
-
"windows-targets",
|
|
688
|
-
]
|
|
689
|
-
|
|
690
843
|
[[package]]
|
|
691
844
|
name = "windows-sys"
|
|
692
845
|
version = "0.61.2"
|
|
@@ -696,70 +849,6 @@ dependencies = [
|
|
|
696
849
|
"windows-link",
|
|
697
850
|
]
|
|
698
851
|
|
|
699
|
-
[[package]]
|
|
700
|
-
name = "windows-targets"
|
|
701
|
-
version = "0.52.6"
|
|
702
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
703
|
-
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
|
704
|
-
dependencies = [
|
|
705
|
-
"windows_aarch64_gnullvm",
|
|
706
|
-
"windows_aarch64_msvc",
|
|
707
|
-
"windows_i686_gnu",
|
|
708
|
-
"windows_i686_gnullvm",
|
|
709
|
-
"windows_i686_msvc",
|
|
710
|
-
"windows_x86_64_gnu",
|
|
711
|
-
"windows_x86_64_gnullvm",
|
|
712
|
-
"windows_x86_64_msvc",
|
|
713
|
-
]
|
|
714
|
-
|
|
715
|
-
[[package]]
|
|
716
|
-
name = "windows_aarch64_gnullvm"
|
|
717
|
-
version = "0.52.6"
|
|
718
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
719
|
-
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
|
720
|
-
|
|
721
|
-
[[package]]
|
|
722
|
-
name = "windows_aarch64_msvc"
|
|
723
|
-
version = "0.52.6"
|
|
724
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
725
|
-
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
|
726
|
-
|
|
727
|
-
[[package]]
|
|
728
|
-
name = "windows_i686_gnu"
|
|
729
|
-
version = "0.52.6"
|
|
730
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
731
|
-
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
|
732
|
-
|
|
733
|
-
[[package]]
|
|
734
|
-
name = "windows_i686_gnullvm"
|
|
735
|
-
version = "0.52.6"
|
|
736
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
737
|
-
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
|
738
|
-
|
|
739
|
-
[[package]]
|
|
740
|
-
name = "windows_i686_msvc"
|
|
741
|
-
version = "0.52.6"
|
|
742
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
743
|
-
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
|
744
|
-
|
|
745
|
-
[[package]]
|
|
746
|
-
name = "windows_x86_64_gnu"
|
|
747
|
-
version = "0.52.6"
|
|
748
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
749
|
-
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
|
750
|
-
|
|
751
|
-
[[package]]
|
|
752
|
-
name = "windows_x86_64_gnullvm"
|
|
753
|
-
version = "0.52.6"
|
|
754
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
755
|
-
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
|
756
|
-
|
|
757
|
-
[[package]]
|
|
758
|
-
name = "windows_x86_64_msvc"
|
|
759
|
-
version = "0.52.6"
|
|
760
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
761
|
-
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|
762
|
-
|
|
763
852
|
[[package]]
|
|
764
853
|
name = "zmij"
|
|
765
854
|
version = "1.0.21"
|
package/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "practicode"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.7"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
description = "Local-first coding-test practice in a Rust terminal UI with optional AI help."
|
|
6
6
|
readme = "README.md"
|
|
@@ -13,7 +13,7 @@ categories = ["command-line-utilities", "development-tools", "text-editors"]
|
|
|
13
13
|
[dependencies]
|
|
14
14
|
anyhow = "1"
|
|
15
15
|
crossterm = "0.29"
|
|
16
|
-
ratatui = "0.
|
|
16
|
+
ratatui = { version = "0.30", default-features = false, features = ["crossterm"] }
|
|
17
17
|
serde = { version = "1", features = ["derive"] }
|
|
18
18
|
serde_json = "1"
|
|
19
19
|
unicode-width = "0.2"
|
package/README.md
CHANGED
|
@@ -12,7 +12,14 @@ Personal coding practice, right in your terminal.
|
|
|
12
12
|
|
|
13
13
|
`practicode` is a small Rust TUI for stdin/stdout practice: problem on the left, code on the right, judge loop in the same terminal.
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## What You Get
|
|
16
|
+
|
|
17
|
+
- Local stdin/stdout judging for Python, TypeScript, Java, and Rust.
|
|
18
|
+
- A two-pane terminal UI with problem text, editor, output, and command palette.
|
|
19
|
+
- Local-first problem history under ignored `.practicode/`, `problems/`, and `submissions/` paths.
|
|
20
|
+
- Optional Codex or Claude Code help for hints and generated next problems.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
16
23
|
|
|
17
24
|
### Prerequisites
|
|
18
25
|
|
|
@@ -43,6 +50,14 @@ npm install
|
|
|
43
50
|
npm start
|
|
44
51
|
```
|
|
45
52
|
|
|
53
|
+
### Check Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
practicode --version
|
|
57
|
+
practicode --smoke
|
|
58
|
+
practicode --help
|
|
59
|
+
```
|
|
60
|
+
|
|
46
61
|
## Daily Loop
|
|
47
62
|
|
|
48
63
|
The code editor starts focused.
|
|
@@ -54,18 +69,26 @@ choose /run
|
|
|
54
69
|
choose /next when it passes
|
|
55
70
|
```
|
|
56
71
|
|
|
57
|
-
Typing `/` outside the editor opens the command palette. Use `up/down` to move, `Enter` to run or complete the selected command, and `Esc` to cancel.
|
|
72
|
+
Typing `/` outside the editor opens the command palette. Use `up/down` to move, `Enter` to run or complete the selected command, and `Esc` to cancel. Press `?` for in-app help or `Ctrl+C` to quit.
|
|
58
73
|
|
|
59
74
|
Submissions are saved as you type under `submissions/<problem-id>/solution.<ext>`.
|
|
60
75
|
|
|
76
|
+
## CLI Flags
|
|
77
|
+
|
|
78
|
+
| Flag | Action |
|
|
79
|
+
| --- | --- |
|
|
80
|
+
| `--help`, `-h` | Show non-interactive help |
|
|
81
|
+
| `--version`, `-V` | Print the installed version |
|
|
82
|
+
| `--smoke` | Print the current problem title and exit |
|
|
83
|
+
|
|
61
84
|
## Commands
|
|
62
85
|
|
|
63
86
|
| Command | Action |
|
|
64
87
|
| --- | --- |
|
|
65
88
|
| `/run` | Judge the current submission |
|
|
66
89
|
| `/code` | Return to the code editor |
|
|
67
|
-
| `/next` | Open the next
|
|
68
|
-
| `/
|
|
90
|
+
| `/next` | Open the next unsolved problem, or ask AI only when none remain |
|
|
91
|
+
| `/generate easy string problem` | Ask AI to create a new problem now |
|
|
69
92
|
| `/back` | Go back through problem history |
|
|
70
93
|
| `/problems` | Browse problems with `up/down` or `j/k`, open with `Enter` |
|
|
71
94
|
| `/open 2` | Open by number, id, or slug |
|
|
@@ -90,14 +113,16 @@ The default UI language is English. Switch it any time with `/ui ko`, `/ui ja`,
|
|
|
90
113
|
|
|
91
114
|
Your practice profile is saved in `.practicode/problem-state.json`. It keeps UI language, code language, theme, preferred difficulty, preferred topics, and topics to avoid. `auto` difficulty follows gradual progression; a fixed difficulty asks local selection and AI generation to prefer that level.
|
|
92
115
|
|
|
93
|
-
##
|
|
116
|
+
## Problem Flow
|
|
117
|
+
|
|
118
|
+
`/next` is local-first: it opens the next unsolved local problem before generating anything. When no unsolved problem remains, it asks the selected AI provider to create one.
|
|
94
119
|
|
|
95
|
-
`/
|
|
120
|
+
Use `/generate <request>` when you explicitly want to create a new problem now.
|
|
96
121
|
|
|
97
122
|
```text
|
|
98
|
-
/
|
|
99
|
-
/
|
|
100
|
-
/
|
|
123
|
+
/generate a slightly harder string problem
|
|
124
|
+
/generate hashmap practice, easy
|
|
125
|
+
/generate sorting problem, no graph yet
|
|
101
126
|
```
|
|
102
127
|
|
|
103
128
|
Codex is the default provider:
|
|
@@ -135,9 +160,22 @@ npm update -g practicode
|
|
|
135
160
|
cargo install --force practicode
|
|
136
161
|
```
|
|
137
162
|
|
|
138
|
-
## Safety
|
|
163
|
+
## Safety And Security
|
|
164
|
+
|
|
165
|
+
- `/run` executes your local submission as a normal process. practicode runs it from `.practicode/build/<problem-id>/run`, but this is not an OS sandbox. Only run code you trust.
|
|
166
|
+
- `/hint` sends the current problem and submission to the selected AI provider CLI.
|
|
167
|
+
- AI-backed `/next` can run a custom shell command from `settings.ai_next_command`; save only commands you trust.
|
|
168
|
+
- Local `.env`, `.npmrc`, `.practicode/`, `problems/`, and `submissions/` are ignored by git. Do not commit tokens, private prompts, or answer keys.
|
|
169
|
+
|
|
170
|
+
## Development Checks
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
cargo test
|
|
174
|
+
cargo run -- --smoke
|
|
175
|
+
cargo audit
|
|
176
|
+
```
|
|
139
177
|
|
|
140
|
-
|
|
178
|
+
This repo has no npm dependencies or lockfile today, so `npm audit` and `pnpm audit` are not applicable until a matching lockfile is added.
|
|
141
179
|
|
|
142
180
|
## Contributing
|
|
143
181
|
|
package/assets/i18n/en.json
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"cmd_code": "Return to the code editor",
|
|
27
27
|
"cmd_edit": "Return to the code editor",
|
|
28
28
|
"cmd_next": "Open the next problem",
|
|
29
|
+
"cmd_generate": "Generate a new problem now",
|
|
29
30
|
"cmd_prev": "Open the previous problem",
|
|
30
31
|
"cmd_list": "Browse problems",
|
|
31
32
|
"cmd_open": "Open by number, id, or slug",
|
package/assets/i18n/es.json
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"cmd_code": "Volver al editor de codigo",
|
|
27
27
|
"cmd_edit": "Volver al editor de codigo",
|
|
28
28
|
"cmd_next": "Abrir el siguiente problema",
|
|
29
|
+
"cmd_generate": "Generar un problema nuevo ahora",
|
|
29
30
|
"cmd_prev": "Abrir el problema anterior",
|
|
30
31
|
"cmd_list": "Abrir la lista de problemas",
|
|
31
32
|
"cmd_open": "Abrir por numero, id o slug",
|
package/assets/i18n/ja.json
CHANGED
package/assets/i18n/ko.json
CHANGED
package/assets/i18n/zh.json
CHANGED
package/package.json
CHANGED
package/src/lib.rs
CHANGED
|
@@ -14,9 +14,39 @@ pub mod text;
|
|
|
14
14
|
pub mod tui;
|
|
15
15
|
pub mod update;
|
|
16
16
|
|
|
17
|
+
pub fn cli_help_text() -> &'static str {
|
|
18
|
+
"practicode - local-first coding-test practice in your terminal
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
practicode Open the TUI
|
|
22
|
+
practicode --smoke Print the current problem title and exit
|
|
23
|
+
practicode --version Print the installed version
|
|
24
|
+
practicode --help Show this help
|
|
25
|
+
|
|
26
|
+
Inside the TUI:
|
|
27
|
+
Esc then / Open the command palette
|
|
28
|
+
? Open help
|
|
29
|
+
Ctrl+C Quit"
|
|
30
|
+
}
|
|
31
|
+
|
|
17
32
|
pub fn run_cli() -> Result<()> {
|
|
18
33
|
let root = env::current_dir().context("read current directory")?;
|
|
19
|
-
|
|
34
|
+
let args = env::args().skip(1).collect::<Vec<_>>();
|
|
35
|
+
if args
|
|
36
|
+
.iter()
|
|
37
|
+
.any(|arg| matches!(arg.as_str(), "-h" | "--help"))
|
|
38
|
+
{
|
|
39
|
+
println!("{}", cli_help_text());
|
|
40
|
+
return Ok(());
|
|
41
|
+
}
|
|
42
|
+
if args
|
|
43
|
+
.iter()
|
|
44
|
+
.any(|arg| matches!(arg.as_str(), "-V" | "--version"))
|
|
45
|
+
{
|
|
46
|
+
println!("practicode {}", update::CURRENT_VERSION);
|
|
47
|
+
return Ok(());
|
|
48
|
+
}
|
|
49
|
+
if args.iter().any(|arg| arg == "--smoke") {
|
|
20
50
|
let bank = core::load_bank(&root)?;
|
|
21
51
|
let state = core::load_state(&root, &bank)?;
|
|
22
52
|
let problem = core::problem_by_id(&bank, &state.current_problem).unwrap_or(&bank[0]);
|
|
@@ -39,3 +69,16 @@ pub fn run_cli() -> Result<()> {
|
|
|
39
69
|
);
|
|
40
70
|
result
|
|
41
71
|
}
|
|
72
|
+
|
|
73
|
+
#[cfg(test)]
|
|
74
|
+
mod tests {
|
|
75
|
+
use super::cli_help_text;
|
|
76
|
+
|
|
77
|
+
#[test]
|
|
78
|
+
fn cli_help_lists_non_interactive_flags_and_tui_exit() {
|
|
79
|
+
let help = cli_help_text();
|
|
80
|
+
assert!(help.contains("--smoke"));
|
|
81
|
+
assert!(help.contains("--version"));
|
|
82
|
+
assert!(help.contains("Ctrl+C"));
|
|
83
|
+
}
|
|
84
|
+
}
|
package/src/tui/commands.rs
CHANGED
|
@@ -29,6 +29,13 @@ pub(super) const COMMAND_HINTS: &[CommandHint] = &[
|
|
|
29
29
|
keep_open: false,
|
|
30
30
|
help: true,
|
|
31
31
|
},
|
|
32
|
+
CommandHint {
|
|
33
|
+
insert: "generate ",
|
|
34
|
+
display: "/generate <request>",
|
|
35
|
+
desc_key: "cmd_generate",
|
|
36
|
+
keep_open: true,
|
|
37
|
+
help: true,
|
|
38
|
+
},
|
|
32
39
|
CommandHint {
|
|
33
40
|
insert: "back",
|
|
34
41
|
display: "/back",
|
package/src/tui.rs
CHANGED
|
@@ -96,7 +96,7 @@ enum TaskResult {
|
|
|
96
96
|
Next {
|
|
97
97
|
output: String,
|
|
98
98
|
old_problem: String,
|
|
99
|
-
|
|
99
|
+
fallback_to_local: bool,
|
|
100
100
|
},
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -210,6 +210,10 @@ impl PracticodeApp {
|
|
|
210
210
|
self.task_rx.is_some()
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
pub fn should_quit_for_test(&self) -> bool {
|
|
214
|
+
self.should_quit
|
|
215
|
+
}
|
|
216
|
+
|
|
213
217
|
pub fn status_text_for_test(&self) -> String {
|
|
214
218
|
self.status_text()
|
|
215
219
|
}
|
|
@@ -602,6 +606,10 @@ impl PracticodeApp {
|
|
|
602
606
|
}
|
|
603
607
|
|
|
604
608
|
fn handle_key(&mut self, key: KeyEvent) -> Result<()> {
|
|
609
|
+
if key.code == KeyCode::Char('c') && key.modifiers.contains(KeyModifiers::CONTROL) {
|
|
610
|
+
self.should_quit = true;
|
|
611
|
+
return Ok(());
|
|
612
|
+
}
|
|
605
613
|
match self.focus {
|
|
606
614
|
Focus::Command => self.handle_command_key(key),
|
|
607
615
|
Focus::Code => self.handle_code_key(key),
|
|
@@ -779,6 +787,7 @@ impl PracticodeApp {
|
|
|
779
787
|
"run" | "r" => self.action_run()?,
|
|
780
788
|
"code" | "edit" | "e" => self.action_edit()?,
|
|
781
789
|
"next" | "n" => self.action_next(arg)?,
|
|
790
|
+
"generate" | "gen" | "new" => self.action_generate(arg),
|
|
782
791
|
"back" | "prev" | "previous" | "p" => self.action_previous()?,
|
|
783
792
|
"answer" | "giveup" | "give" | "g" => self.action_give_up()?,
|
|
784
793
|
"problems" | "list" => self.start_problem_list(),
|
|
@@ -891,14 +900,6 @@ impl PracticodeApp {
|
|
|
891
900
|
fn action_next(&mut self, request: &str) -> Result<()> {
|
|
892
901
|
let request = request.trim();
|
|
893
902
|
let old_problem = self.state.current_problem.clone();
|
|
894
|
-
if !request.is_empty() {
|
|
895
|
-
self.start_next_problem(old_problem, true, request.to_string());
|
|
896
|
-
return Ok(());
|
|
897
|
-
}
|
|
898
|
-
if self.state.settings.next_source == "ai" {
|
|
899
|
-
self.start_next_problem(old_problem, false, String::new());
|
|
900
|
-
return Ok(());
|
|
901
|
-
}
|
|
902
903
|
if let Some(problem) = next_problem(&self.root, &self.bank, &mut self.state)? {
|
|
903
904
|
self.problem = problem;
|
|
904
905
|
self.load_code_editor()?;
|
|
@@ -906,11 +907,24 @@ impl PracticodeApp {
|
|
|
906
907
|
self.focus = Focus::Code;
|
|
907
908
|
return Ok(());
|
|
908
909
|
}
|
|
909
|
-
self.start_next_problem(old_problem, true,
|
|
910
|
+
self.start_next_problem(old_problem, true, request.to_string());
|
|
910
911
|
Ok(())
|
|
911
912
|
}
|
|
912
913
|
|
|
913
|
-
fn
|
|
914
|
+
fn action_generate(&mut self, request: &str) {
|
|
915
|
+
self.start_next_problem(
|
|
916
|
+
self.state.current_problem.clone(),
|
|
917
|
+
false,
|
|
918
|
+
request.trim().to_string(),
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
fn start_next_problem(
|
|
923
|
+
&mut self,
|
|
924
|
+
old_problem: String,
|
|
925
|
+
fallback_to_local: bool,
|
|
926
|
+
request: String,
|
|
927
|
+
) {
|
|
914
928
|
if self.task_rx.is_some() {
|
|
915
929
|
self.write_text_output(ui_text(&self.state.settings.ui_language, "already_busy"));
|
|
916
930
|
return;
|
|
@@ -923,11 +937,11 @@ impl PracticodeApp {
|
|
|
923
937
|
let state = self.state.clone();
|
|
924
938
|
let (tx, rx) = mpsc::channel();
|
|
925
939
|
thread::spawn(move || {
|
|
926
|
-
let output = run_ai_next(&root, &state,
|
|
940
|
+
let output = run_ai_next(&root, &state, true, &request);
|
|
927
941
|
let _ = tx.send(TaskResult::Next {
|
|
928
942
|
output,
|
|
929
943
|
old_problem,
|
|
930
|
-
|
|
944
|
+
fallback_to_local,
|
|
931
945
|
});
|
|
932
946
|
});
|
|
933
947
|
self.task_rx = Some(rx);
|
|
@@ -937,17 +951,17 @@ impl PracticodeApp {
|
|
|
937
951
|
&mut self,
|
|
938
952
|
output: String,
|
|
939
953
|
old_problem: String,
|
|
940
|
-
|
|
954
|
+
fallback_to_local: bool,
|
|
941
955
|
) -> Result<()> {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
self.state = load_state(&self.root, &self.bank)?;
|
|
945
|
-
}
|
|
956
|
+
self.bank = load_bank(&self.root)?;
|
|
957
|
+
self.state = load_state(&self.root, &self.bank)?;
|
|
946
958
|
self.problem = problem_by_id(&self.bank, &self.state.current_problem)
|
|
947
959
|
.cloned()
|
|
948
960
|
.unwrap_or_else(|| self.bank[0].clone());
|
|
949
961
|
if self.state.current_problem == old_problem {
|
|
950
|
-
if
|
|
962
|
+
if fallback_to_local
|
|
963
|
+
&& let Some(problem) = next_problem(&self.root, &self.bank, &mut self.state)?
|
|
964
|
+
{
|
|
951
965
|
self.problem = problem;
|
|
952
966
|
} else {
|
|
953
967
|
self.write_text_output(&format!(
|
|
@@ -1127,9 +1141,11 @@ impl PracticodeApp {
|
|
|
1127
1141
|
TaskResult::Next {
|
|
1128
1142
|
output,
|
|
1129
1143
|
old_problem,
|
|
1130
|
-
|
|
1144
|
+
fallback_to_local,
|
|
1131
1145
|
} => {
|
|
1132
|
-
if let Err(error) =
|
|
1146
|
+
if let Err(error) =
|
|
1147
|
+
self.finish_next_problem(output, old_problem, fallback_to_local)
|
|
1148
|
+
{
|
|
1133
1149
|
self.write_text_output(&format!("Next failed\n{error}"));
|
|
1134
1150
|
}
|
|
1135
1151
|
}
|
|
@@ -1638,11 +1654,7 @@ impl PracticodeApp {
|
|
|
1638
1654
|
}
|
|
1639
1655
|
|
|
1640
1656
|
fn next_source_help(&self) -> String {
|
|
1641
|
-
|
|
1642
|
-
"Next behavior: plain /next asks AI every time. /next <request> also sends that request.".to_string()
|
|
1643
|
-
} else {
|
|
1644
|
-
"Next behavior: /next uses local problems first and asks AI when it needs a new one. Use /next <request> to ask AI directly.".to_string()
|
|
1645
|
-
}
|
|
1657
|
+
"Next behavior: /next opens unsolved local problems first and asks AI only when none remain. Use /generate <request> to create a problem immediately.".to_string()
|
|
1646
1658
|
}
|
|
1647
1659
|
|
|
1648
1660
|
fn busy_dots(&self) -> String {
|