@mariozechner/pi-tui 0.57.0 → 0.57.1
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/dist/components/editor.d.ts +14 -0
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +61 -0
- package/dist/components/editor.js.map +1 -1
- package/dist/keybindings.d.ts +1 -1
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +3 -0
- package/dist/keybindings.js.map +1 -1
- package/dist/keys.d.ts +2 -7
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +108 -77
- package/dist/keys.js.map +1 -1
- package/package.json +1 -1
package/dist/keys.js
CHANGED
|
@@ -460,20 +460,24 @@ function matchesKittySequence(data, expectedCodepoint, expectedModifier) {
|
|
|
460
460
|
}
|
|
461
461
|
return false;
|
|
462
462
|
}
|
|
463
|
+
function parseModifyOtherKeysSequence(data) {
|
|
464
|
+
const match = data.match(/^\x1b\[27;(\d+);(\d+)~$/);
|
|
465
|
+
if (!match)
|
|
466
|
+
return null;
|
|
467
|
+
const modValue = parseInt(match[1], 10);
|
|
468
|
+
const codepoint = parseInt(match[2], 10);
|
|
469
|
+
return { codepoint, modifier: modValue - 1 };
|
|
470
|
+
}
|
|
463
471
|
/**
|
|
464
472
|
* Match xterm modifyOtherKeys format: CSI 27 ; modifiers ; keycode ~
|
|
465
473
|
* This is used by terminals when Kitty protocol is not enabled.
|
|
466
474
|
* Modifier values are 1-indexed: 2=shift, 3=alt, 5=ctrl, etc.
|
|
467
475
|
*/
|
|
468
476
|
function matchesModifyOtherKeys(data, expectedKeycode, expectedModifier) {
|
|
469
|
-
const
|
|
470
|
-
if (!
|
|
477
|
+
const parsed = parseModifyOtherKeysSequence(data);
|
|
478
|
+
if (!parsed)
|
|
471
479
|
return false;
|
|
472
|
-
|
|
473
|
-
const keycode = parseInt(match[2], 10);
|
|
474
|
-
// Convert from 1-indexed xterm format to our 0-indexed format
|
|
475
|
-
const actualMod = modValue - 1;
|
|
476
|
-
return keycode === expectedKeycode && actualMod === expectedModifier;
|
|
480
|
+
return parsed.codepoint === expectedKeycode && parsed.modifier === expectedModifier;
|
|
477
481
|
}
|
|
478
482
|
// =============================================================================
|
|
479
483
|
// Generic Key Matching
|
|
@@ -499,6 +503,28 @@ function rawCtrlChar(key) {
|
|
|
499
503
|
}
|
|
500
504
|
return null;
|
|
501
505
|
}
|
|
506
|
+
function isDigitKey(key) {
|
|
507
|
+
return key >= "0" && key <= "9";
|
|
508
|
+
}
|
|
509
|
+
function matchesPrintableModifyOtherKeys(data, expectedKeycode, expectedModifier) {
|
|
510
|
+
if (expectedModifier === 0)
|
|
511
|
+
return false;
|
|
512
|
+
return matchesModifyOtherKeys(data, expectedKeycode, expectedModifier);
|
|
513
|
+
}
|
|
514
|
+
function formatKeyNameWithModifiers(keyName, modifier) {
|
|
515
|
+
const mods = [];
|
|
516
|
+
const effectiveMod = modifier & ~LOCK_MASK;
|
|
517
|
+
const supportedModifierMask = MODIFIERS.shift | MODIFIERS.ctrl | MODIFIERS.alt;
|
|
518
|
+
if ((effectiveMod & ~supportedModifierMask) !== 0)
|
|
519
|
+
return undefined;
|
|
520
|
+
if (effectiveMod & MODIFIERS.shift)
|
|
521
|
+
mods.push("shift");
|
|
522
|
+
if (effectiveMod & MODIFIERS.ctrl)
|
|
523
|
+
mods.push("ctrl");
|
|
524
|
+
if (effectiveMod & MODIFIERS.alt)
|
|
525
|
+
mods.push("alt");
|
|
526
|
+
return mods.length > 0 ? `${mods.join("+")}+${keyName}` : keyName;
|
|
527
|
+
}
|
|
502
528
|
function parseKeyId(keyId) {
|
|
503
529
|
const parts = keyId.toLowerCase().split("+");
|
|
504
530
|
const key = parts[parts.length - 1];
|
|
@@ -611,7 +637,8 @@ export function matchesKey(data, keyId) {
|
|
|
611
637
|
matchesKittySequence(data, CODEPOINTS.kpEnter, 0));
|
|
612
638
|
}
|
|
613
639
|
return (matchesKittySequence(data, CODEPOINTS.enter, modifier) ||
|
|
614
|
-
matchesKittySequence(data, CODEPOINTS.kpEnter, modifier)
|
|
640
|
+
matchesKittySequence(data, CODEPOINTS.kpEnter, modifier) ||
|
|
641
|
+
matchesModifyOtherKeys(data, CODEPOINTS.enter, modifier));
|
|
615
642
|
case "backspace":
|
|
616
643
|
if (alt && !ctrl && !shift) {
|
|
617
644
|
if (data === "\x1b\x7f" || data === "\x1b\b") {
|
|
@@ -765,16 +792,18 @@ export function matchesKey(data, keyId) {
|
|
|
765
792
|
return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES[functionKey]);
|
|
766
793
|
}
|
|
767
794
|
}
|
|
768
|
-
// Handle single letter keys
|
|
769
|
-
if (key.length === 1 && ((key >= "a" && key <= "z") || SYMBOL_KEYS.has(key))) {
|
|
795
|
+
// Handle single letter/digit keys and symbols
|
|
796
|
+
if (key.length === 1 && ((key >= "a" && key <= "z") || isDigitKey(key) || SYMBOL_KEYS.has(key))) {
|
|
770
797
|
const codepoint = key.charCodeAt(0);
|
|
771
798
|
const rawCtrl = rawCtrlChar(key);
|
|
799
|
+
const isLetter = key >= "a" && key <= "z";
|
|
800
|
+
const isDigit = isDigitKey(key);
|
|
772
801
|
if (ctrl && alt && !shift && !_kittyProtocolActive && rawCtrl) {
|
|
773
802
|
// Legacy: ctrl+alt+key is ESC followed by the control character
|
|
774
803
|
return data === `\x1b${rawCtrl}`;
|
|
775
804
|
}
|
|
776
|
-
if (alt && !ctrl && !shift && !_kittyProtocolActive &&
|
|
777
|
-
// Legacy: alt+letter is ESC followed by the
|
|
805
|
+
if (alt && !ctrl && !shift && !_kittyProtocolActive && (isLetter || isDigit)) {
|
|
806
|
+
// Legacy: alt+letter/digit is ESC followed by the key
|
|
778
807
|
if (data === `\x1b${key}`)
|
|
779
808
|
return true;
|
|
780
809
|
}
|
|
@@ -782,19 +811,23 @@ export function matchesKey(data, keyId) {
|
|
|
782
811
|
// Legacy: ctrl+key sends the control character
|
|
783
812
|
if (rawCtrl && data === rawCtrl)
|
|
784
813
|
return true;
|
|
785
|
-
return matchesKittySequence(data, codepoint, MODIFIERS.ctrl)
|
|
814
|
+
return (matchesKittySequence(data, codepoint, MODIFIERS.ctrl) ||
|
|
815
|
+
matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.ctrl));
|
|
786
816
|
}
|
|
787
817
|
if (ctrl && shift && !alt) {
|
|
788
|
-
return matchesKittySequence(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl)
|
|
818
|
+
return (matchesKittySequence(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl) ||
|
|
819
|
+
matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl));
|
|
789
820
|
}
|
|
790
821
|
if (shift && !ctrl && !alt) {
|
|
791
822
|
// Legacy: shift+letter produces uppercase
|
|
792
|
-
if (data === key.toUpperCase())
|
|
823
|
+
if (isLetter && data === key.toUpperCase())
|
|
793
824
|
return true;
|
|
794
|
-
return matchesKittySequence(data, codepoint, MODIFIERS.shift)
|
|
825
|
+
return (matchesKittySequence(data, codepoint, MODIFIERS.shift) ||
|
|
826
|
+
matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift));
|
|
795
827
|
}
|
|
796
828
|
if (modifier !== 0) {
|
|
797
|
-
return matchesKittySequence(data, codepoint, modifier)
|
|
829
|
+
return (matchesKittySequence(data, codepoint, modifier) ||
|
|
830
|
+
matchesPrintableModifyOtherKeys(data, codepoint, modifier));
|
|
798
831
|
}
|
|
799
832
|
// Check both raw char and Kitty sequence (needed for release events)
|
|
800
833
|
return data === key || matchesKittySequence(data, codepoint, 0);
|
|
@@ -807,67 +840,65 @@ export function matchesKey(data, keyId) {
|
|
|
807
840
|
* @param data - Raw input data from terminal
|
|
808
841
|
* @returns Key identifier string (e.g., "ctrl+c") or undefined
|
|
809
842
|
*/
|
|
843
|
+
function formatParsedKey(codepoint, modifier, baseLayoutKey) {
|
|
844
|
+
// Use base layout key only when codepoint is not a recognized Latin
|
|
845
|
+
// letter (a-z), digit (0-9), or symbol (/, -, [, ;, etc.). For those,
|
|
846
|
+
// the codepoint is authoritative regardless of physical key position.
|
|
847
|
+
// This prevents remapped layouts (Dvorak, Colemak, xremap, etc.) from
|
|
848
|
+
// reporting the wrong key name based on the QWERTY physical position.
|
|
849
|
+
const isLatinLetter = codepoint >= 97 && codepoint <= 122; // a-z
|
|
850
|
+
const isDigit = codepoint >= 48 && codepoint <= 57; // 0-9
|
|
851
|
+
const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(codepoint));
|
|
852
|
+
const effectiveCodepoint = isLatinLetter || isDigit || isKnownSymbol ? codepoint : (baseLayoutKey ?? codepoint);
|
|
853
|
+
let keyName;
|
|
854
|
+
if (effectiveCodepoint === CODEPOINTS.escape)
|
|
855
|
+
keyName = "escape";
|
|
856
|
+
else if (effectiveCodepoint === CODEPOINTS.tab)
|
|
857
|
+
keyName = "tab";
|
|
858
|
+
else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter)
|
|
859
|
+
keyName = "enter";
|
|
860
|
+
else if (effectiveCodepoint === CODEPOINTS.space)
|
|
861
|
+
keyName = "space";
|
|
862
|
+
else if (effectiveCodepoint === CODEPOINTS.backspace)
|
|
863
|
+
keyName = "backspace";
|
|
864
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete)
|
|
865
|
+
keyName = "delete";
|
|
866
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert)
|
|
867
|
+
keyName = "insert";
|
|
868
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home)
|
|
869
|
+
keyName = "home";
|
|
870
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end)
|
|
871
|
+
keyName = "end";
|
|
872
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp)
|
|
873
|
+
keyName = "pageUp";
|
|
874
|
+
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown)
|
|
875
|
+
keyName = "pageDown";
|
|
876
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.up)
|
|
877
|
+
keyName = "up";
|
|
878
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.down)
|
|
879
|
+
keyName = "down";
|
|
880
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.left)
|
|
881
|
+
keyName = "left";
|
|
882
|
+
else if (effectiveCodepoint === ARROW_CODEPOINTS.right)
|
|
883
|
+
keyName = "right";
|
|
884
|
+
else if (effectiveCodepoint >= 48 && effectiveCodepoint <= 57)
|
|
885
|
+
keyName = String.fromCharCode(effectiveCodepoint);
|
|
886
|
+
else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122)
|
|
887
|
+
keyName = String.fromCharCode(effectiveCodepoint);
|
|
888
|
+
else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint)))
|
|
889
|
+
keyName = String.fromCharCode(effectiveCodepoint);
|
|
890
|
+
if (!keyName)
|
|
891
|
+
return undefined;
|
|
892
|
+
return formatKeyNameWithModifiers(keyName, modifier);
|
|
893
|
+
}
|
|
810
894
|
export function parseKey(data) {
|
|
811
895
|
const kitty = parseKittySequence(data);
|
|
812
896
|
if (kitty) {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
return undefined;
|
|
819
|
-
if (effectiveMod & MODIFIERS.shift)
|
|
820
|
-
mods.push("shift");
|
|
821
|
-
if (effectiveMod & MODIFIERS.ctrl)
|
|
822
|
-
mods.push("ctrl");
|
|
823
|
-
if (effectiveMod & MODIFIERS.alt)
|
|
824
|
-
mods.push("alt");
|
|
825
|
-
// Use base layout key only when codepoint is not a recognized Latin
|
|
826
|
-
// letter (a-z) or symbol (/, -, [, ;, etc.). For those, the codepoint
|
|
827
|
-
// is authoritative regardless of physical key position. This prevents
|
|
828
|
-
// remapped layouts (Dvorak, Colemak, xremap, etc.) from reporting the
|
|
829
|
-
// wrong key name based on the QWERTY physical position.
|
|
830
|
-
const isLatinLetter = codepoint >= 97 && codepoint <= 122; // a-z
|
|
831
|
-
const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(codepoint));
|
|
832
|
-
const effectiveCodepoint = isLatinLetter || isKnownSymbol ? codepoint : (baseLayoutKey ?? codepoint);
|
|
833
|
-
let keyName;
|
|
834
|
-
if (effectiveCodepoint === CODEPOINTS.escape)
|
|
835
|
-
keyName = "escape";
|
|
836
|
-
else if (effectiveCodepoint === CODEPOINTS.tab)
|
|
837
|
-
keyName = "tab";
|
|
838
|
-
else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter)
|
|
839
|
-
keyName = "enter";
|
|
840
|
-
else if (effectiveCodepoint === CODEPOINTS.space)
|
|
841
|
-
keyName = "space";
|
|
842
|
-
else if (effectiveCodepoint === CODEPOINTS.backspace)
|
|
843
|
-
keyName = "backspace";
|
|
844
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete)
|
|
845
|
-
keyName = "delete";
|
|
846
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert)
|
|
847
|
-
keyName = "insert";
|
|
848
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home)
|
|
849
|
-
keyName = "home";
|
|
850
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end)
|
|
851
|
-
keyName = "end";
|
|
852
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp)
|
|
853
|
-
keyName = "pageUp";
|
|
854
|
-
else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown)
|
|
855
|
-
keyName = "pageDown";
|
|
856
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.up)
|
|
857
|
-
keyName = "up";
|
|
858
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.down)
|
|
859
|
-
keyName = "down";
|
|
860
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.left)
|
|
861
|
-
keyName = "left";
|
|
862
|
-
else if (effectiveCodepoint === ARROW_CODEPOINTS.right)
|
|
863
|
-
keyName = "right";
|
|
864
|
-
else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122)
|
|
865
|
-
keyName = String.fromCharCode(effectiveCodepoint);
|
|
866
|
-
else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint)))
|
|
867
|
-
keyName = String.fromCharCode(effectiveCodepoint);
|
|
868
|
-
if (keyName) {
|
|
869
|
-
return mods.length > 0 ? `${mods.join("+")}+${keyName}` : keyName;
|
|
870
|
-
}
|
|
897
|
+
return formatParsedKey(kitty.codepoint, kitty.modifier, kitty.baseLayoutKey);
|
|
898
|
+
}
|
|
899
|
+
const modifyOtherKeys = parseModifyOtherKeysSequence(data);
|
|
900
|
+
if (modifyOtherKeys) {
|
|
901
|
+
return formatParsedKey(modifyOtherKeys.codepoint, modifyOtherKeys.modifier);
|
|
871
902
|
}
|
|
872
903
|
// Mode-aware legacy sequences
|
|
873
904
|
// When Kitty protocol is active, ambiguous sequences are interpreted as custom terminal mappings:
|
|
@@ -924,8 +955,8 @@ export function parseKey(data) {
|
|
|
924
955
|
if (code >= 1 && code <= 26) {
|
|
925
956
|
return `ctrl+alt+${String.fromCharCode(code + 96)}`;
|
|
926
957
|
}
|
|
927
|
-
// Legacy alt+letter (ESC followed by
|
|
928
|
-
if (code >= 97 && code <= 122) {
|
|
958
|
+
// Legacy alt+letter/digit (ESC followed by the key)
|
|
959
|
+
if ((code >= 97 && code <= 122) || (code >= 48 && code <= 57)) {
|
|
929
960
|
return `alt+${String.fromCharCode(code)}`;
|
|
930
961
|
}
|
|
931
962
|
}
|