thebird 1.2.55 → 1.2.57
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/docs/preview-sw.js +1 -1
- package/docs/shell-readline.js +130 -0
- package/docs/shell.js +21 -17
- package/package.json +1 -1
package/docs/preview-sw.js
CHANGED
|
@@ -44,7 +44,7 @@ async function handlePreview(key, request) {
|
|
|
44
44
|
const db = await openIDB();
|
|
45
45
|
const fs = await getFS(db);
|
|
46
46
|
if (key in fs) return new Response(fs[key], { status: 200, headers: { 'Content-Type': getMime(key) } });
|
|
47
|
-
const clients = await self.clients.matchAll({ type: 'window' });
|
|
47
|
+
const clients = await self.clients.matchAll({ type: 'window', includeUncontrolled: true });
|
|
48
48
|
if (!clients.length) return new Response('not found: ' + key, { status: 404 });
|
|
49
49
|
const { port1, port2 } = new MessageChannel();
|
|
50
50
|
const result = await new Promise((res, rej) => {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export function createReadline({ term, getCompletions, onLine, getPrompt }) {
|
|
2
|
+
let buf = '';
|
|
3
|
+
let pos = 0;
|
|
4
|
+
let histIdx = -1;
|
|
5
|
+
let escBuf = '';
|
|
6
|
+
let inEsc = false;
|
|
7
|
+
|
|
8
|
+
const write = s => term.write(s);
|
|
9
|
+
|
|
10
|
+
function promptStr() { return '\r\n\x1b[32m' + getPrompt() + ' $ \x1b[0m'; }
|
|
11
|
+
function showPrompt() { write(promptStr()); }
|
|
12
|
+
|
|
13
|
+
function redraw() {
|
|
14
|
+
write('\r\x1b[2K\x1b[32m' + getPrompt() + ' $ \x1b[0m' + buf);
|
|
15
|
+
if (pos < buf.length) write('\x1b[' + (buf.length - pos) + 'D');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function insert(ch) {
|
|
19
|
+
buf = buf.slice(0, pos) + ch + buf.slice(pos);
|
|
20
|
+
pos++;
|
|
21
|
+
redraw();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function delBefore() {
|
|
25
|
+
if (!pos) return;
|
|
26
|
+
buf = buf.slice(0, pos - 1) + buf.slice(pos);
|
|
27
|
+
pos--;
|
|
28
|
+
redraw();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function delAfter() {
|
|
32
|
+
if (pos >= buf.length) return;
|
|
33
|
+
buf = buf.slice(0, pos) + buf.slice(pos + 1);
|
|
34
|
+
redraw();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function moveTo(n) {
|
|
38
|
+
pos = Math.max(0, Math.min(buf.length, n));
|
|
39
|
+
const pLen = getPrompt().length + 3;
|
|
40
|
+
if (pLen + pos > 0) write('\r\x1b[' + (pLen + pos) + 'C');
|
|
41
|
+
else write('\r');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function handleTab() {
|
|
45
|
+
const word = buf.slice(0, pos).split(/\s+/).pop() || '';
|
|
46
|
+
const completions = getCompletions(buf, word);
|
|
47
|
+
if (!completions.length) return;
|
|
48
|
+
if (completions.length === 1) {
|
|
49
|
+
const rest = completions[0].slice(word.length);
|
|
50
|
+
buf = buf.slice(0, pos) + rest + buf.slice(pos);
|
|
51
|
+
pos += rest.length;
|
|
52
|
+
redraw();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const common = completions.reduce((a, b) => {
|
|
56
|
+
let i = 0;
|
|
57
|
+
while (i < a.length && a[i] === b[i]) i++;
|
|
58
|
+
return a.slice(0, i);
|
|
59
|
+
});
|
|
60
|
+
if (common.length > word.length) {
|
|
61
|
+
const rest = common.slice(word.length);
|
|
62
|
+
buf = buf.slice(0, pos) + rest + buf.slice(pos);
|
|
63
|
+
pos += rest.length;
|
|
64
|
+
redraw();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
write('\r\n' + completions.join(' '));
|
|
68
|
+
redraw();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function commit() {
|
|
72
|
+
const line = buf;
|
|
73
|
+
write('\r\n');
|
|
74
|
+
const hist = getHistory();
|
|
75
|
+
if (line.trim()) hist.unshift(line);
|
|
76
|
+
buf = '';
|
|
77
|
+
pos = 0;
|
|
78
|
+
histIdx = -1;
|
|
79
|
+
onLine(line);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getHistory() { return window.__debug?.shell?.history || []; }
|
|
83
|
+
|
|
84
|
+
function histNav(dir) {
|
|
85
|
+
const hist = getHistory();
|
|
86
|
+
if (!hist.length) return;
|
|
87
|
+
histIdx = Math.max(-1, Math.min(hist.length - 1, histIdx + dir));
|
|
88
|
+
buf = histIdx === -1 ? '' : hist[histIdx];
|
|
89
|
+
pos = buf.length;
|
|
90
|
+
redraw();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const ESC_MAP = {
|
|
94
|
+
'[A': () => histNav(1),
|
|
95
|
+
'[B': () => histNav(-1),
|
|
96
|
+
'[C': () => { if (pos < buf.length) { pos++; write('\x1b[C'); } },
|
|
97
|
+
'[D': () => { if (pos > 0) { pos--; write('\x1b[D'); } },
|
|
98
|
+
'[H': () => moveTo(0),
|
|
99
|
+
'[F': () => moveTo(buf.length),
|
|
100
|
+
'[3~': () => delAfter(),
|
|
101
|
+
'[1~': () => moveTo(0),
|
|
102
|
+
'[4~': () => moveTo(buf.length),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
function onData(data) {
|
|
106
|
+
if (inEsc) {
|
|
107
|
+
escBuf += data;
|
|
108
|
+
if (escBuf === '[') return;
|
|
109
|
+
if (escBuf.match(/^\[[\x40-\x7E]$/) || escBuf.match(/^\[\d+~$/)) {
|
|
110
|
+
const handler = ESC_MAP[escBuf];
|
|
111
|
+
if (handler) handler();
|
|
112
|
+
inEsc = false; escBuf = '';
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (escBuf.length > 6) { inEsc = false; escBuf = ''; }
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (data === '\x1b') { inEsc = true; escBuf = ''; return; }
|
|
119
|
+
if (data === '\x01') { moveTo(0); return; }
|
|
120
|
+
if (data === '\x05') { moveTo(buf.length); return; }
|
|
121
|
+
if (data === '\x0b') { buf = buf.slice(0, pos); redraw(); return; }
|
|
122
|
+
if (data === '\x15') { buf = buf.slice(pos); pos = 0; redraw(); return; }
|
|
123
|
+
if (data === '\x09') { handleTab(); return; }
|
|
124
|
+
if (data === '\r') { commit(); return; }
|
|
125
|
+
if (data === '\x7f') { delBefore(); return; }
|
|
126
|
+
if (data >= ' ') { insert(data); return; }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { onData, showPrompt };
|
|
130
|
+
}
|
package/docs/shell.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createMachine, createActor } from './vendor/xstate.js';
|
|
2
2
|
import { createNodeEnv } from './shell-node.js';
|
|
3
|
+
import { createReadline } from './shell-readline.js';
|
|
3
4
|
|
|
4
5
|
function resolvePath(cwd, p) {
|
|
5
6
|
if (!p || p === '~') return '/';
|
|
@@ -134,7 +135,6 @@ export function createShell({ term, onPreviewWrite }) {
|
|
|
134
135
|
|
|
135
136
|
async function run(line, onData) {
|
|
136
137
|
if (!line.trim()) return;
|
|
137
|
-
ctx.history.push(line);
|
|
138
138
|
const st = actor.getSnapshot().value;
|
|
139
139
|
if (st === 'node-repl' && line.trim() !== 'exit') { await ctx.nodeEval(line); return; }
|
|
140
140
|
if (line.trim() === 'exit') { BUILTINS.exit(actor); return; }
|
|
@@ -162,16 +162,30 @@ export function createShell({ term, onPreviewWrite }) {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
function getCompletions(line, word) {
|
|
166
|
+
const snap = window.__debug.idbSnapshot || {};
|
|
167
|
+
const files = Object.keys(snap);
|
|
168
|
+
const tokens = line.trim().split(/\s+/);
|
|
169
|
+
if (tokens.length <= 1 && !line.includes(' ')) {
|
|
170
|
+
const cmds = Object.keys(BUILTINS);
|
|
171
|
+
return cmds.filter(c => c.startsWith(word));
|
|
172
|
+
}
|
|
173
|
+
return files.filter(f => f.startsWith(word));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const rl = createReadline({
|
|
177
|
+
term,
|
|
178
|
+
getCompletions,
|
|
179
|
+
getPrompt: () => ctx.cwd,
|
|
180
|
+
onLine: line => run(line, onData).then(() => rl.showPrompt()),
|
|
181
|
+
});
|
|
167
182
|
|
|
168
183
|
function onData(data) {
|
|
169
184
|
if (data === '\x03') {
|
|
170
185
|
actor.send({ type: 'ERROR' });
|
|
171
186
|
inputQueue = [];
|
|
172
|
-
buf = '';
|
|
173
187
|
term.write('^C');
|
|
174
|
-
|
|
188
|
+
rl.showPrompt();
|
|
175
189
|
return;
|
|
176
190
|
}
|
|
177
191
|
const st = actor.getSnapshot().value;
|
|
@@ -179,23 +193,13 @@ export function createShell({ term, onPreviewWrite }) {
|
|
|
179
193
|
inputQueue.push(data);
|
|
180
194
|
return;
|
|
181
195
|
}
|
|
182
|
-
|
|
183
|
-
term.write('\r\n');
|
|
184
|
-
const line = buf;
|
|
185
|
-
buf = '';
|
|
186
|
-
run(line, onData).then(() => prompt());
|
|
187
|
-
} else if (data === '\x7f') {
|
|
188
|
-
if (buf.length) { buf = buf.slice(0, -1); term.write('\x08 \x08'); }
|
|
189
|
-
} else {
|
|
190
|
-
buf += data;
|
|
191
|
-
term.write(data);
|
|
192
|
-
}
|
|
196
|
+
rl.onData(data);
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
term.onData(onData);
|
|
196
200
|
onPreviewWrite && (window.__debug.shell.onPreviewWrite = onPreviewWrite);
|
|
197
201
|
const runPublic = line => run(line, onData);
|
|
198
202
|
window.__debug.shell.run = runPublic;
|
|
199
|
-
|
|
203
|
+
rl.showPrompt();
|
|
200
204
|
return { run: runPublic };
|
|
201
205
|
}
|
package/package.json
CHANGED