termbeam 1.24.10 → 1.24.11
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/CHANGELOG.md +4 -0
- package/package.json +1 -1
- package/src/cli/prompts.js +53 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.24.11] - 2026-07-08
|
|
4
|
+
|
|
5
|
+
- fix(cli): handle split and coalesced key input in choose() arrow navigation (@dorlugasigal)
|
|
6
|
+
|
|
3
7
|
## [1.24.10] - 2026-07-07
|
|
4
8
|
|
|
5
9
|
- feat(ci): autonomous Dependabot auto-fix and auto-merge workflows (#263) (@dorlugasigal)
|
package/package.json
CHANGED
package/src/cli/prompts.js
CHANGED
|
@@ -74,24 +74,60 @@ function choose(rl, question, choices, defaultIndex = 0) {
|
|
|
74
74
|
}
|
|
75
75
|
process.stdin.resume();
|
|
76
76
|
|
|
77
|
+
// Bytes arrive as a raw stream: a single keypress may be split across
|
|
78
|
+
// multiple 'data' events, and several keypresses may be coalesced into one
|
|
79
|
+
// (common when keys are pressed quickly). Buffer the stream and consume one
|
|
80
|
+
// recognized token at a time so navigation never silently drops keys.
|
|
81
|
+
let pending = Buffer.alloc(0);
|
|
82
|
+
|
|
83
|
+
function moveUp() {
|
|
84
|
+
selected = (selected - 1 + items.length) % items.length;
|
|
85
|
+
render(true);
|
|
86
|
+
}
|
|
87
|
+
function moveDown() {
|
|
88
|
+
selected = (selected + 1) % items.length;
|
|
89
|
+
render(true);
|
|
90
|
+
}
|
|
91
|
+
|
|
77
92
|
function onKey(buf) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
pending = pending.length ? Buffer.concat([pending, buf]) : buf;
|
|
94
|
+
|
|
95
|
+
while (pending.length > 0) {
|
|
96
|
+
const b = pending[0];
|
|
97
|
+
|
|
98
|
+
if (b === 0x1b) {
|
|
99
|
+
// Escape sequence — need at least ESC '[' <code> to interpret.
|
|
100
|
+
if (pending.length < 2) return; // wait for more bytes
|
|
101
|
+
if (pending[1] === 0x5b /* [ */) {
|
|
102
|
+
if (pending.length < 3) return; // wait for the final byte
|
|
103
|
+
const code = pending[2];
|
|
104
|
+
if (code === 0x41 /* A */) moveUp();
|
|
105
|
+
else if (code === 0x42 /* B */) moveDown();
|
|
106
|
+
// Ignore other CSI sequences (left/right/home/etc.)
|
|
107
|
+
pending = pending.subarray(3);
|
|
108
|
+
} else {
|
|
109
|
+
// Lone ESC or unsupported sequence — drop the ESC and continue.
|
|
110
|
+
pending = pending.subarray(1);
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (b === 0x0d /* \r */ || b === 0x0a /* \n */) {
|
|
116
|
+
cleanup();
|
|
117
|
+
process.stdout.write('\r\x1b[K\n');
|
|
118
|
+
console.log(dim(` Selected: ${items[selected].label}`));
|
|
119
|
+
resolve({ index: selected, value: items[selected].label });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (b === 0x03 /* Ctrl-C */) {
|
|
123
|
+
cleanup();
|
|
124
|
+
process.stdout.write('\x1b[?1049l');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
if (b === 0x6b /* k */) moveUp();
|
|
128
|
+
else if (b === 0x6a /* j */) moveDown();
|
|
129
|
+
// Any other byte is ignored.
|
|
130
|
+
pending = pending.subarray(1);
|
|
95
131
|
}
|
|
96
132
|
}
|
|
97
133
|
|