@zenfs/core 1.11.3 → 2.0.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.
- package/dist/backends/backend.d.ts +19 -15
- package/dist/backends/backend.js +31 -15
- package/dist/backends/cow.d.ts +20 -30
- package/dist/backends/cow.js +52 -142
- package/dist/backends/fetch.d.ts +1 -0
- package/dist/backends/fetch.js +3 -1
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.js +1 -1
- package/dist/backends/memory.d.ts +5 -7
- package/dist/backends/memory.js +2 -3
- package/dist/backends/passthrough.d.ts +19 -22
- package/dist/backends/passthrough.js +85 -160
- package/dist/backends/port.d.ts +207 -0
- package/dist/backends/port.js +297 -0
- package/dist/backends/single_buffer.d.ts +11 -5
- package/dist/backends/single_buffer.js +18 -12
- package/dist/backends/store/fs.d.ts +11 -27
- package/dist/backends/store/fs.js +67 -91
- package/dist/backends/store/store.d.ts +7 -12
- package/dist/config.d.ts +1 -10
- package/dist/config.js +7 -8
- package/dist/context.d.ts +8 -21
- package/dist/context.js +33 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/contexts.d.ts +63 -0
- package/dist/internal/contexts.js +15 -0
- package/dist/internal/credentials.d.ts +2 -11
- package/dist/internal/credentials.js +0 -19
- package/dist/internal/devices.d.ts +18 -80
- package/dist/internal/devices.js +76 -279
- package/dist/internal/file_index.js +3 -3
- package/dist/internal/filesystem.d.ts +31 -89
- package/dist/internal/filesystem.js +21 -20
- package/dist/internal/index.d.ts +0 -1
- package/dist/internal/index.js +0 -1
- package/dist/internal/index_fs.d.ts +12 -30
- package/dist/internal/index_fs.js +23 -55
- package/dist/internal/inode.d.ts +147 -9
- package/dist/internal/inode.js +333 -25
- package/dist/internal/log.d.ts +19 -13
- package/dist/internal/log.js +81 -80
- package/dist/mixins/async.js +26 -90
- package/dist/mixins/mutexed.d.ts +17 -16
- package/dist/mixins/mutexed.js +29 -31
- package/dist/mixins/readonly.d.ts +7 -6
- package/dist/mixins/readonly.js +6 -0
- package/dist/mixins/sync.js +8 -8
- package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
- package/dist/{vfs/path.js → path.js} +6 -9
- package/dist/readline.d.ts +134 -0
- package/dist/readline.js +623 -0
- package/dist/utils.d.ts +4 -35
- package/dist/utils.js +8 -73
- package/dist/vfs/acl.d.ts +42 -0
- package/dist/vfs/acl.js +249 -0
- package/dist/vfs/async.d.ts +7 -21
- package/dist/vfs/async.js +19 -19
- package/dist/vfs/config.d.ts +6 -18
- package/dist/vfs/config.js +8 -18
- package/dist/vfs/dir.d.ts +3 -3
- package/dist/vfs/dir.js +9 -8
- package/dist/vfs/file.d.ts +106 -0
- package/dist/vfs/file.js +235 -0
- package/dist/vfs/flags.d.ts +19 -0
- package/dist/vfs/flags.js +62 -0
- package/dist/vfs/index.d.ts +4 -10
- package/dist/vfs/index.js +4 -13
- package/dist/vfs/ioctl.d.ts +87 -0
- package/dist/vfs/ioctl.js +304 -0
- package/dist/vfs/promises.d.ts +78 -16
- package/dist/vfs/promises.js +273 -122
- package/dist/vfs/shared.d.ts +7 -26
- package/dist/vfs/shared.js +25 -53
- package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
- package/dist/{stats.js → vfs/stats.js} +11 -66
- package/dist/vfs/streams.d.ts +1 -0
- package/dist/vfs/streams.js +24 -19
- package/dist/vfs/sync.d.ts +4 -3
- package/dist/vfs/sync.js +143 -128
- package/dist/vfs/watchers.d.ts +2 -2
- package/dist/vfs/watchers.js +6 -6
- package/dist/vfs/xattr.d.ts +116 -0
- package/dist/vfs/xattr.js +218 -0
- package/package.json +3 -3
- package/readme.md +1 -1
- package/tests/backend/config.worker.js +4 -1
- package/tests/backend/fetch.test.ts +3 -0
- package/tests/backend/port.test.ts +21 -35
- package/tests/backend/remote.worker.js +4 -1
- package/tests/backend/single-buffer.test.ts +24 -0
- package/tests/common/context.test.ts +1 -1
- package/tests/common/handle.test.ts +17 -12
- package/tests/common/path.test.ts +1 -1
- package/tests/common/readline.test.ts +104 -0
- package/tests/common.ts +4 -19
- package/tests/fetch/fetch.ts +1 -1
- package/tests/fs/links.test.ts +1 -1
- package/tests/fs/permissions.test.ts +7 -6
- package/tests/fs/readFile.test.ts +3 -3
- package/tests/fs/stat.test.ts +6 -6
- package/tests/fs/streams.test.ts +2 -11
- package/tests/fs/times.test.ts +1 -1
- package/tests/fs/xattr.test.ts +85 -0
- package/tests/logs.js +22 -0
- package/tests/setup/context.ts +1 -1
- package/tests/setup/index.ts +3 -3
- package/tests/setup/port.ts +1 -1
- package/dist/backends/port/fs.d.ts +0 -84
- package/dist/backends/port/fs.js +0 -151
- package/dist/backends/port/rpc.d.ts +0 -77
- package/dist/backends/port/rpc.js +0 -100
- package/dist/backends/store/simple.d.ts +0 -20
- package/dist/backends/store/simple.js +0 -13
- package/dist/internal/file.d.ts +0 -351
- package/dist/internal/file.js +0 -739
package/dist/readline.js
ADDED
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
// A cross-platform node:readline implementation
|
|
3
|
+
import { EventEmitter } from 'eventemitter3';
|
|
4
|
+
import { warn } from './internal/log.js';
|
|
5
|
+
export class Interface extends EventEmitter {
|
|
6
|
+
get cursor() {
|
|
7
|
+
return this._cursor;
|
|
8
|
+
}
|
|
9
|
+
constructor(input, output, completer, terminal = false) {
|
|
10
|
+
super();
|
|
11
|
+
this.input = input;
|
|
12
|
+
this.output = output;
|
|
13
|
+
this.terminal = terminal;
|
|
14
|
+
this.line = '';
|
|
15
|
+
this._cursor = 0;
|
|
16
|
+
this._buffer = '';
|
|
17
|
+
this._closed = false;
|
|
18
|
+
this._paused = false;
|
|
19
|
+
this._prompt = '';
|
|
20
|
+
this._history = [];
|
|
21
|
+
this._historyIndex = -1;
|
|
22
|
+
this._currentLine = '';
|
|
23
|
+
this._onData = (data) => {
|
|
24
|
+
if (this._paused || this._closed)
|
|
25
|
+
return;
|
|
26
|
+
this._buffer += typeof data === 'string' ? data : data.toString('utf8');
|
|
27
|
+
for (let lineEnd = this._buffer.indexOf('\n'); lineEnd >= 0; lineEnd = this._buffer.indexOf('\n')) {
|
|
28
|
+
let line = this._buffer.substring(0, lineEnd);
|
|
29
|
+
if (line.endsWith('\r')) {
|
|
30
|
+
line = line.substring(0, line.length - 1);
|
|
31
|
+
}
|
|
32
|
+
this._buffer = this._buffer.substring(lineEnd + 1);
|
|
33
|
+
this.line = line;
|
|
34
|
+
if (line.trim() && !line.trim().match(/^\s*$/) && this._history.at(-1) != line) {
|
|
35
|
+
this._history.push(line);
|
|
36
|
+
this._historyIndex = this._history.length;
|
|
37
|
+
this.emit('history', this._history);
|
|
38
|
+
}
|
|
39
|
+
this.emit('line', line);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
this.input.on('data', this._onData);
|
|
43
|
+
this.input.on('end', this.close.bind(this));
|
|
44
|
+
this.input.on('close', this.close.bind(this));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Closes the interface and removes all event listeners
|
|
48
|
+
*/
|
|
49
|
+
close() {
|
|
50
|
+
var _a, _b;
|
|
51
|
+
if (this._closed)
|
|
52
|
+
return;
|
|
53
|
+
this._closed = true;
|
|
54
|
+
(_b = (_a = this.input) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
55
|
+
if (this._buffer.length) {
|
|
56
|
+
const line = this._buffer;
|
|
57
|
+
this._buffer = '';
|
|
58
|
+
this.line = line;
|
|
59
|
+
this.emit('line', line);
|
|
60
|
+
}
|
|
61
|
+
this.emit('history', this._history);
|
|
62
|
+
this.emit('close');
|
|
63
|
+
this.removeAllListeners();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Pauses the input stream
|
|
67
|
+
*/
|
|
68
|
+
pause() {
|
|
69
|
+
if (this._paused)
|
|
70
|
+
return this;
|
|
71
|
+
this._paused = true;
|
|
72
|
+
if ('pause' in this.input)
|
|
73
|
+
this.input.pause();
|
|
74
|
+
this.emit('pause');
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resumes the input stream
|
|
79
|
+
*/
|
|
80
|
+
resume() {
|
|
81
|
+
if (!this._paused)
|
|
82
|
+
return this;
|
|
83
|
+
this._paused = false;
|
|
84
|
+
if ('resume' in this.input)
|
|
85
|
+
this.input.resume();
|
|
86
|
+
this.emit('resume');
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Sets the prompt text
|
|
91
|
+
*/
|
|
92
|
+
setPrompt(prompt) {
|
|
93
|
+
this._prompt = prompt;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Gets the current prompt text
|
|
97
|
+
*/
|
|
98
|
+
getPrompt() {
|
|
99
|
+
return this._prompt;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Displays the prompt to the user
|
|
103
|
+
*/
|
|
104
|
+
prompt(preserveCursor) {
|
|
105
|
+
if (!this.output)
|
|
106
|
+
return;
|
|
107
|
+
if (!preserveCursor) {
|
|
108
|
+
this.output.write(this._prompt);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const { cols } = this.getCursorPos();
|
|
112
|
+
this.output.write(this._prompt);
|
|
113
|
+
this._cursor = cols;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Writes data to the interface and handles key events
|
|
117
|
+
*/
|
|
118
|
+
write(data, key) {
|
|
119
|
+
if (this._closed)
|
|
120
|
+
return;
|
|
121
|
+
if (data) {
|
|
122
|
+
const str = typeof data === 'string' ? data : data.toString('utf8');
|
|
123
|
+
this._onData(str);
|
|
124
|
+
}
|
|
125
|
+
if (!key || !this.terminal)
|
|
126
|
+
return;
|
|
127
|
+
switch ((key.ctrl ? '^' : '') + key.name) {
|
|
128
|
+
case '^c':
|
|
129
|
+
this.emit('SIGINT');
|
|
130
|
+
break;
|
|
131
|
+
case '^z':
|
|
132
|
+
this.emit('SIGTSTP');
|
|
133
|
+
break;
|
|
134
|
+
case '^q':
|
|
135
|
+
this.emit('SIGCONT');
|
|
136
|
+
break;
|
|
137
|
+
case 'home':
|
|
138
|
+
case '^a':
|
|
139
|
+
if (!this.output)
|
|
140
|
+
return;
|
|
141
|
+
moveCursor(this.output, -this._cursor, 0);
|
|
142
|
+
this._cursor = 0;
|
|
143
|
+
this._cursor = 0;
|
|
144
|
+
break;
|
|
145
|
+
case '^e':
|
|
146
|
+
case 'end': {
|
|
147
|
+
if (!this.output)
|
|
148
|
+
return;
|
|
149
|
+
const dx = this.line.length - this._cursor;
|
|
150
|
+
if (!dx)
|
|
151
|
+
return;
|
|
152
|
+
moveCursor(this.output, dx, 0);
|
|
153
|
+
this._cursor = this.line.length;
|
|
154
|
+
this._cursor = this.line.length;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case '^k': {
|
|
158
|
+
if (!this.output)
|
|
159
|
+
return;
|
|
160
|
+
if (this._cursor >= this.line.length)
|
|
161
|
+
return;
|
|
162
|
+
const newLine = this.line.slice(0, this._cursor);
|
|
163
|
+
clearLine(this.output, 1);
|
|
164
|
+
this.line = newLine;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
case '^u': {
|
|
168
|
+
if (!this.output || !this._cursor)
|
|
169
|
+
return;
|
|
170
|
+
const newLine = this.line.slice(this._cursor);
|
|
171
|
+
clearLine(this.output, 0);
|
|
172
|
+
moveCursor(this.output, 0, 0);
|
|
173
|
+
this.output.write(this._prompt + newLine);
|
|
174
|
+
this.line = newLine;
|
|
175
|
+
this._cursor = 0;
|
|
176
|
+
this._cursor = 0;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case '^w': {
|
|
180
|
+
if (!this.output || !this._cursor)
|
|
181
|
+
return;
|
|
182
|
+
let i = this._cursor - 1;
|
|
183
|
+
while (i >= 0 && this.line[i] === ' ')
|
|
184
|
+
i--;
|
|
185
|
+
while (i >= 0 && this.line[i] !== ' ')
|
|
186
|
+
i--;
|
|
187
|
+
const newLine = this.line.slice(0, i + 1) + this.line.slice(this._cursor);
|
|
188
|
+
const newCursorPos = i + 1;
|
|
189
|
+
this._renderLine(newLine);
|
|
190
|
+
this._cursor = newCursorPos;
|
|
191
|
+
this._cursor = newCursorPos;
|
|
192
|
+
moveCursor(this.output, -newLine.length, 0);
|
|
193
|
+
moveCursor(this.output, newCursorPos, 0);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case '^return':
|
|
197
|
+
case '^enter':
|
|
198
|
+
this._onData('\n');
|
|
199
|
+
break;
|
|
200
|
+
case 'return':
|
|
201
|
+
case 'enter':
|
|
202
|
+
this._onData((!data ? '' : typeof data == 'string' ? data : data.toString('utf8')) + '\n');
|
|
203
|
+
break;
|
|
204
|
+
case 'up':
|
|
205
|
+
case 'down': {
|
|
206
|
+
if (!this.output || !this._history.length)
|
|
207
|
+
return;
|
|
208
|
+
if (this._historyIndex === this._history.length) {
|
|
209
|
+
this._currentLine = this.line || '';
|
|
210
|
+
}
|
|
211
|
+
if (key.name == 'up' && this._historyIndex > 0) {
|
|
212
|
+
this._historyIndex--;
|
|
213
|
+
}
|
|
214
|
+
else if (key.name == 'down' && this._historyIndex < this._history.length - 1) {
|
|
215
|
+
this._historyIndex++;
|
|
216
|
+
}
|
|
217
|
+
else if (key.name == 'down' && this._historyIndex == this._history.length - 1) {
|
|
218
|
+
this._historyIndex = this._history.length;
|
|
219
|
+
this._renderLine(this._currentLine);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const historyItem = this._history[this._historyIndex];
|
|
226
|
+
this._renderLine(historyItem);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
case 'left':
|
|
230
|
+
case 'right': {
|
|
231
|
+
const dx = key.name == 'left' ? -1 : 1;
|
|
232
|
+
if (!this.output)
|
|
233
|
+
return;
|
|
234
|
+
const newPos = Math.max(0, Math.min(this.line.length, this._cursor + dx));
|
|
235
|
+
if (newPos == this._cursor)
|
|
236
|
+
return;
|
|
237
|
+
moveCursor(this.output, dx, 0);
|
|
238
|
+
this._cursor = newPos;
|
|
239
|
+
this._cursor = newPos;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
case 'backspace': {
|
|
243
|
+
if (!this.output || !this._cursor)
|
|
244
|
+
return;
|
|
245
|
+
const newLine = this.line.slice(0, this._cursor - 1) + this.line.slice(this._cursor);
|
|
246
|
+
this._renderLine(newLine);
|
|
247
|
+
this._cursor = --this._cursor;
|
|
248
|
+
if (this._cursor > 0) {
|
|
249
|
+
moveCursor(this.output, -this._cursor, 0);
|
|
250
|
+
moveCursor(this.output, this._cursor, 0);
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
case 'delete': {
|
|
255
|
+
if (!this.output)
|
|
256
|
+
return;
|
|
257
|
+
if (this._cursor >= this.line.length)
|
|
258
|
+
return;
|
|
259
|
+
const newLine = this.line.slice(0, this._cursor) + this.line.slice(this._cursor + 1);
|
|
260
|
+
clearLine(this.output, 0);
|
|
261
|
+
moveCursor(this.output, 0, 0);
|
|
262
|
+
this.output.write(this._prompt + newLine);
|
|
263
|
+
this.line = newLine;
|
|
264
|
+
moveCursor(this.output, -newLine.length, 0);
|
|
265
|
+
moveCursor(this.output, this._cursor, 0);
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
_renderLine(text) {
|
|
271
|
+
if (!this.output)
|
|
272
|
+
return;
|
|
273
|
+
clearLine(this.output, 0);
|
|
274
|
+
moveCursor(this.output, 0, 0);
|
|
275
|
+
this.output.write(this._prompt + text);
|
|
276
|
+
this.line = text;
|
|
277
|
+
this._cursor = text.length;
|
|
278
|
+
this._cursor = text.length;
|
|
279
|
+
}
|
|
280
|
+
question(query, optionsOrCallback, maybeCallback) {
|
|
281
|
+
const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : maybeCallback;
|
|
282
|
+
if (this._closed || !this.output) {
|
|
283
|
+
callback('');
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
this.output.write(query);
|
|
287
|
+
this.once('line', callback);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Gets the current cursor position
|
|
291
|
+
*/
|
|
292
|
+
getCursorPos() {
|
|
293
|
+
return { rows: 0, cols: this.cursor };
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Prepends a listener for the specified event
|
|
297
|
+
*/
|
|
298
|
+
prependListener(event, listener) {
|
|
299
|
+
const listeners = this.listeners(event);
|
|
300
|
+
this.removeAllListeners(event);
|
|
301
|
+
this.on(event, listener);
|
|
302
|
+
listeners.forEach(this.on.bind(this, event));
|
|
303
|
+
return this;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Prepends a one-time listener for the specified event
|
|
307
|
+
*/
|
|
308
|
+
prependOnceListener(event, listener) {
|
|
309
|
+
const listeners = this.listeners(event);
|
|
310
|
+
this.removeAllListeners(event);
|
|
311
|
+
this.once(event, listener);
|
|
312
|
+
listeners.forEach(this.on.bind(this, event));
|
|
313
|
+
return this;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Sets the maximum number of listeners
|
|
317
|
+
*/
|
|
318
|
+
setMaxListeners() {
|
|
319
|
+
warn('Interface.prototype.setMaxListeners is not supported');
|
|
320
|
+
return this;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Gets the maximum number of listeners
|
|
324
|
+
*/
|
|
325
|
+
getMaxListeners() {
|
|
326
|
+
warn('Interface.prototype.getMaxListeners is not supported');
|
|
327
|
+
return 10;
|
|
328
|
+
}
|
|
329
|
+
[Symbol.asyncIterator]() {
|
|
330
|
+
let done = false;
|
|
331
|
+
return {
|
|
332
|
+
next: async () => {
|
|
333
|
+
if (done)
|
|
334
|
+
return { done, value: undefined };
|
|
335
|
+
const { resolve, promise } = Promise.withResolvers();
|
|
336
|
+
this.once('line', (line) => resolve({ value: line, done: false }));
|
|
337
|
+
this.once('close', () => {
|
|
338
|
+
done = true;
|
|
339
|
+
resolve({ value: undefined, done });
|
|
340
|
+
});
|
|
341
|
+
return promise;
|
|
342
|
+
},
|
|
343
|
+
return: async (value) => {
|
|
344
|
+
if (done)
|
|
345
|
+
return { done, value };
|
|
346
|
+
done = true;
|
|
347
|
+
this.close();
|
|
348
|
+
return { done, value };
|
|
349
|
+
},
|
|
350
|
+
throw: async (error) => {
|
|
351
|
+
if (!done) {
|
|
352
|
+
done = true;
|
|
353
|
+
this.close();
|
|
354
|
+
}
|
|
355
|
+
throw error;
|
|
356
|
+
},
|
|
357
|
+
[Symbol.asyncIterator]() {
|
|
358
|
+
return this;
|
|
359
|
+
},
|
|
360
|
+
[Symbol.asyncDispose]: async () => {
|
|
361
|
+
if (done)
|
|
362
|
+
return;
|
|
363
|
+
done = true;
|
|
364
|
+
this.close();
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
async [Symbol.asyncDispose]() {
|
|
369
|
+
if (this._closed)
|
|
370
|
+
return;
|
|
371
|
+
const { resolve, promise } = Promise.withResolvers();
|
|
372
|
+
this.once('close', () => resolve());
|
|
373
|
+
this.close();
|
|
374
|
+
await promise;
|
|
375
|
+
}
|
|
376
|
+
rawListeners(event) {
|
|
377
|
+
return this.listeners(event);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
export function createInterface(input, output, completer, terminal) {
|
|
381
|
+
return 'input' in input
|
|
382
|
+
? new Interface(input.input, input.output, input.completer, input.terminal)
|
|
383
|
+
: new Interface(input, output, completer, terminal);
|
|
384
|
+
}
|
|
385
|
+
createInterface;
|
|
386
|
+
/**
|
|
387
|
+
* Clear the current line in the terminal
|
|
388
|
+
* @param stream The stream to clear the line on
|
|
389
|
+
* @param dir The direction to clear: -1 for left, 1 for right, 0 for entire line
|
|
390
|
+
*/
|
|
391
|
+
export function clearLine(stream, dir) {
|
|
392
|
+
stream.write(dir >= 0 ? '\r\x1b[K' : '\x1b[K');
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
clearLine;
|
|
396
|
+
/**
|
|
397
|
+
* Clear the screen down from the current position
|
|
398
|
+
* @param stream The stream to clear the screen on
|
|
399
|
+
*/
|
|
400
|
+
export function clearScreenDown(stream) {
|
|
401
|
+
if (!stream.write)
|
|
402
|
+
return false;
|
|
403
|
+
stream.write('\x1b[J');
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
clearScreenDown;
|
|
407
|
+
/**
|
|
408
|
+
* Move the cursor in the terminal
|
|
409
|
+
* @param stream The stream to move the cursor on
|
|
410
|
+
* @param dx The number of characters to move horizontally
|
|
411
|
+
* @param dy The number of lines to move vertically
|
|
412
|
+
*/
|
|
413
|
+
export function moveCursor(stream, dx, dy) {
|
|
414
|
+
if (!stream.write)
|
|
415
|
+
return false;
|
|
416
|
+
let cmd = '';
|
|
417
|
+
if (dx < 0) {
|
|
418
|
+
cmd += `\x1b[${-dx}D`;
|
|
419
|
+
}
|
|
420
|
+
else if (dx > 0) {
|
|
421
|
+
cmd += `\x1b[${dx}C`;
|
|
422
|
+
}
|
|
423
|
+
if (dy < 0) {
|
|
424
|
+
cmd += `\x1b[${-dy}A`;
|
|
425
|
+
}
|
|
426
|
+
else if (dy > 0) {
|
|
427
|
+
cmd += `\x1b[${dy}B`;
|
|
428
|
+
}
|
|
429
|
+
if (cmd)
|
|
430
|
+
stream.write(cmd);
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
moveCursor;
|
|
434
|
+
const _unescaped = {
|
|
435
|
+
'\r': 'return',
|
|
436
|
+
'\n': 'enter',
|
|
437
|
+
'\t': 'tab',
|
|
438
|
+
'\b': 'backspace',
|
|
439
|
+
'\x7f': 'backspace',
|
|
440
|
+
'\x1b': 'escape',
|
|
441
|
+
' ': 'space',
|
|
442
|
+
};
|
|
443
|
+
const _escaped = {
|
|
444
|
+
/* xterm ESC [ letter */
|
|
445
|
+
'[A': { name: 'up' },
|
|
446
|
+
'[B': { name: 'down' },
|
|
447
|
+
'[C': { name: 'right' },
|
|
448
|
+
'[D': { name: 'left' },
|
|
449
|
+
'[E': { name: 'clear' },
|
|
450
|
+
'[F': { name: 'end' },
|
|
451
|
+
'[H': { name: 'home' },
|
|
452
|
+
/* xterm/gnome ESC [ letter (with modifier) */
|
|
453
|
+
'[P': { name: 'f1' },
|
|
454
|
+
'[Q': { name: 'f2' },
|
|
455
|
+
'[R': { name: 'f3' },
|
|
456
|
+
'[S': { name: 'f4' },
|
|
457
|
+
/* xterm/gnome ESC O letter */
|
|
458
|
+
OA: { name: 'up' },
|
|
459
|
+
OB: { name: 'down' },
|
|
460
|
+
OC: { name: 'right' },
|
|
461
|
+
OD: { name: 'left' },
|
|
462
|
+
OE: { name: 'clear' },
|
|
463
|
+
OF: { name: 'end' },
|
|
464
|
+
OH: { name: 'home' },
|
|
465
|
+
/* xterm/gnome ESC O letter (without modifier) */
|
|
466
|
+
OP: { name: 'f1' },
|
|
467
|
+
OQ: { name: 'f2' },
|
|
468
|
+
OR: { name: 'f3' },
|
|
469
|
+
OS: { name: 'f4' },
|
|
470
|
+
/* xterm/rxvt ESC [ number ~ */
|
|
471
|
+
'[1~': { name: 'home' },
|
|
472
|
+
'[2~': { name: 'insert' },
|
|
473
|
+
'[3~': { name: 'delete' },
|
|
474
|
+
'[4~': { name: 'end' },
|
|
475
|
+
'[5~': { name: 'pageup' },
|
|
476
|
+
'[6~': { name: 'pagedown' },
|
|
477
|
+
'[7~': { name: 'home' },
|
|
478
|
+
'[8~': { name: 'end' },
|
|
479
|
+
/* xterm/rxvt ESC [ number ~ */
|
|
480
|
+
'[11~': { name: 'f1' },
|
|
481
|
+
'[12~': { name: 'f2' },
|
|
482
|
+
'[13~': { name: 'f3' },
|
|
483
|
+
'[14~': { name: 'f4' },
|
|
484
|
+
/* common */
|
|
485
|
+
'[15~': { name: 'f5' },
|
|
486
|
+
'[17~': { name: 'f6' },
|
|
487
|
+
'[18~': { name: 'f7' },
|
|
488
|
+
'[19~': { name: 'f8' },
|
|
489
|
+
'[20~': { name: 'f9' },
|
|
490
|
+
'[21~': { name: 'f10' },
|
|
491
|
+
'[23~': { name: 'f11' },
|
|
492
|
+
'[24~': { name: 'f12' },
|
|
493
|
+
/* paste bracket mode */
|
|
494
|
+
'[200~': { name: 'paste-start' },
|
|
495
|
+
'[201~': { name: 'paste-end' },
|
|
496
|
+
/* rxvt keys with modifiers */
|
|
497
|
+
'[a': { name: 'up', shift: true },
|
|
498
|
+
'[b': { name: 'down', shift: true },
|
|
499
|
+
'[c': { name: 'right', shift: true },
|
|
500
|
+
'[d': { name: 'left', shift: true },
|
|
501
|
+
'[e': { name: 'clear', shift: true },
|
|
502
|
+
/* from Cygwin and used in libuv */
|
|
503
|
+
'[[A': { name: 'f1' },
|
|
504
|
+
'[[B': { name: 'f2' },
|
|
505
|
+
'[[C': { name: 'f3' },
|
|
506
|
+
'[[D': { name: 'f4' },
|
|
507
|
+
'[[E': { name: 'f5' },
|
|
508
|
+
/* putty */
|
|
509
|
+
'[[5~': { name: 'pageup' },
|
|
510
|
+
'[[6~': { name: 'pagedown' },
|
|
511
|
+
'[2$': { name: 'insert', shift: true },
|
|
512
|
+
'[3$': { name: 'delete', shift: true },
|
|
513
|
+
'[5$': { name: 'pageup', shift: true },
|
|
514
|
+
'[6$': { name: 'pagedown', shift: true },
|
|
515
|
+
'[7$': { name: 'home', shift: true },
|
|
516
|
+
'[8$': { name: 'end', shift: true },
|
|
517
|
+
Oa: { name: 'up', ctrl: true },
|
|
518
|
+
Ob: { name: 'down', ctrl: true },
|
|
519
|
+
Oc: { name: 'right', ctrl: true },
|
|
520
|
+
Od: { name: 'left', ctrl: true },
|
|
521
|
+
Oe: { name: 'clear', ctrl: true },
|
|
522
|
+
'[2^': { name: 'insert', ctrl: true },
|
|
523
|
+
'[3^': { name: 'delete', ctrl: true },
|
|
524
|
+
'[5^': { name: 'pageup', ctrl: true },
|
|
525
|
+
'[6^': { name: 'pagedown', ctrl: true },
|
|
526
|
+
'[7^': { name: 'home', ctrl: true },
|
|
527
|
+
'[8^': { name: 'end', ctrl: true },
|
|
528
|
+
/* misc. */
|
|
529
|
+
'[Z': { name: 'tab', shift: true },
|
|
530
|
+
undefined: { name: 'undefined' },
|
|
531
|
+
};
|
|
532
|
+
/**
|
|
533
|
+
* This is an absolute monstrosity.
|
|
534
|
+
* It's good enough though.
|
|
535
|
+
*/
|
|
536
|
+
function _parseKey(sequence) {
|
|
537
|
+
const key = {
|
|
538
|
+
sequence,
|
|
539
|
+
name: undefined,
|
|
540
|
+
ctrl: false,
|
|
541
|
+
meta: false,
|
|
542
|
+
shift: false,
|
|
543
|
+
};
|
|
544
|
+
if (sequence in _unescaped) {
|
|
545
|
+
key.name = _unescaped[sequence];
|
|
546
|
+
key.meta = sequence.startsWith('\x1b');
|
|
547
|
+
return key;
|
|
548
|
+
}
|
|
549
|
+
if (sequence.length == 1 && sequence.charCodeAt(0) >= 32) {
|
|
550
|
+
key.name = sequence.toLowerCase();
|
|
551
|
+
key.shift = sequence >= 'A' && sequence <= 'Z';
|
|
552
|
+
return key;
|
|
553
|
+
}
|
|
554
|
+
if (sequence.length == 1) {
|
|
555
|
+
key.ctrl = true;
|
|
556
|
+
key.name = String.fromCharCode(sequence.charCodeAt(0) + 64).toLowerCase();
|
|
557
|
+
return key;
|
|
558
|
+
}
|
|
559
|
+
if (sequence.length == 2 && sequence[0] == '\x1b' && sequence[1] >= ' ') {
|
|
560
|
+
key.meta = true;
|
|
561
|
+
key.name = sequence[1].toLowerCase();
|
|
562
|
+
key.shift = sequence[1] >= 'A' && sequence[1] <= 'Z';
|
|
563
|
+
return key;
|
|
564
|
+
}
|
|
565
|
+
if (!sequence.startsWith('\x1b'))
|
|
566
|
+
return key;
|
|
567
|
+
const rest = sequence.slice(1);
|
|
568
|
+
if (rest in _escaped) {
|
|
569
|
+
Object.assign(key, _escaped[rest]);
|
|
570
|
+
return key;
|
|
571
|
+
}
|
|
572
|
+
if ((!rest.startsWith('[') && !rest.startsWith('O')) || !rest.length) {
|
|
573
|
+
key.meta = true;
|
|
574
|
+
return key;
|
|
575
|
+
}
|
|
576
|
+
// Format: \x1b[Num;ModifierChar or \x1b[;ModifierChar
|
|
577
|
+
const match = /^\[((\d+)?(;\d+)?([~^$A-Za-z]))\]?$/.exec(rest);
|
|
578
|
+
if (match) {
|
|
579
|
+
const modifier = match[3] ? parseInt(match[3].slice(1), 10) : 1;
|
|
580
|
+
const baseCode = '[' + (match[2] || '') + match[4];
|
|
581
|
+
if (baseCode in _escaped) {
|
|
582
|
+
Object.assign(key, _escaped[baseCode]);
|
|
583
|
+
key.shift = !!(modifier & 1);
|
|
584
|
+
key.meta = !!(modifier & 2) || !!(modifier & 8);
|
|
585
|
+
key.ctrl = !!(modifier & 4);
|
|
586
|
+
return key;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// Check for 3-digit codes (paste mode, etc.)
|
|
590
|
+
const [, digits] = /^\[(\d{3})~$/.exec(rest) || [];
|
|
591
|
+
if (digits) {
|
|
592
|
+
const code = `[${digits}~`;
|
|
593
|
+
if (code in _escaped) {
|
|
594
|
+
Object.assign(key, _escaped[code]);
|
|
595
|
+
return key;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
key.meta = true;
|
|
599
|
+
return key;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* The `readline.emitKeypressEvents()` method causes the given Readable stream to begin emitting `'keypress'` events corresponding to received input.
|
|
603
|
+
*
|
|
604
|
+
* Optionally, interface specifies a `readline.Interface` instance for which autocompletion is disabled when copy-pasted input is detected.
|
|
605
|
+
*
|
|
606
|
+
* If the `stream` is a TTY, then it must be in raw mode.
|
|
607
|
+
*
|
|
608
|
+
* This is automatically called by any readline instance on its `input` if the `input` is a terminal. Closing the `readline` instance does not stop the `input` from emitting `'keypress'` events.
|
|
609
|
+
*/
|
|
610
|
+
export function emitKeypressEvents(stream, readlineInterface) {
|
|
611
|
+
stream.on('data', (buffer) => {
|
|
612
|
+
const str = buffer.toString('utf8');
|
|
613
|
+
stream.emit('keypress', str, _parseKey(str));
|
|
614
|
+
});
|
|
615
|
+
if (!readlineInterface)
|
|
616
|
+
return;
|
|
617
|
+
stream.on('data', data => {
|
|
618
|
+
if (data.toString('utf8').includes('\u0003')) {
|
|
619
|
+
readlineInterface.emit('SIGINT');
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
emitKeypressEvents;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,32 +1,11 @@
|
|
|
1
|
+
import type { UUID } from 'node:crypto';
|
|
1
2
|
import type * as fs from 'node:fs';
|
|
2
|
-
import
|
|
3
|
+
import { type OptionalTuple } from 'utilium';
|
|
3
4
|
import { ErrnoError } from './internal/error.js';
|
|
4
5
|
declare global {
|
|
5
6
|
function atob(data: string): string;
|
|
6
7
|
function btoa(data: string): string;
|
|
7
8
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Encodes a string into a buffer
|
|
10
|
-
* @internal
|
|
11
|
-
*/
|
|
12
|
-
export declare function encodeRaw(input: string): Uint8Array;
|
|
13
|
-
/**
|
|
14
|
-
* Decodes a string from a buffer
|
|
15
|
-
* @internal
|
|
16
|
-
*/
|
|
17
|
-
export declare function decodeRaw(input?: Uint8Array): string;
|
|
18
|
-
/**
|
|
19
|
-
* Encodes a string into a buffer
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
export declare function encodeUTF8(input: string): Uint8Array;
|
|
23
|
-
export { /** @deprecated @hidden */ encodeUTF8 as encode };
|
|
24
|
-
/**
|
|
25
|
-
* Decodes a string from a buffer
|
|
26
|
-
* @internal
|
|
27
|
-
*/
|
|
28
|
-
export declare function decodeUTF8(input?: Uint8Array): string;
|
|
29
|
-
export { /** @deprecated @hidden */ decodeUTF8 as decode };
|
|
30
9
|
/**
|
|
31
10
|
* Decodes a directory listing
|
|
32
11
|
* @hidden
|
|
@@ -69,15 +48,5 @@ export declare function normalizeOptions(options: fs.WriteFileOptions | (fs.Enco
|
|
|
69
48
|
flag: string;
|
|
70
49
|
mode: number;
|
|
71
50
|
};
|
|
72
|
-
export
|
|
73
|
-
|
|
74
|
-
* Generate a random ino
|
|
75
|
-
* @internal @deprecated @hidden
|
|
76
|
-
*/
|
|
77
|
-
export declare function randomBigInt(): bigint;
|
|
78
|
-
/**
|
|
79
|
-
* Prevents infinite loops
|
|
80
|
-
* @internal
|
|
81
|
-
* @deprecated Use `canary` from Utilium
|
|
82
|
-
*/
|
|
83
|
-
export declare function canary(path?: string, syscall?: string): () => void;
|
|
51
|
+
export declare function stringifyUUID(uuid: bigint): UUID;
|
|
52
|
+
export declare function parseUUID(uuid: UUID): bigint;
|