@nick-skriabin/glyph 0.1.23 → 0.1.25
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/README.md +19 -0
- package/dist/index.cjs +376 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +376 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
21
|
+
<a href="https://www.npmjs.com/package/@nick-skriabin/glyph"><img src="https://img.shields.io/npm/v/@nick-skriabin/glyph?color=crimson&logo=npm" alt="npm version"></a>
|
|
21
22
|
<img src="https://img.shields.io/badge/React-18%2B-61dafb?logo=react&logoColor=white" alt="React 18+">
|
|
22
23
|
<img src="https://img.shields.io/badge/Yoga-Flexbox-mediumpurple?logo=meta&logoColor=white" alt="Yoga Flexbox">
|
|
23
24
|
<img src="https://img.shields.io/badge/TypeScript-First-3178c6?logo=typescript&logoColor=white" alt="TypeScript">
|
|
@@ -616,6 +617,24 @@ pnpm --filter showcase dev # Progress, Spinner, Toasts
|
|
|
616
617
|
|
|
617
618
|
---
|
|
618
619
|
|
|
620
|
+
## Who Uses Glyph
|
|
621
|
+
|
|
622
|
+
<table>
|
|
623
|
+
<tr>
|
|
624
|
+
<td align="center">
|
|
625
|
+
<a href="https://github.com/nick-skriabin/aion">
|
|
626
|
+
<strong>Aion</strong>
|
|
627
|
+
</a>
|
|
628
|
+
<br>
|
|
629
|
+
<sub>Calendar & time management TUI</sub>
|
|
630
|
+
</td>
|
|
631
|
+
</tr>
|
|
632
|
+
</table>
|
|
633
|
+
|
|
634
|
+
<sub>Using Glyph in your project? <a href="https://github.com/nick-skriabin/glyph/issues">Let us know!</a></sub>
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
619
638
|
## Architecture
|
|
620
639
|
|
|
621
640
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -348,9 +348,18 @@ var Terminal = class {
|
|
|
348
348
|
resetStyles() {
|
|
349
349
|
this.write(`${CSI}0m`);
|
|
350
350
|
}
|
|
351
|
+
/** Enable kitty keyboard protocol for enhanced key detection */
|
|
352
|
+
enableKittyKeyboard() {
|
|
353
|
+
this.write(`${CSI}>1u`);
|
|
354
|
+
}
|
|
355
|
+
/** Disable kitty keyboard protocol */
|
|
356
|
+
disableKittyKeyboard() {
|
|
357
|
+
this.write(`${CSI}<u`);
|
|
358
|
+
}
|
|
351
359
|
setup() {
|
|
352
360
|
this.enterRawMode();
|
|
353
361
|
this.enterAltScreen();
|
|
362
|
+
this.enableKittyKeyboard();
|
|
354
363
|
this.hideCursor();
|
|
355
364
|
this.clearScreen();
|
|
356
365
|
this.attachStdinListener();
|
|
@@ -365,6 +374,7 @@ var Terminal = class {
|
|
|
365
374
|
}
|
|
366
375
|
this.resetStyles();
|
|
367
376
|
this.resetCursorColor();
|
|
377
|
+
this.disableKittyKeyboard();
|
|
368
378
|
this.showCursor();
|
|
369
379
|
this.exitAltScreen();
|
|
370
380
|
this.exitRawMode();
|
|
@@ -379,6 +389,7 @@ var Terminal = class {
|
|
|
379
389
|
this.oscAccum = "";
|
|
380
390
|
this.resetStyles();
|
|
381
391
|
this.resetCursorColor();
|
|
392
|
+
this.disableKittyKeyboard();
|
|
382
393
|
this.showCursor();
|
|
383
394
|
this.exitAltScreen();
|
|
384
395
|
this.exitRawMode();
|
|
@@ -387,6 +398,7 @@ var Terminal = class {
|
|
|
387
398
|
resume() {
|
|
388
399
|
this.enterRawMode();
|
|
389
400
|
this.enterAltScreen();
|
|
401
|
+
this.enableKittyKeyboard();
|
|
390
402
|
this.hideCursor();
|
|
391
403
|
this.clearScreen();
|
|
392
404
|
}
|
|
@@ -536,6 +548,211 @@ var Terminal = class {
|
|
|
536
548
|
};
|
|
537
549
|
|
|
538
550
|
// src/runtime/input.ts
|
|
551
|
+
function getKeyNameFromCode(code) {
|
|
552
|
+
switch (code) {
|
|
553
|
+
// Standard ASCII
|
|
554
|
+
case 9:
|
|
555
|
+
return "tab";
|
|
556
|
+
case 13:
|
|
557
|
+
return "return";
|
|
558
|
+
case 27:
|
|
559
|
+
return "escape";
|
|
560
|
+
case 32:
|
|
561
|
+
return " ";
|
|
562
|
+
case 127:
|
|
563
|
+
return "backspace";
|
|
564
|
+
// Kitty protocol special keys
|
|
565
|
+
case 57358:
|
|
566
|
+
return "capslock";
|
|
567
|
+
case 57359:
|
|
568
|
+
return "scrolllock";
|
|
569
|
+
case 57360:
|
|
570
|
+
return "numlock";
|
|
571
|
+
case 57361:
|
|
572
|
+
return "printscreen";
|
|
573
|
+
case 57362:
|
|
574
|
+
return "pause";
|
|
575
|
+
case 57363:
|
|
576
|
+
return "menu";
|
|
577
|
+
// Function keys (kitty uses these codes)
|
|
578
|
+
case 57364:
|
|
579
|
+
return "f13";
|
|
580
|
+
case 57365:
|
|
581
|
+
return "f14";
|
|
582
|
+
case 57366:
|
|
583
|
+
return "f15";
|
|
584
|
+
case 57367:
|
|
585
|
+
return "f16";
|
|
586
|
+
case 57368:
|
|
587
|
+
return "f17";
|
|
588
|
+
case 57369:
|
|
589
|
+
return "f18";
|
|
590
|
+
case 57370:
|
|
591
|
+
return "f19";
|
|
592
|
+
case 57371:
|
|
593
|
+
return "f20";
|
|
594
|
+
case 57372:
|
|
595
|
+
return "f21";
|
|
596
|
+
case 57373:
|
|
597
|
+
return "f22";
|
|
598
|
+
case 57374:
|
|
599
|
+
return "f23";
|
|
600
|
+
case 57375:
|
|
601
|
+
return "f24";
|
|
602
|
+
case 57376:
|
|
603
|
+
return "f25";
|
|
604
|
+
// Keypad keys
|
|
605
|
+
case 57399:
|
|
606
|
+
return "kp0";
|
|
607
|
+
case 57400:
|
|
608
|
+
return "kp1";
|
|
609
|
+
case 57401:
|
|
610
|
+
return "kp2";
|
|
611
|
+
case 57402:
|
|
612
|
+
return "kp3";
|
|
613
|
+
case 57403:
|
|
614
|
+
return "kp4";
|
|
615
|
+
case 57404:
|
|
616
|
+
return "kp5";
|
|
617
|
+
case 57405:
|
|
618
|
+
return "kp6";
|
|
619
|
+
case 57406:
|
|
620
|
+
return "kp7";
|
|
621
|
+
case 57407:
|
|
622
|
+
return "kp8";
|
|
623
|
+
case 57408:
|
|
624
|
+
return "kp9";
|
|
625
|
+
case 57409:
|
|
626
|
+
return "kpdecimal";
|
|
627
|
+
case 57410:
|
|
628
|
+
return "kpdivide";
|
|
629
|
+
case 57411:
|
|
630
|
+
return "kpmultiply";
|
|
631
|
+
case 57412:
|
|
632
|
+
return "kpminus";
|
|
633
|
+
case 57413:
|
|
634
|
+
return "kpplus";
|
|
635
|
+
case 57414:
|
|
636
|
+
return "kpenter";
|
|
637
|
+
case 57415:
|
|
638
|
+
return "kpequal";
|
|
639
|
+
// Navigation (kitty protocol)
|
|
640
|
+
case 57416:
|
|
641
|
+
return "kpleft";
|
|
642
|
+
case 57417:
|
|
643
|
+
return "kpright";
|
|
644
|
+
case 57418:
|
|
645
|
+
return "kpup";
|
|
646
|
+
case 57419:
|
|
647
|
+
return "kpdown";
|
|
648
|
+
case 57420:
|
|
649
|
+
return "kppageup";
|
|
650
|
+
case 57421:
|
|
651
|
+
return "kppagedown";
|
|
652
|
+
case 57422:
|
|
653
|
+
return "kphome";
|
|
654
|
+
case 57423:
|
|
655
|
+
return "kpend";
|
|
656
|
+
case 57424:
|
|
657
|
+
return "kpinsert";
|
|
658
|
+
case 57425:
|
|
659
|
+
return "kpdelete";
|
|
660
|
+
// Media keys
|
|
661
|
+
case 57428:
|
|
662
|
+
return "mediaplaypause";
|
|
663
|
+
case 57429:
|
|
664
|
+
return "mediastop";
|
|
665
|
+
case 57430:
|
|
666
|
+
return "mediaprev";
|
|
667
|
+
case 57431:
|
|
668
|
+
return "medianext";
|
|
669
|
+
case 57432:
|
|
670
|
+
return "mediarewind";
|
|
671
|
+
case 57433:
|
|
672
|
+
return "mediafastforward";
|
|
673
|
+
case 57434:
|
|
674
|
+
return "mediamute";
|
|
675
|
+
case 57435:
|
|
676
|
+
return "volumedown";
|
|
677
|
+
case 57436:
|
|
678
|
+
return "volumeup";
|
|
679
|
+
default:
|
|
680
|
+
if (code >= 32 && code <= 126) {
|
|
681
|
+
return String.fromCharCode(code).toLowerCase();
|
|
682
|
+
}
|
|
683
|
+
return "unknown";
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
function getTildeKeyName(param) {
|
|
687
|
+
const baseParam = param.split(";")[0];
|
|
688
|
+
switch (baseParam) {
|
|
689
|
+
case "1":
|
|
690
|
+
return "home";
|
|
691
|
+
case "2":
|
|
692
|
+
return "insert";
|
|
693
|
+
case "3":
|
|
694
|
+
return "delete";
|
|
695
|
+
case "4":
|
|
696
|
+
return "end";
|
|
697
|
+
case "5":
|
|
698
|
+
return "pageup";
|
|
699
|
+
case "6":
|
|
700
|
+
return "pagedown";
|
|
701
|
+
case "7":
|
|
702
|
+
return "home";
|
|
703
|
+
case "8":
|
|
704
|
+
return "end";
|
|
705
|
+
case "11":
|
|
706
|
+
return "f1";
|
|
707
|
+
case "12":
|
|
708
|
+
return "f2";
|
|
709
|
+
case "13":
|
|
710
|
+
return "f3";
|
|
711
|
+
case "14":
|
|
712
|
+
return "f4";
|
|
713
|
+
case "15":
|
|
714
|
+
return "f5";
|
|
715
|
+
case "17":
|
|
716
|
+
return "f6";
|
|
717
|
+
case "18":
|
|
718
|
+
return "f7";
|
|
719
|
+
case "19":
|
|
720
|
+
return "f8";
|
|
721
|
+
case "20":
|
|
722
|
+
return "f9";
|
|
723
|
+
case "21":
|
|
724
|
+
return "f10";
|
|
725
|
+
case "23":
|
|
726
|
+
return "f11";
|
|
727
|
+
case "24":
|
|
728
|
+
return "f12";
|
|
729
|
+
case "25":
|
|
730
|
+
return "f13";
|
|
731
|
+
case "26":
|
|
732
|
+
return "f14";
|
|
733
|
+
case "28":
|
|
734
|
+
return "f15";
|
|
735
|
+
case "29":
|
|
736
|
+
return "f16";
|
|
737
|
+
case "31":
|
|
738
|
+
return "f17";
|
|
739
|
+
case "32":
|
|
740
|
+
return "f18";
|
|
741
|
+
case "33":
|
|
742
|
+
return "f19";
|
|
743
|
+
case "34":
|
|
744
|
+
return "f20";
|
|
745
|
+
default:
|
|
746
|
+
return "unknown";
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
function applyModifiers(key, mod) {
|
|
750
|
+
const m = mod - 1;
|
|
751
|
+
if (m & 1) key.shift = true;
|
|
752
|
+
if (m & 2) key.alt = true;
|
|
753
|
+
if (m & 4) key.ctrl = true;
|
|
754
|
+
if (m & 8) key.meta = true;
|
|
755
|
+
}
|
|
539
756
|
function parseKeySequence(data) {
|
|
540
757
|
const keys = [];
|
|
541
758
|
let i = 0;
|
|
@@ -551,9 +768,17 @@ function parseKeySequence(data) {
|
|
|
551
768
|
continue;
|
|
552
769
|
}
|
|
553
770
|
}
|
|
771
|
+
if (data[i + 1] === "O") {
|
|
772
|
+
const seq = parseSs3Sequence(data, i);
|
|
773
|
+
if (seq) {
|
|
774
|
+
keys.push(seq.key);
|
|
775
|
+
i = seq.end;
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
554
779
|
if (i + 1 < data.length && data.charCodeAt(i + 1) >= 32) {
|
|
555
780
|
keys.push({
|
|
556
|
-
name: data[i + 1],
|
|
781
|
+
name: data[i + 1].toLowerCase(),
|
|
557
782
|
sequence: data.substring(i, i + 2),
|
|
558
783
|
alt: true
|
|
559
784
|
});
|
|
@@ -588,6 +813,102 @@ function parseKeySequence(data) {
|
|
|
588
813
|
}
|
|
589
814
|
return keys;
|
|
590
815
|
}
|
|
816
|
+
function parseSs3Sequence(data, start) {
|
|
817
|
+
if (start + 2 >= data.length) return null;
|
|
818
|
+
const final = data[start + 2];
|
|
819
|
+
const sequence = data.substring(start, start + 3);
|
|
820
|
+
let key;
|
|
821
|
+
switch (final) {
|
|
822
|
+
// Arrow keys (some terminals)
|
|
823
|
+
case "A":
|
|
824
|
+
key = { name: "up", sequence };
|
|
825
|
+
break;
|
|
826
|
+
case "B":
|
|
827
|
+
key = { name: "down", sequence };
|
|
828
|
+
break;
|
|
829
|
+
case "C":
|
|
830
|
+
key = { name: "right", sequence };
|
|
831
|
+
break;
|
|
832
|
+
case "D":
|
|
833
|
+
key = { name: "left", sequence };
|
|
834
|
+
break;
|
|
835
|
+
// Home/End (some terminals)
|
|
836
|
+
case "H":
|
|
837
|
+
key = { name: "home", sequence };
|
|
838
|
+
break;
|
|
839
|
+
case "F":
|
|
840
|
+
key = { name: "end", sequence };
|
|
841
|
+
break;
|
|
842
|
+
// Function keys F1-F4
|
|
843
|
+
case "P":
|
|
844
|
+
key = { name: "f1", sequence };
|
|
845
|
+
break;
|
|
846
|
+
case "Q":
|
|
847
|
+
key = { name: "f2", sequence };
|
|
848
|
+
break;
|
|
849
|
+
case "R":
|
|
850
|
+
key = { name: "f3", sequence };
|
|
851
|
+
break;
|
|
852
|
+
case "S":
|
|
853
|
+
key = { name: "f4", sequence };
|
|
854
|
+
break;
|
|
855
|
+
// Keypad (application mode)
|
|
856
|
+
case "j":
|
|
857
|
+
key = { name: "kpmultiply", sequence };
|
|
858
|
+
break;
|
|
859
|
+
case "k":
|
|
860
|
+
key = { name: "kpplus", sequence };
|
|
861
|
+
break;
|
|
862
|
+
case "l":
|
|
863
|
+
key = { name: "kpcomma", sequence };
|
|
864
|
+
break;
|
|
865
|
+
case "m":
|
|
866
|
+
key = { name: "kpminus", sequence };
|
|
867
|
+
break;
|
|
868
|
+
case "n":
|
|
869
|
+
key = { name: "kpdecimal", sequence };
|
|
870
|
+
break;
|
|
871
|
+
case "o":
|
|
872
|
+
key = { name: "kpdivide", sequence };
|
|
873
|
+
break;
|
|
874
|
+
case "p":
|
|
875
|
+
key = { name: "kp0", sequence };
|
|
876
|
+
break;
|
|
877
|
+
case "q":
|
|
878
|
+
key = { name: "kp1", sequence };
|
|
879
|
+
break;
|
|
880
|
+
case "r":
|
|
881
|
+
key = { name: "kp2", sequence };
|
|
882
|
+
break;
|
|
883
|
+
case "s":
|
|
884
|
+
key = { name: "kp3", sequence };
|
|
885
|
+
break;
|
|
886
|
+
case "t":
|
|
887
|
+
key = { name: "kp4", sequence };
|
|
888
|
+
break;
|
|
889
|
+
case "u":
|
|
890
|
+
key = { name: "kp5", sequence };
|
|
891
|
+
break;
|
|
892
|
+
case "v":
|
|
893
|
+
key = { name: "kp6", sequence };
|
|
894
|
+
break;
|
|
895
|
+
case "w":
|
|
896
|
+
key = { name: "kp7", sequence };
|
|
897
|
+
break;
|
|
898
|
+
case "x":
|
|
899
|
+
key = { name: "kp8", sequence };
|
|
900
|
+
break;
|
|
901
|
+
case "y":
|
|
902
|
+
key = { name: "kp9", sequence };
|
|
903
|
+
break;
|
|
904
|
+
case "M":
|
|
905
|
+
key = { name: "kpenter", sequence };
|
|
906
|
+
break;
|
|
907
|
+
default:
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
return { key, end: start + 3 };
|
|
911
|
+
}
|
|
591
912
|
function parseCsiSequence(data, start) {
|
|
592
913
|
let i = start + 2;
|
|
593
914
|
let params = "";
|
|
@@ -606,6 +927,7 @@ function parseCsiSequence(data, start) {
|
|
|
606
927
|
i++;
|
|
607
928
|
let key;
|
|
608
929
|
switch (final) {
|
|
930
|
+
// Arrow keys
|
|
609
931
|
case "A":
|
|
610
932
|
key = { name: "up", sequence };
|
|
611
933
|
break;
|
|
@@ -618,43 +940,73 @@ function parseCsiSequence(data, start) {
|
|
|
618
940
|
case "D":
|
|
619
941
|
key = { name: "left", sequence };
|
|
620
942
|
break;
|
|
943
|
+
// Home/End
|
|
621
944
|
case "H":
|
|
622
945
|
key = { name: "home", sequence };
|
|
623
946
|
break;
|
|
624
947
|
case "F":
|
|
625
948
|
key = { name: "end", sequence };
|
|
626
949
|
break;
|
|
950
|
+
// Shift+Tab
|
|
627
951
|
case "Z":
|
|
628
952
|
key = { name: "tab", sequence, shift: true };
|
|
629
953
|
break;
|
|
954
|
+
// Function keys (some terminals)
|
|
955
|
+
case "P":
|
|
956
|
+
key = { name: "f1", sequence };
|
|
957
|
+
break;
|
|
958
|
+
case "Q":
|
|
959
|
+
key = { name: "f2", sequence };
|
|
960
|
+
break;
|
|
961
|
+
case "R":
|
|
962
|
+
key = { name: "f3", sequence };
|
|
963
|
+
break;
|
|
964
|
+
case "S":
|
|
965
|
+
key = { name: "f4", sequence };
|
|
966
|
+
break;
|
|
967
|
+
// ~ terminated sequences (VT-style)
|
|
630
968
|
case "~": {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
default:
|
|
645
|
-
key = { name: "unknown", sequence };
|
|
969
|
+
if (params.startsWith("27;")) {
|
|
970
|
+
const modParts = params.split(";");
|
|
971
|
+
const mod = parseInt(modParts[1] ?? "1", 10);
|
|
972
|
+
const keyCode = parseInt(modParts[2] ?? "0", 10);
|
|
973
|
+
key = { name: getKeyNameFromCode(keyCode), sequence };
|
|
974
|
+
applyModifiers(key, mod);
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
key = { name: getTildeKeyName(params), sequence };
|
|
978
|
+
if (params.includes(";")) {
|
|
979
|
+
const parts = params.split(";");
|
|
980
|
+
const mod = parseInt(parts[1] ?? "1", 10);
|
|
981
|
+
applyModifiers(key, mod);
|
|
646
982
|
}
|
|
647
983
|
break;
|
|
648
984
|
}
|
|
985
|
+
// Kitty keyboard protocol: CSI code;mod u
|
|
986
|
+
case "u": {
|
|
987
|
+
const parts = params.split(";");
|
|
988
|
+
const keyCode = parseInt(parts[0] ?? "0", 10);
|
|
989
|
+
const mod = parseInt(parts[1] ?? "1", 10);
|
|
990
|
+
key = { name: getKeyNameFromCode(keyCode), sequence };
|
|
991
|
+
applyModifiers(key, mod);
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
// Focus events (if terminal reports them)
|
|
995
|
+
case "I":
|
|
996
|
+
key = { name: "focus", sequence };
|
|
997
|
+
break;
|
|
998
|
+
case "O":
|
|
999
|
+
key = { name: "blur", sequence };
|
|
1000
|
+
break;
|
|
649
1001
|
default:
|
|
650
1002
|
key = { name: "unknown", sequence };
|
|
651
1003
|
}
|
|
652
|
-
if (params.includes(";")) {
|
|
1004
|
+
if (params.includes(";") && !["~", "u"].includes(final)) {
|
|
653
1005
|
const parts = params.split(";");
|
|
654
|
-
const mod = parseInt(parts[1] ?? "1", 10)
|
|
655
|
-
if (mod
|
|
656
|
-
|
|
657
|
-
|
|
1006
|
+
const mod = parseInt(parts[parts.length - 1] ?? "1", 10);
|
|
1007
|
+
if (mod >= 1 && mod <= 16) {
|
|
1008
|
+
applyModifiers(key, mod);
|
|
1009
|
+
}
|
|
658
1010
|
}
|
|
659
1011
|
return { key, end: i };
|
|
660
1012
|
}
|
|
@@ -2357,7 +2709,8 @@ function parseKeyDescriptor(descriptor) {
|
|
|
2357
2709
|
name,
|
|
2358
2710
|
ctrl: parts.includes("ctrl"),
|
|
2359
2711
|
alt: parts.includes("alt"),
|
|
2360
|
-
shift: parts.includes("shift")
|
|
2712
|
+
shift: parts.includes("shift"),
|
|
2713
|
+
meta: parts.includes("meta") || parts.includes("cmd") || parts.includes("super") || parts.includes("win")
|
|
2361
2714
|
};
|
|
2362
2715
|
}
|
|
2363
2716
|
function matchesKey(matcher, key) {
|
|
@@ -2365,6 +2718,7 @@ function matchesKey(matcher, key) {
|
|
|
2365
2718
|
if (matcher.ctrl !== !!key.ctrl) return false;
|
|
2366
2719
|
if (matcher.alt !== !!key.alt) return false;
|
|
2367
2720
|
if (matcher.shift !== !!key.shift) return false;
|
|
2721
|
+
if (matcher.meta !== !!key.meta) return false;
|
|
2368
2722
|
return true;
|
|
2369
2723
|
}
|
|
2370
2724
|
function Keybind({
|