@papillon6814/copi 0.1.0 → 0.2.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/LICENSE.unicode +39 -0
- package/README.md +57 -5
- package/dist/native/rename-exclusive-arm64 +0 -0
- package/dist/native/rename-exclusive-arm64.manifest.json +12 -0
- package/dist/src/apply.d.ts +9 -0
- package/dist/src/apply.js +110 -9
- package/dist/src/catalog.d.ts +21 -4
- package/dist/src/catalog.js +265 -133
- package/dist/src/cli.d.ts +2 -1
- package/dist/src/cli.js +73 -3
- package/dist/src/groups.js +8 -3
- package/dist/src/inspect.d.ts +3 -1
- package/dist/src/inspect.js +16 -6
- package/dist/src/instruction-reference.d.ts +6 -0
- package/dist/src/instruction-reference.js +21 -0
- package/dist/src/manage.d.ts +2 -0
- package/dist/src/manage.js +329 -0
- package/dist/src/migrate.d.ts +25 -0
- package/dist/src/migrate.js +171 -0
- package/dist/src/migration-backup.d.ts +22 -0
- package/dist/src/migration-backup.js +403 -0
- package/dist/src/migration-inventory.d.ts +9 -0
- package/dist/src/migration-inventory.js +237 -0
- package/dist/src/migration-resolution.d.ts +28 -0
- package/dist/src/migration-resolution.js +1618 -0
- package/dist/src/migration.d.ts +49 -0
- package/dist/src/migration.js +1004 -0
- package/dist/src/names.d.ts +11 -0
- package/dist/src/names.js +40 -0
- package/dist/src/native-placement.d.ts +16 -0
- package/dist/src/native-placement.js +557 -0
- package/dist/src/refresh.d.ts +20 -0
- package/dist/src/refresh.js +143 -0
- package/dist/src/resource-mutations.d.ts +45 -0
- package/dist/src/resource-mutations.js +225 -0
- package/dist/src/source-content.d.ts +4 -0
- package/dist/src/source-content.js +208 -0
- package/dist/src/storage-journal.d.ts +111 -0
- package/dist/src/storage-journal.js +613 -0
- package/dist/src/storage-root-lease.d.ts +7 -0
- package/dist/src/storage-root-lease.js +92 -0
- package/dist/src/storage-transaction.d.ts +100 -0
- package/dist/src/storage-transaction.js +3951 -0
- package/dist/src/terminal-editor.d.ts +8 -0
- package/dist/src/terminal-editor.js +391 -0
- package/dist/src/types.d.ts +18 -2
- package/dist/src/unicode-case-folding-data.d.ts +1 -0
- package/dist/src/unicode-case-folding-data.js +1596 -0
- package/dist/src/unicode-case-folding.d.ts +2 -0
- package/dist/src/unicode-case-folding.js +9 -0
- package/dist/src/wizard.d.ts +11 -3
- package/dist/src/wizard.js +274 -18
- package/package.json +5 -3
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type TerminalEditResult = {
|
|
2
|
+
kind: "cancelled";
|
|
3
|
+
} | {
|
|
4
|
+
kind: "submitted";
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
7
|
+
/** In-memory editor only: no file/catalog access, no body logging on submit or cancel. */
|
|
8
|
+
export declare function editTerminalText(initialText: string): Promise<TerminalEditResult>;
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { StringDecoder } from "node:string_decoder";
|
|
2
|
+
const segmenter = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
3
|
+
function linesOf(text) {
|
|
4
|
+
const lines = [];
|
|
5
|
+
let start = 0;
|
|
6
|
+
for (const match of text.matchAll(/\r\n|\n|\r/g)) {
|
|
7
|
+
lines.push({ text: text.slice(start, match.index), ending: match[0] });
|
|
8
|
+
start = match.index + match[0].length;
|
|
9
|
+
}
|
|
10
|
+
lines.push({ text: text.slice(start), ending: "" });
|
|
11
|
+
return lines;
|
|
12
|
+
}
|
|
13
|
+
function shownText(text) {
|
|
14
|
+
return text.replace(/[\x00-\x1f\x7f-\x9f\ufeff\u202a-\u202e\u2066-\u2069]/g, (char) => char === "\t" ? " " : `\\u${char.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
15
|
+
}
|
|
16
|
+
function cellWidth(text) {
|
|
17
|
+
if (/^[\p{Mark}]+$/u.test(text))
|
|
18
|
+
return 1;
|
|
19
|
+
if (/\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20e3/u.test(text))
|
|
20
|
+
return 2;
|
|
21
|
+
const point = text.codePointAt(0);
|
|
22
|
+
return point >= 0x1100 && (point <= 0x115f || point === 0x2329 || point === 0x232a ||
|
|
23
|
+
(point >= 0x2e80 && point <= 0xa4cf && point !== 0x303f) || (point >= 0xac00 && point <= 0xd7a3) ||
|
|
24
|
+
(point >= 0xf900 && point <= 0xfaff) || (point >= 0xfe10 && point <= 0xfe19) ||
|
|
25
|
+
(point >= 0xfe30 && point <= 0xfe6f) || (point >= 0xff01 && point <= 0xff60) ||
|
|
26
|
+
(point >= 0xffe0 && point <= 0xffe6) || (point >= 0x20000 && point <= 0x3fffd)) ? 2 : 1;
|
|
27
|
+
}
|
|
28
|
+
function glyphsOf(line) {
|
|
29
|
+
if (line.glyphs)
|
|
30
|
+
return line.glyphs;
|
|
31
|
+
const glyphs = [];
|
|
32
|
+
const add = (text, start) => {
|
|
33
|
+
const shown = /^[\p{Mark}]+$/u.test(text) ? `◌${text}` : shownText(text);
|
|
34
|
+
glyphs.push({ text, shown, start, end: start + text.length, width: /^[\p{Mark}]+$/u.test(text) ? 1 : shown !== text ? shown.length : cellWidth(text) });
|
|
35
|
+
};
|
|
36
|
+
// Avoid invoking the Unicode segmenter a million times for a long ASCII file.
|
|
37
|
+
if (/^[\x20-\x7e]*$/.test(line.text)) {
|
|
38
|
+
for (let i = 0; i < line.text.length; i++)
|
|
39
|
+
add(line.text[i], i);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
for (const part of segmenter.segment(line.text))
|
|
43
|
+
add(part.segment, part.index);
|
|
44
|
+
}
|
|
45
|
+
line.glyphs = glyphs;
|
|
46
|
+
return glyphs;
|
|
47
|
+
}
|
|
48
|
+
function rowsOf(line, columns) {
|
|
49
|
+
if (line.rows && line.columns === columns)
|
|
50
|
+
return line.rows;
|
|
51
|
+
const rows = [];
|
|
52
|
+
const glyphs = glyphsOf(line);
|
|
53
|
+
let start = 0, width = 0;
|
|
54
|
+
for (let i = 0; i < glyphs.length; i++) {
|
|
55
|
+
const next = Math.min(columns, glyphs[i].width);
|
|
56
|
+
if (width + next > columns) {
|
|
57
|
+
rows.push({ start, end: i, width });
|
|
58
|
+
start = i;
|
|
59
|
+
width = 0;
|
|
60
|
+
}
|
|
61
|
+
width += next;
|
|
62
|
+
}
|
|
63
|
+
rows.push({ start, end: glyphs.length, width });
|
|
64
|
+
line.rows = rows;
|
|
65
|
+
line.columns = columns;
|
|
66
|
+
return rows;
|
|
67
|
+
}
|
|
68
|
+
/** In-memory editor only: no file/catalog access, no body logging on submit or cancel. */
|
|
69
|
+
export async function editTerminalText(initialText) {
|
|
70
|
+
const input = process.stdin, output = process.stdout;
|
|
71
|
+
if (!input.isTTY || !output.isTTY)
|
|
72
|
+
throw new Error("Text editing requires an interactive stdin/stdout TTY.");
|
|
73
|
+
const wasRaw = Boolean(input.isRaw), wasFlowing = input.readableFlowing === true;
|
|
74
|
+
const decoder = new StringDecoder("utf8");
|
|
75
|
+
let lines = linesOf(initialText), lineIndex = 0, offset = 0, pending = "", paste = false, pasteText = "";
|
|
76
|
+
let finished = false, frame, escapeTimer;
|
|
77
|
+
let verticalColumn;
|
|
78
|
+
const newline = lines.find((line) => line.ending)?.ending ?? "\n";
|
|
79
|
+
const dimensions = () => ({ columns: Math.max(1, (output.columns || 80) - 1), height: Math.max(1, (output.rows || 24) - 2) });
|
|
80
|
+
const point = () => {
|
|
81
|
+
const glyphs = glyphsOf(lines[lineIndex]);
|
|
82
|
+
let index = glyphs.findIndex((glyph) => glyph.end > offset);
|
|
83
|
+
if (index < 0)
|
|
84
|
+
index = glyphs.length;
|
|
85
|
+
const rows = rowsOf(lines[lineIndex], dimensions().columns);
|
|
86
|
+
let rowIndex = rows.findIndex((row, i) => index < row.end || i === rows.length - 1);
|
|
87
|
+
if (rowIndex < 0)
|
|
88
|
+
rowIndex = rows.length - 1;
|
|
89
|
+
const row = rows[rowIndex];
|
|
90
|
+
const column = glyphs.slice(row.start, index).reduce((sum, glyph) => sum + Math.min(dimensions().columns, glyph.width), 0);
|
|
91
|
+
return { index, rowIndex, column };
|
|
92
|
+
};
|
|
93
|
+
const previousRow = (line, row) => {
|
|
94
|
+
if (row > 0)
|
|
95
|
+
return [line, row - 1];
|
|
96
|
+
if (line === 0)
|
|
97
|
+
return undefined;
|
|
98
|
+
return [line - 1, rowsOf(lines[line - 1], dimensions().columns).length - 1];
|
|
99
|
+
};
|
|
100
|
+
const nextRow = (line, row) => {
|
|
101
|
+
if (row + 1 < rowsOf(lines[line], dimensions().columns).length)
|
|
102
|
+
return [line, row + 1];
|
|
103
|
+
return line + 1 < lines.length ? [line + 1, 0] : undefined;
|
|
104
|
+
};
|
|
105
|
+
const render = () => {
|
|
106
|
+
frame = undefined;
|
|
107
|
+
if (finished)
|
|
108
|
+
return;
|
|
109
|
+
const { columns, height } = dimensions();
|
|
110
|
+
const caret = point();
|
|
111
|
+
let top = [lineIndex, caret.rowIndex], caretRow = 0;
|
|
112
|
+
for (let i = 0; i < height - 1; i++) {
|
|
113
|
+
const previous = previousRow(...top);
|
|
114
|
+
if (!previous)
|
|
115
|
+
break;
|
|
116
|
+
top = previous;
|
|
117
|
+
caretRow++;
|
|
118
|
+
}
|
|
119
|
+
const visible = [];
|
|
120
|
+
let at = top;
|
|
121
|
+
while (visible.length < height && at) {
|
|
122
|
+
const line = lines[at[0]], row = rowsOf(line, columns)[at[1]];
|
|
123
|
+
visible.push(glyphsOf(line).slice(row.start, row.end).map((glyph) => glyph.width > columns ? glyph.shown.slice(0, columns) : glyph.shown).join(""));
|
|
124
|
+
at = nextRow(...at);
|
|
125
|
+
}
|
|
126
|
+
const header = (columns >= 52 ? "Edit saved text · Ctrl-S: review · Esc / Ctrl-C: cancel" : "Ctrl-S review/Esc cancel").slice(0, columns);
|
|
127
|
+
const footer = `Line ${lineIndex + 1}/${lines.length} · Enter: newline · arrows: move · PgUp/PgDn: scroll`.slice(0, columns);
|
|
128
|
+
let screen = `\u001b[?25l\u001b[H\u001b[2K${header}`;
|
|
129
|
+
for (let i = 0; i < height; i++)
|
|
130
|
+
screen += `\u001b[${i + 2};1H\u001b[2K${visible[i] ?? ""}`;
|
|
131
|
+
screen += `\u001b[${height + 2};1H\u001b[2K${footer}\u001b[${caretRow + 2};${Math.min(columns, caret.column) + 1}H\u001b[?25h`;
|
|
132
|
+
output.write(screen);
|
|
133
|
+
};
|
|
134
|
+
const redraw = () => { if (!frame && !finished)
|
|
135
|
+
frame = setTimeout(() => { try {
|
|
136
|
+
render();
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
cancel();
|
|
140
|
+
} }, 16); };
|
|
141
|
+
const insert = (text) => {
|
|
142
|
+
if (!text)
|
|
143
|
+
return;
|
|
144
|
+
const line = lines[lineIndex];
|
|
145
|
+
const added = linesOf(line.text.slice(0, offset) + text + line.text.slice(offset));
|
|
146
|
+
const head = linesOf(line.text.slice(0, offset) + text);
|
|
147
|
+
added[added.length - 1].ending = line.ending;
|
|
148
|
+
lines.splice(lineIndex, 1, ...added);
|
|
149
|
+
lineIndex += head.length - 1;
|
|
150
|
+
offset = head[head.length - 1].text.length;
|
|
151
|
+
verticalColumn = undefined;
|
|
152
|
+
};
|
|
153
|
+
const horizontal = (direction) => {
|
|
154
|
+
const glyphs = glyphsOf(lines[lineIndex]);
|
|
155
|
+
if (direction < 0) {
|
|
156
|
+
let previous;
|
|
157
|
+
for (let i = glyphs.length - 1; i >= 0; i--)
|
|
158
|
+
if (glyphs[i].start < offset) {
|
|
159
|
+
previous = glyphs[i];
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
if (previous)
|
|
163
|
+
offset = previous.start;
|
|
164
|
+
else if (lineIndex > 0) {
|
|
165
|
+
lineIndex--;
|
|
166
|
+
offset = lines[lineIndex].text.length;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const next = glyphs.find((glyph) => glyph.end > offset);
|
|
171
|
+
if (next)
|
|
172
|
+
offset = next.end;
|
|
173
|
+
else if (lineIndex + 1 < lines.length) {
|
|
174
|
+
lineIndex++;
|
|
175
|
+
offset = 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
verticalColumn = undefined;
|
|
179
|
+
};
|
|
180
|
+
const vertical = (direction) => {
|
|
181
|
+
const caret = point();
|
|
182
|
+
const target = direction < 0 ? previousRow(lineIndex, caret.rowIndex) : nextRow(lineIndex, caret.rowIndex);
|
|
183
|
+
if (!target)
|
|
184
|
+
return;
|
|
185
|
+
verticalColumn ??= caret.column;
|
|
186
|
+
lineIndex = target[0];
|
|
187
|
+
const line = lines[lineIndex], row = rowsOf(line, dimensions().columns)[target[1]], glyphs = glyphsOf(line);
|
|
188
|
+
let width = 0, index = row.start;
|
|
189
|
+
while (index < row.end && width + glyphs[index].width <= verticalColumn)
|
|
190
|
+
width += glyphs[index++].width;
|
|
191
|
+
offset = glyphs[index]?.start ?? line.text.length;
|
|
192
|
+
};
|
|
193
|
+
const remove = (backwards) => {
|
|
194
|
+
const oldLine = lineIndex, oldOffset = offset;
|
|
195
|
+
horizontal(backwards ? -1 : 1);
|
|
196
|
+
if (oldLine === lineIndex) {
|
|
197
|
+
const line = lines[lineIndex];
|
|
198
|
+
lines[lineIndex] = { text: line.text.slice(0, Math.min(oldOffset, offset)) + line.text.slice(Math.max(oldOffset, offset)), ending: line.ending };
|
|
199
|
+
offset = Math.min(oldOffset, offset);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
const first = Math.min(oldLine, lineIndex), left = lines[first], right = lines[first + 1];
|
|
203
|
+
lines.splice(first, 2, { text: left.text + right.text, ending: right.ending });
|
|
204
|
+
lineIndex = first;
|
|
205
|
+
offset = left.text.length;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
let complete;
|
|
209
|
+
const result = new Promise((resolve) => { complete = resolve; });
|
|
210
|
+
const finish = (value) => {
|
|
211
|
+
if (finished)
|
|
212
|
+
return;
|
|
213
|
+
finished = true;
|
|
214
|
+
if (frame)
|
|
215
|
+
clearTimeout(frame);
|
|
216
|
+
if (escapeTimer)
|
|
217
|
+
clearTimeout(escapeTimer);
|
|
218
|
+
input.off("data", data);
|
|
219
|
+
input.off("end", cancel);
|
|
220
|
+
input.off("close", cancel);
|
|
221
|
+
input.off("error", cancel);
|
|
222
|
+
output.off("resize", redraw);
|
|
223
|
+
output.off("error", cancel);
|
|
224
|
+
for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"])
|
|
225
|
+
process.off(signal, cancel);
|
|
226
|
+
try {
|
|
227
|
+
input.setRawMode(wasRaw);
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
if (!wasFlowing)
|
|
231
|
+
input.pause();
|
|
232
|
+
try {
|
|
233
|
+
output.write("\u001b[?2004l\u001b[?1049l\u001b[?25h");
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
complete(value);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const cancel = () => finish({ kind: "cancelled" });
|
|
241
|
+
const command = (sequence) => {
|
|
242
|
+
switch (sequence) {
|
|
243
|
+
case "\u001b[A":
|
|
244
|
+
vertical(-1);
|
|
245
|
+
break;
|
|
246
|
+
case "\u001b[B":
|
|
247
|
+
vertical(1);
|
|
248
|
+
break;
|
|
249
|
+
case "\u001b[C":
|
|
250
|
+
horizontal(1);
|
|
251
|
+
break;
|
|
252
|
+
case "\u001b[D":
|
|
253
|
+
horizontal(-1);
|
|
254
|
+
break;
|
|
255
|
+
case "\u001b[H":
|
|
256
|
+
case "\u001bOH":
|
|
257
|
+
case "\u001b[1~":
|
|
258
|
+
offset = 0;
|
|
259
|
+
verticalColumn = undefined;
|
|
260
|
+
break;
|
|
261
|
+
case "\u001b[F":
|
|
262
|
+
case "\u001bOF":
|
|
263
|
+
case "\u001b[4~":
|
|
264
|
+
offset = lines[lineIndex].text.length;
|
|
265
|
+
verticalColumn = undefined;
|
|
266
|
+
break;
|
|
267
|
+
case "\u001b[1;5H":
|
|
268
|
+
lineIndex = 0;
|
|
269
|
+
offset = 0;
|
|
270
|
+
verticalColumn = undefined;
|
|
271
|
+
break;
|
|
272
|
+
case "\u001b[1;5F":
|
|
273
|
+
lineIndex = lines.length - 1;
|
|
274
|
+
offset = lines[lineIndex].text.length;
|
|
275
|
+
verticalColumn = undefined;
|
|
276
|
+
break;
|
|
277
|
+
case "\u001b[3~":
|
|
278
|
+
remove(false);
|
|
279
|
+
break;
|
|
280
|
+
case "\u001b[5~":
|
|
281
|
+
for (let i = 0; i < dimensions().height; i++)
|
|
282
|
+
vertical(-1);
|
|
283
|
+
break;
|
|
284
|
+
case "\u001b[6~":
|
|
285
|
+
for (let i = 0; i < dimensions().height; i++)
|
|
286
|
+
vertical(1);
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
const consume = () => {
|
|
291
|
+
while (pending && !finished) {
|
|
292
|
+
if (paste) {
|
|
293
|
+
const end = pending.indexOf("\u001b[201~");
|
|
294
|
+
if (end < 0) {
|
|
295
|
+
// Keep a possible split closing delimiter, not the full paste, in the parser.
|
|
296
|
+
const keep = Math.min(5, pending.length);
|
|
297
|
+
pasteText += pending.slice(0, pending.length - keep);
|
|
298
|
+
pending = pending.slice(-keep);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
pasteText += pending.slice(0, end);
|
|
302
|
+
pending = pending.slice(end + 6);
|
|
303
|
+
insert(pasteText);
|
|
304
|
+
pasteText = "";
|
|
305
|
+
paste = false;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (pending.startsWith("\u001b[200~")) {
|
|
309
|
+
paste = true;
|
|
310
|
+
pending = pending.slice(6);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (pending[0] === "\u001b") {
|
|
314
|
+
const match = /^(?:\u001b\[[0-9;?]*[A-Za-z~]|\u001bO[A-Za-z])/.exec(pending);
|
|
315
|
+
if (match) {
|
|
316
|
+
if (match[0].length > 64) {
|
|
317
|
+
cancel();
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
command(match[0]);
|
|
321
|
+
pending = pending.slice(match[0].length);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (pending === "\u001b") {
|
|
325
|
+
escapeTimer = setTimeout(cancel, 100);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (/^\u001b(?:\[[0-9;?]*|O)$/.test(pending)) {
|
|
329
|
+
// A recognized control prefix is not a standalone Esc key. Await continuation,
|
|
330
|
+
// with bounded parser storage; explicit cancel, EOF and signals still terminate.
|
|
331
|
+
if (pending.length > 64)
|
|
332
|
+
cancel();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
cancel();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const control = pending.search(/[\x00-\x08\x0a-\x1f\x7f]/);
|
|
339
|
+
if (control > 0 || control < 0) {
|
|
340
|
+
const end = control < 0 ? pending.length : control;
|
|
341
|
+
insert(pending.slice(0, end));
|
|
342
|
+
pending = pending.slice(end);
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
const char = pending[0];
|
|
346
|
+
pending = pending.slice(1);
|
|
347
|
+
if (char === "\u0013")
|
|
348
|
+
finish({ kind: "submitted", text: lines.map((line) => line.text + line.ending).join("") });
|
|
349
|
+
else if (char === "\u0003" || char === "\u0004")
|
|
350
|
+
cancel();
|
|
351
|
+
else if (char === "\r")
|
|
352
|
+
insert(newline);
|
|
353
|
+
else if (char === "\n")
|
|
354
|
+
insert("\n");
|
|
355
|
+
else if (char === "\u007f" || char === "\b")
|
|
356
|
+
remove(true);
|
|
357
|
+
}
|
|
358
|
+
redraw();
|
|
359
|
+
};
|
|
360
|
+
const data = (chunk) => {
|
|
361
|
+
if (escapeTimer) {
|
|
362
|
+
clearTimeout(escapeTimer);
|
|
363
|
+
escapeTimer = undefined;
|
|
364
|
+
}
|
|
365
|
+
try {
|
|
366
|
+
pending += typeof chunk === "string" ? chunk : decoder.write(chunk);
|
|
367
|
+
consume();
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
cancel();
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
try {
|
|
374
|
+
input.on("data", data);
|
|
375
|
+
input.on("end", cancel);
|
|
376
|
+
input.on("close", cancel);
|
|
377
|
+
input.on("error", cancel);
|
|
378
|
+
output.on("resize", redraw);
|
|
379
|
+
output.on("error", cancel);
|
|
380
|
+
for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"])
|
|
381
|
+
process.on(signal, cancel);
|
|
382
|
+
input.setRawMode(true);
|
|
383
|
+
input.resume();
|
|
384
|
+
output.write("\u001b[?1049h\u001b[?2004h");
|
|
385
|
+
render();
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
cancel();
|
|
389
|
+
}
|
|
390
|
+
return result;
|
|
391
|
+
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -44,7 +44,14 @@ export interface SnapshotFile {
|
|
|
44
44
|
export interface SnapshotFileContents extends SnapshotFile {
|
|
45
45
|
bytes: Buffer;
|
|
46
46
|
}
|
|
47
|
-
export
|
|
47
|
+
export type ContentLocation = {
|
|
48
|
+
kind: "file";
|
|
49
|
+
path: string;
|
|
50
|
+
} | {
|
|
51
|
+
kind: "tree";
|
|
52
|
+
path: string;
|
|
53
|
+
};
|
|
54
|
+
export interface LegacySavedItem {
|
|
48
55
|
id: string;
|
|
49
56
|
kind: ResourceKind;
|
|
50
57
|
source: string;
|
|
@@ -55,13 +62,22 @@ export interface SavedItem {
|
|
|
55
62
|
savedAt: string;
|
|
56
63
|
files: SnapshotFile[];
|
|
57
64
|
}
|
|
65
|
+
export interface SavedItem extends LegacySavedItem {
|
|
66
|
+
content: ContentLocation;
|
|
67
|
+
}
|
|
58
68
|
export interface Group {
|
|
59
69
|
id: string;
|
|
60
70
|
name: string;
|
|
61
71
|
itemIds: string[];
|
|
62
72
|
}
|
|
63
73
|
export interface Catalog {
|
|
64
|
-
version:
|
|
74
|
+
version: 2;
|
|
65
75
|
items: SavedItem[];
|
|
66
76
|
groups: Group[];
|
|
67
77
|
}
|
|
78
|
+
export interface LegacyCatalog {
|
|
79
|
+
version: 1;
|
|
80
|
+
items: LegacySavedItem[];
|
|
81
|
+
groups: Group[];
|
|
82
|
+
}
|
|
83
|
+
export type StoredCatalog = Catalog | LegacyCatalog;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const unicode17CaseFolding: ReadonlyMap<number, string>;
|