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 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 = "cassowary"
25
- version = "0.3.0"
39
+ name = "by_address"
40
+ version = "1.2.1"
26
41
  source = "registry+https://github.com/rust-lang/crates.io-index"
27
- checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
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.8.2"
61
+ version = "0.9.1"
47
62
  source = "registry+https://github.com/rust-lang/crates.io-index"
48
- checksum = "7fd622ebbb56a5b2ccb651b32b911cdeb2a9b4b11776b2473bf26a26a286244e"
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 1.1.4",
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 0.61.2",
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.1.5"
210
+ version = "0.2.0"
200
211
  source = "registry+https://github.com/rust-lang/crates.io-index"
201
- checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
212
+ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
202
213
 
203
214
  [[package]]
204
215
  name = "hashbrown"
205
- version = "0.15.5"
216
+ version = "0.16.1"
206
217
  source = "registry+https://github.com/rust-lang/crates.io-index"
207
- checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
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.13.0"
272
+ version = "0.14.0"
251
273
  source = "registry+https://github.com/rust-lang/crates.io-index"
252
- checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
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 = "linux-raw-sys"
271
- version = "0.4.15"
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 = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
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.12.5"
346
+ version = "0.18.0"
305
347
  source = "registry+https://github.com/rust-lang/crates.io-index"
306
- checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
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 0.61.2",
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 = "paste"
354
- version = "1.0.15"
443
+ name = "portable-atomic"
444
+ version = "1.13.1"
355
445
  source = "registry+https://github.com/rust-lang/crates.io-index"
356
- checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
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.6"
456
+ version = "0.1.7"
361
457
  dependencies = [
362
458
  "anyhow",
363
- "crossterm 0.29.0",
459
+ "crossterm",
364
460
  "ratatui",
365
461
  "serde",
366
462
  "serde_json",
367
- "unicode-width 0.2.0",
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.29.0"
487
+ version = "0.30.2"
392
488
  source = "registry+https://github.com/rust-lang/crates.io-index"
393
- checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
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
- "crossterm 0.28.1",
399
- "indoc",
400
- "instability",
506
+ "hashbrown 0.17.1",
401
507
  "itertools",
508
+ "kasuari",
402
509
  "lru",
403
- "paste",
510
+ "palette",
511
+ "serde",
404
512
  "strum",
513
+ "thiserror",
405
514
  "unicode-segmentation",
406
515
  "unicode-truncate",
407
- "unicode-width 0.2.0",
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 0.12.1",
451
- "windows-sys 0.61.2",
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.26.3"
700
+ version = "0.28.0"
573
701
  source = "registry+https://github.com/rust-lang/crates.io-index"
574
- checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
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.26.4"
709
+ version = "0.28.0"
582
710
  source = "registry+https://github.com/rust-lang/crates.io-index"
583
- checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
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 = "1.1.0"
785
+ version = "2.0.1"
618
786
  source = "registry+https://github.com/rust-lang/crates.io-index"
619
- checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
787
+ checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5"
620
788
  dependencies = [
621
789
  "itertools",
622
790
  "unicode-segmentation",
623
- "unicode-width 0.1.14",
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.6"
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.29"
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
- ## Start
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 local problem, or ask AI to create one |
68
- | `/next easy string problem` | Ask AI for a custom next problem |
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
- ## AI Problems
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
- `/next <request>` passes your request into the selected AI problem generator.
120
+ Use `/generate <request>` when you explicitly want to create a new problem now.
96
121
 
97
122
  ```text
98
- /next a slightly harder string problem
99
- /next hashmap practice, easy
100
- /next sorting problem, no graph yet
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
- `/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.
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
 
@@ -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",
@@ -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",
@@ -26,6 +26,7 @@
26
26
  "cmd_code": "コードエディタに戻る",
27
27
  "cmd_edit": "コードエディタに戻る",
28
28
  "cmd_next": "次の問題を開く",
29
+ "cmd_generate": "新しい問題を今すぐ生成",
29
30
  "cmd_prev": "前の問題を開く",
30
31
  "cmd_list": "問題一覧を開く",
31
32
  "cmd_open": "番号、id、slug で問題を開く",
@@ -26,6 +26,7 @@
26
26
  "cmd_code": "코드 편집기로 돌아가기",
27
27
  "cmd_edit": "코드 편집기로 돌아가기",
28
28
  "cmd_next": "다음 문제 열기",
29
+ "cmd_generate": "새 문제를 바로 생성",
29
30
  "cmd_prev": "이전 문제 열기",
30
31
  "cmd_list": "문제 목록 열기",
31
32
  "cmd_open": "번호, id, slug로 문제 열기",
@@ -26,6 +26,7 @@
26
26
  "cmd_code": "回到代码编辑器",
27
27
  "cmd_edit": "回到代码编辑器",
28
28
  "cmd_next": "打开下一题",
29
+ "cmd_generate": "立即生成新题",
29
30
  "cmd_prev": "打开上一题",
30
31
  "cmd_list": "打开题目列表",
31
32
  "cmd_open": "按编号、id 或 slug 打开题目",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "practicode",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Local-first coding-test practice in a Rust terminal UI with optional AI help.",
5
5
  "license": "MIT",
6
6
  "repository": {
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
- if env::args().any(|arg| arg == "--smoke") {
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
+ }
@@ -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
- force: bool,
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, String::new());
910
+ self.start_next_problem(old_problem, true, request.to_string());
910
911
  Ok(())
911
912
  }
912
913
 
913
- fn start_next_problem(&mut self, old_problem: String, force: bool, request: String) {
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, force, &request);
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
- force,
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
- force: bool,
954
+ fallback_to_local: bool,
941
955
  ) -> Result<()> {
942
- if self.state.settings.next_source == "ai" || force {
943
- self.bank = load_bank(&self.root)?;
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 let Some(problem) = next_problem(&self.root, &self.bank, &mut self.state)? {
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
- force,
1144
+ fallback_to_local,
1131
1145
  } => {
1132
- if let Err(error) = self.finish_next_problem(output, old_problem, force) {
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
- if self.state.settings.next_source == "ai" {
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 {