smolcoder 0.4.0

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.
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ // Hand-rolled terminal key decoder (zero deps). Parses VT escape sequences
3
+ // from raw-mode stdin, including bracketed paste so pasted newlines insert
4
+ // instead of submitting.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.KeyDecoder = void 0;
7
+ const CSI_MAP = {
8
+ A: "up",
9
+ B: "down",
10
+ C: "right",
11
+ D: "left",
12
+ H: "home",
13
+ F: "end",
14
+ Z: "shifttab",
15
+ "1~": "home",
16
+ "3~": "delete",
17
+ "4~": "end",
18
+ "7~": "home",
19
+ "8~": "end",
20
+ };
21
+ function normalizePaste(s) {
22
+ return s
23
+ .replace(/\r\n/g, "\n")
24
+ .replace(/\r/g, "\n")
25
+ // strip control chars except newline and tab
26
+ .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
27
+ }
28
+ class KeyDecoder {
29
+ pasteBuf = null;
30
+ decode(s) {
31
+ const out = [];
32
+ let i = 0;
33
+ while (i < s.length) {
34
+ // inside a bracketed paste: consume until the end marker
35
+ if (this.pasteBuf !== null) {
36
+ const end = s.indexOf("\x1b[201~", i);
37
+ if (end < 0) {
38
+ this.pasteBuf += s.slice(i);
39
+ return out;
40
+ }
41
+ this.pasteBuf += s.slice(i, end);
42
+ out.push({ type: "text", text: normalizePaste(this.pasteBuf) });
43
+ this.pasteBuf = null;
44
+ i = end + 6;
45
+ continue;
46
+ }
47
+ const ch = s[i];
48
+ if (ch === "\x1b") {
49
+ if (s.startsWith("\x1b[200~", i)) {
50
+ this.pasteBuf = "";
51
+ i += 6;
52
+ continue;
53
+ }
54
+ if (s[i + 1] === "[") {
55
+ let j = i + 2;
56
+ while (j < s.length && !(s[j] >= "@" && s[j] <= "~"))
57
+ j++;
58
+ if (j >= s.length)
59
+ break; // incomplete sequence — drop
60
+ const seq = s.slice(i + 2, j + 1);
61
+ const mapped = CSI_MAP[seq];
62
+ if (mapped)
63
+ out.push({ type: mapped });
64
+ i = j + 1;
65
+ continue;
66
+ }
67
+ if (s[i + 1] === "O" && i + 2 < s.length) {
68
+ const mapped = CSI_MAP[s[i + 2]];
69
+ if (mapped)
70
+ out.push({ type: mapped });
71
+ i += 3;
72
+ continue;
73
+ }
74
+ out.push({ type: "esc" });
75
+ i++;
76
+ continue;
77
+ }
78
+ const code = ch.charCodeAt(0);
79
+ if (ch === "\r" || ch === "\n") {
80
+ out.push({ type: "enter" });
81
+ i++;
82
+ continue;
83
+ }
84
+ if (ch === "\t") {
85
+ out.push({ type: "tab" });
86
+ i++;
87
+ continue;
88
+ }
89
+ if (code === 127 || code === 8) {
90
+ out.push({ type: "backspace" });
91
+ i++;
92
+ continue;
93
+ }
94
+ if (code === 3) {
95
+ out.push({ type: "ctrlc" });
96
+ i++;
97
+ continue;
98
+ }
99
+ if (code === 4) {
100
+ out.push({ type: "ctrld" });
101
+ i++;
102
+ continue;
103
+ }
104
+ if (code === 21) {
105
+ out.push({ type: "ctrlu" });
106
+ i++;
107
+ continue;
108
+ }
109
+ if (code === 23) {
110
+ out.push({ type: "ctrlw" });
111
+ i++;
112
+ continue;
113
+ }
114
+ if (code === 1) {
115
+ out.push({ type: "ctrla" });
116
+ i++;
117
+ continue;
118
+ }
119
+ if (code === 5) {
120
+ out.push({ type: "ctrle" });
121
+ i++;
122
+ continue;
123
+ }
124
+ if (code < 32) {
125
+ i++;
126
+ continue;
127
+ } // other control chars: ignore
128
+ // printable run (single keystroke or unbracketed paste)
129
+ let j = i;
130
+ let run = "";
131
+ while (j < s.length) {
132
+ const cj = s[j];
133
+ const cc = cj.charCodeAt(0);
134
+ if (cj === "\x1b" || cj === "\r" || cj === "\n" || cj === "\t" || cc < 32 || cc === 127)
135
+ break;
136
+ run += cj;
137
+ j++;
138
+ }
139
+ out.push(run.length === 1 ? { type: "char", text: run } : { type: "text", text: run });
140
+ i = j;
141
+ }
142
+ return out;
143
+ }
144
+ }
145
+ exports.KeyDecoder = KeyDecoder;