@akterjs/cli 0.0.0-stage → 0.1.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 +201 -0
- package/README.md +47 -2
- package/dist/Argument-D81dqizB.mjs +57 -0
- package/dist/Array-B4kuTQeW.mjs +2323 -0
- package/dist/Boolean-kILIvmhE.mjs +26 -0
- package/dist/ChildProcess-BCIwxPGc.mjs +577 -0
- package/dist/CliError-Cf5xqkkj.mjs +633 -0
- package/dist/Command-Dzq9KM-h.mjs +5135 -0
- package/dist/Config-B6OND9WR.mjs +854 -0
- package/dist/Console-BKHUkH6a.mjs +141 -0
- package/dist/Data-CeCULr0-.mjs +251 -0
- package/dist/Digest-CBd3uv5B.mjs +348 -0
- package/dist/Duration-EH9Vy4U6.mjs +791 -0
- package/dist/Effect-CKFpqbmw.mjs +12911 -0
- package/dist/FileSystem-4pPcEb_i.mjs +1366 -0
- package/dist/HttpClientError-BUeMWx70.mjs +303 -0
- package/dist/HttpClientResponse-D5ZKICVV.mjs +855 -0
- package/dist/Match-CGPLZYrV.mjs +434 -0
- package/dist/MutableHashMap-f8nW8AJR.mjs +376 -0
- package/dist/MutableHashSet-_HI572Ya.mjs +155 -0
- package/dist/MutableRef-D4Qv592C.mjs +107 -0
- package/dist/Number-BvkRkfc-.mjs +137 -0
- package/dist/Option-DkxSnBhp.mjs +3967 -0
- package/dist/Order-C1JC991I.mjs +481 -0
- package/dist/Path-Djdv_eF5.mjs +130 -0
- package/dist/Queue-CO5UQ6os.mjs +1394 -0
- package/dist/Redacted-RkJrG5Me.mjs +160 -0
- package/dist/Ref-BIPOxJNH.mjs +267 -0
- package/dist/Runtime-BInIAwK3.mjs +297 -0
- package/dist/Schema-MiKt5K1v.mjs +10999 -0
- package/dist/SecureRandom-B_U4ysO3.mjs +279 -0
- package/dist/Semaphore-DOVJ4ZGS.mjs +177 -0
- package/dist/Stdio-KylmOBX_.mjs +74 -0
- package/dist/Stream-bK9QIETN.mjs +4012 -0
- package/dist/String-q5dcsVe4.mjs +351 -0
- package/dist/TerminalCapabilities-w_44MAca.mjs +1769 -0
- package/dist/WebCrypto-ZI_GNVlw.mjs +33 -0
- package/dist/actor-call.service-CGM_vD9u.mjs +1269 -0
- package/dist/actor-client.adapter-Coem7gF1.mjs +3691 -0
- package/dist/akter-program.config-C4cXx4Fr.mjs +7034 -0
- package/dist/akter.cli.mjs +5 -0
- package/dist/app-cli.config.mjs +49 -0
- package/dist/app-entry.pure.mjs +31 -0
- package/dist/archive/akter-archive.schema.mjs +65 -0
- package/dist/archive/akter-archive.service.mjs +309 -0
- package/dist/archive/archive-cli.config.mjs +45 -0
- package/dist/archive/archive-invalid.errors.mjs +5 -0
- package/dist/archive/archived-lineage.pure.mjs +13 -0
- package/dist/archive/tar.pure.mjs +291 -0
- package/dist/archive/zstd.adapter.mjs +46 -0
- package/dist/bench/bench-report.pure.mjs +120 -0
- package/dist/bench/bench-runner.pure.mjs +89 -0
- package/dist/bench/bench.service.mjs +301 -0
- package/dist/cli-runtime.layer-BqK2mmVL.mjs +1191 -0
- package/dist/cli-runtime.layer.mjs +1 -0
- package/dist/cloud-client.adapter-Cy1BjDbG.mjs +3186 -0
- package/dist/cloud-client.adapter-DOVMoYAj.mjs +304 -0
- package/dist/command/akter-commands.config.mjs +32 -0
- package/dist/command/akter-program.config.mjs +1 -0
- package/dist/credentials/credentials.service.mjs +226 -0
- package/dist/credentials/keychain.adapter.mjs +92 -0
- package/dist/credentials/login.config.mjs +251 -0
- package/dist/deploy/auth/api-attempt.service.mjs +30 -0
- package/dist/deploy/auth/token-refresh.errors.mjs +4 -0
- package/dist/deploy/build-bundle.adapter.mjs +133 -0
- package/dist/deploy/build-manifest.pure.mjs +44 -0
- package/dist/deploy/cloud-client.adapter.mjs +1 -0
- package/dist/deploy/cloud-url.pure.mjs +17 -0
- package/dist/deploy/deploy-failed.errors.mjs +17 -0
- package/dist/deploy/deploy.service.mjs +156 -0
- package/dist/deploy/request-failure.pure.mjs +87 -0
- package/dist/dev-runner.pure.mjs +30 -0
- package/dist/docs/doc-topics.pure.mjs +21 -0
- package/dist/docs/docs.config.mjs +1 -0
- package/dist/docs.config-_21Xi6HU.mjs +190 -0
- package/dist/export/actor-export.service.mjs +267 -0
- package/dist/export/export-failed.errors.mjs +4 -0
- package/dist/export/export-failure.pure.mjs +18 -0
- package/dist/export/ordered-lines.pure.mjs +43 -0
- package/dist/export/ranged-download.pure.mjs +66 -0
- package/dist/export/snapshot-download.pure.mjs +86 -0
- package/dist/history-runner.pure.mjs +186 -0
- package/dist/history-since.pure.mjs +17 -0
- package/dist/hosted-runtime.layer-Cx3IPsEd.mjs +16358 -0
- package/dist/local/environment-cli.config.mjs +90 -0
- package/dist/local/environment-runner.pure.mjs +75 -0
- package/dist/local/local-cli.config.mjs +159 -0
- package/dist/logs/log-follow.config.mjs +21 -0
- package/dist/logs/log-follow.service.mjs +87 -0
- package/dist/logs/log-lines.pure.mjs +44 -0
- package/dist/migrate-runner.pure.mjs +28 -0
- package/dist/operation-input.pure-CS9iUhqK.mjs +1383 -0
- package/dist/operation-registry.pure-DVC8EDgj.mjs +283 -0
- package/dist/registry/actor-call.service.mjs +1 -0
- package/dist/registry/actor-commands.config.mjs +127 -0
- package/dist/registry/actor-refusal.pure.mjs +34 -0
- package/dist/registry/approval.service.mjs +80 -0
- package/dist/registry/cloud-commands.config.mjs +151 -0
- package/dist/registry/cloud-served.pure.mjs +31 -0
- package/dist/registry/operation-call.service.mjs +262 -0
- package/dist/registry/operation-input.pure.mjs +1 -0
- package/dist/registry/operation-output.pure.mjs +91 -0
- package/dist/registry/served-command.config.mjs +57 -0
- package/dist/runner-exited.errors.mjs +10 -0
- package/dist/terminal/cli-exit.errors.mjs +38 -0
- package/dist/terminal/cli-failure.pure.mjs +31 -0
- package/dist/terminal/confirm.adapter.mjs +27 -0
- package/package.json +61 -3
|
@@ -0,0 +1,1769 @@
|
|
|
1
|
+
import { S as none, Tn as pipe, _ as isSome, bn as dual, f as getOrElse, qt as hasProperty, w as some, x as match } from "./Option-DkxSnBhp.mjs";
|
|
2
|
+
import { $t as suspend, A as ensuring, B as flatMap$1, Et as orDie, Gt as scoped, M as fail, Nt as raceFirst, W as fnUntraced, Xt as succeed$1, _t as match$1, aa as Service, at as isEffect, dt as map$1, en as sync, f as cached, ht as mapError, ia as Reference, va as Prototype } from "./Effect-CKFpqbmw.mjs";
|
|
3
|
+
import { L as reduce, M as match$2, d as findFirstIndex, f as findLast, j as map$2, o as empty, u as findFirst, w as isReadonlyArrayNonEmpty } from "./Array-B4kuTQeW.mjs";
|
|
4
|
+
import { p as Error$1, sn as tag } from "./Schema-MiKt5K1v.mjs";
|
|
5
|
+
import { a as taggedEnum } from "./Data-CeCULr0-.mjs";
|
|
6
|
+
import { i as round } from "./Number-BvkRkfc-.mjs";
|
|
7
|
+
import { g as take } from "./Queue-CO5UQ6os.mjs";
|
|
8
|
+
import { n as make$1 } from "./Redacted-RkJrG5Me.mjs";
|
|
9
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/Terminal.js
|
|
10
|
+
const TypeId$1 = "~effect/Terminal";
|
|
11
|
+
const QuitErrorTypeId = "~effect/Terminal/QuitError";
|
|
12
|
+
/**
|
|
13
|
+
* Represents an error that occurs when a user attempts to
|
|
14
|
+
* quit out of a `Terminal` prompt for input (usually by entering `ctrl`+`c`).
|
|
15
|
+
*
|
|
16
|
+
* **When to use**
|
|
17
|
+
*
|
|
18
|
+
* Use when implementing terminal input or prompts that need to signal
|
|
19
|
+
* user-requested cancellation through the typed error channel.
|
|
20
|
+
*
|
|
21
|
+
* @see {@link isQuitError} for checking unknown errors when handling terminal cancellation
|
|
22
|
+
*
|
|
23
|
+
* @stability unstable
|
|
24
|
+
* @category errors
|
|
25
|
+
* @since 4.0.0
|
|
26
|
+
*/
|
|
27
|
+
var QuitError = class extends (/*#__PURE__*/ Error$1("QuitError")({ _tag: /*#__PURE__*/ tag("QuitError") })) {
|
|
28
|
+
/**
|
|
29
|
+
* Marks this value as a terminal quit error for runtime guards.
|
|
30
|
+
*
|
|
31
|
+
* @since 4.0.0
|
|
32
|
+
*/
|
|
33
|
+
[QuitErrorTypeId] = QuitErrorTypeId;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Returns `true` if the provided value is a `Terminal.QuitError`.
|
|
37
|
+
*
|
|
38
|
+
* **When to use**
|
|
39
|
+
*
|
|
40
|
+
* Use to narrow unknown failures to `QuitError` when handling terminal input
|
|
41
|
+
* cancellation.
|
|
42
|
+
*
|
|
43
|
+
* **Details**
|
|
44
|
+
*
|
|
45
|
+
* Returns `true` when the value carries the `QuitError` runtime marker and
|
|
46
|
+
* narrows it to `QuitError`.
|
|
47
|
+
*
|
|
48
|
+
* @see {@link QuitError} for the error value produced when terminal input is quit
|
|
49
|
+
*
|
|
50
|
+
* @stability unstable
|
|
51
|
+
* @category guards
|
|
52
|
+
* @since 4.0.0
|
|
53
|
+
*/
|
|
54
|
+
const isQuitError = (u) => hasProperty(u, QuitErrorTypeId);
|
|
55
|
+
/**
|
|
56
|
+
* Service tag for command-line input and output services.
|
|
57
|
+
*
|
|
58
|
+
* **When to use**
|
|
59
|
+
*
|
|
60
|
+
* Use to access or provide platform terminal capabilities such as reading
|
|
61
|
+
* input, writing output, and inspecting terminal dimensions.
|
|
62
|
+
*
|
|
63
|
+
* @stability unstable
|
|
64
|
+
* @category services
|
|
65
|
+
* @since 4.0.0
|
|
66
|
+
*/
|
|
67
|
+
const Terminal = /*#__PURE__*/ Service("effect/Terminal");
|
|
68
|
+
/**
|
|
69
|
+
* Creates a `Terminal` service implementation.
|
|
70
|
+
*
|
|
71
|
+
* **When to use**
|
|
72
|
+
*
|
|
73
|
+
* Use to construct a custom `Terminal` service implementation from concrete
|
|
74
|
+
* terminal capabilities when writing a platform adapter, test implementation,
|
|
75
|
+
* or custom runtime service.
|
|
76
|
+
*
|
|
77
|
+
* **Details**
|
|
78
|
+
*
|
|
79
|
+
* The implementation object supplies `columns`, `rows`, `size`, `readInput`,
|
|
80
|
+
* `readLine`, and `display`; `make` attaches the `Terminal` service marker so
|
|
81
|
+
* the result can be provided through the `Terminal` context service.
|
|
82
|
+
*
|
|
83
|
+
* @stability unstable
|
|
84
|
+
* @category constructors
|
|
85
|
+
* @since 4.0.0
|
|
86
|
+
*/
|
|
87
|
+
const make = (impl) => Terminal.of({
|
|
88
|
+
...impl,
|
|
89
|
+
[TypeId$1]: TypeId$1
|
|
90
|
+
});
|
|
91
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/cli/internal/ansi.js
|
|
92
|
+
/**
|
|
93
|
+
* Internal ANSI escape sequence helpers used by the unstable CLI rendering
|
|
94
|
+
* implementation. This module centralizes the control codes for text styling,
|
|
95
|
+
* cursor movement, line erasing, and terminal notifications so renderers can
|
|
96
|
+
* compose terminal output without scattering raw escape sequences throughout
|
|
97
|
+
* the CLI internals.
|
|
98
|
+
*
|
|
99
|
+
* The helpers deliberately work with plain strings because terminal rendering
|
|
100
|
+
* is sensitive to ordering: style codes must be reset after annotated text,
|
|
101
|
+
* cursor operations must account for one-based terminal coordinates, and line
|
|
102
|
+
* clearing usually needs to preserve the cursor position expected by the next
|
|
103
|
+
* frame.
|
|
104
|
+
*/
|
|
105
|
+
const ESC = "\x1B[";
|
|
106
|
+
const SEP = ";";
|
|
107
|
+
/**
|
|
108
|
+
* @internal
|
|
109
|
+
*/
|
|
110
|
+
const reset = `${ESC}0m`;
|
|
111
|
+
/**
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
const bold = `${ESC}1m`;
|
|
115
|
+
/**
|
|
116
|
+
* @internal
|
|
117
|
+
*/
|
|
118
|
+
const italicized = `${ESC}3m`;
|
|
119
|
+
/**
|
|
120
|
+
* @internal
|
|
121
|
+
*/
|
|
122
|
+
const underlined = `${ESC}4m`;
|
|
123
|
+
/**
|
|
124
|
+
* @internal
|
|
125
|
+
*/
|
|
126
|
+
const strikethrough = `${ESC}9m`;
|
|
127
|
+
/**
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
const cursorShow = `${ESC}?25h`;
|
|
131
|
+
/**
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
const cursorHide = `${ESC}?25l`;
|
|
135
|
+
/**
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
const eraseLine = `${ESC}2K`;
|
|
139
|
+
/**
|
|
140
|
+
* @internal
|
|
141
|
+
*/
|
|
142
|
+
const red = `${ESC}31m`;
|
|
143
|
+
/**
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
const green = `${ESC}32m`;
|
|
147
|
+
/**
|
|
148
|
+
* @internal
|
|
149
|
+
*/
|
|
150
|
+
const magenta = `${ESC}35m`;
|
|
151
|
+
/**
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
const white = `${ESC}37m`;
|
|
155
|
+
/**
|
|
156
|
+
* @internal
|
|
157
|
+
*/
|
|
158
|
+
const blackBright = `${ESC}90m`;
|
|
159
|
+
/**
|
|
160
|
+
* @internal
|
|
161
|
+
*/
|
|
162
|
+
const cyanBright = `${ESC}96m`;
|
|
163
|
+
/**
|
|
164
|
+
* Wraps `text` in the given styles followed by a reset. When `colors` is
|
|
165
|
+
* `false` the text is returned unchanged, so callers gate color and style
|
|
166
|
+
* escapes in one place while cursor and erase controls stay untouched.
|
|
167
|
+
*
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
170
|
+
const annotate = (colors, text, ...styles) => {
|
|
171
|
+
if (!colors) return text;
|
|
172
|
+
return `${styles.flat().join("")}${text}${reset}`;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Detects whether CLI output should use color and style escapes: stdout must
|
|
176
|
+
* be a TTY and `NO_COLOR` must be unset or empty.
|
|
177
|
+
*
|
|
178
|
+
* @internal
|
|
179
|
+
*/
|
|
180
|
+
const detectColors = () => {
|
|
181
|
+
const globalProcess = globalThis.process;
|
|
182
|
+
return typeof globalProcess === "object" && globalProcess !== null && typeof globalProcess.stdout === "object" && globalProcess.stdout !== null && globalProcess.stdout.isTTY === true && !globalProcess.env?.NO_COLOR;
|
|
183
|
+
};
|
|
184
|
+
const combine = (...styles) => styles;
|
|
185
|
+
/**
|
|
186
|
+
* @internal
|
|
187
|
+
*/
|
|
188
|
+
const cursorTo = (column, row) => {
|
|
189
|
+
if (row === void 0) return `${ESC}${Math.max(column + 1, 0)}G`;
|
|
190
|
+
return `${ESC}${row + 1}${SEP}${Math.max(column + 1, 0)}H`;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* @internal
|
|
194
|
+
*/
|
|
195
|
+
const cursorDown = (lines = 1) => {
|
|
196
|
+
return `${ESC}${lines}B`;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* @internal
|
|
200
|
+
*/
|
|
201
|
+
const cursorMove = (column, row = 0) => {
|
|
202
|
+
let command = "";
|
|
203
|
+
if (row < 0) command += `${ESC}${-row}A`;
|
|
204
|
+
if (row > 0) command += `${ESC}${row}B`;
|
|
205
|
+
if (column > 0) command += `${ESC}${column}C`;
|
|
206
|
+
if (column < 0) command += `${ESC}${-column}D`;
|
|
207
|
+
return command;
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* @internal
|
|
211
|
+
*/
|
|
212
|
+
const eraseLines = (rows) => {
|
|
213
|
+
let command = "";
|
|
214
|
+
for (let i = 0; i < rows; i++) command += `${ESC}2K` + (i < rows - 1 ? `${ESC}1A` : "");
|
|
215
|
+
if (rows > 0) command += `${ESC}G`;
|
|
216
|
+
return command;
|
|
217
|
+
};
|
|
218
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/cli/Prompt.js
|
|
219
|
+
/**
|
|
220
|
+
* Builds interactive terminal prompts for CLI applications.
|
|
221
|
+
*
|
|
222
|
+
* A `Prompt<A>` describes a small terminal UI that renders frames, reads
|
|
223
|
+
* keyboard input, validates responses, and eventually produces an `A`. Prompts
|
|
224
|
+
* can ask for simple values, selections, lists, files, hidden text, or custom
|
|
225
|
+
* interactions. This module includes prompt constructors, tools for combining
|
|
226
|
+
* and transforming prompt output, and support for running prompts through the
|
|
227
|
+
* `Terminal` service.
|
|
228
|
+
*
|
|
229
|
+
* @stability unstable
|
|
230
|
+
* @since 4.0.0
|
|
231
|
+
*/
|
|
232
|
+
const TypeId = "~effect/cli/Prompt";
|
|
233
|
+
const defaultTheme = {
|
|
234
|
+
prefix: "?",
|
|
235
|
+
arrowUp: "↑",
|
|
236
|
+
arrowDown: "↓",
|
|
237
|
+
checkboxOn: "☒",
|
|
238
|
+
checkboxOff: "☐",
|
|
239
|
+
tick: "✔",
|
|
240
|
+
ellipsis: "…",
|
|
241
|
+
pointerSmall: "›",
|
|
242
|
+
pointer: "❯",
|
|
243
|
+
descriptionSeparator: "- ",
|
|
244
|
+
passwordMask: "*",
|
|
245
|
+
toggleSeparator: "/",
|
|
246
|
+
primaryColor: cyanBright,
|
|
247
|
+
mutedColor: blackBright,
|
|
248
|
+
successColor: green,
|
|
249
|
+
errorColor: red,
|
|
250
|
+
submittedColor: white
|
|
251
|
+
};
|
|
252
|
+
const windowsTheme = {
|
|
253
|
+
...defaultTheme,
|
|
254
|
+
checkboxOn: "[*]",
|
|
255
|
+
checkboxOff: "[ ]",
|
|
256
|
+
tick: "√",
|
|
257
|
+
ellipsis: "...",
|
|
258
|
+
pointerSmall: "»",
|
|
259
|
+
pointer: ">"
|
|
260
|
+
};
|
|
261
|
+
/**
|
|
262
|
+
* Creates a prompt theme using the current platform defaults.
|
|
263
|
+
*
|
|
264
|
+
* **Details**
|
|
265
|
+
*
|
|
266
|
+
* Unless `colors` is provided, it is detected when the theme is created:
|
|
267
|
+
* colors are enabled when stdout is a TTY and `NO_COLOR` is unset or empty.
|
|
268
|
+
*
|
|
269
|
+
* @stability unstable
|
|
270
|
+
* @category constructors
|
|
271
|
+
* @since 4.0.0
|
|
272
|
+
*/
|
|
273
|
+
const makeTheme = (options) => ({
|
|
274
|
+
...process.platform === "win32" ? windowsTheme : defaultTheme,
|
|
275
|
+
...options,
|
|
276
|
+
colors: options?.colors ?? detectColors()
|
|
277
|
+
});
|
|
278
|
+
/**
|
|
279
|
+
* Context reference for the theme used by built-in prompts.
|
|
280
|
+
*
|
|
281
|
+
* **Details**
|
|
282
|
+
*
|
|
283
|
+
* Provide this reference once to theme every prompt in an application. A
|
|
284
|
+
* prompt's `theme` option takes precedence over the context value. The
|
|
285
|
+
* command wizard also reads `colors` from this reference, so provide a theme
|
|
286
|
+
* with `colors: false` to disable wizard styling.
|
|
287
|
+
*
|
|
288
|
+
* The default value is created with `makeTheme` the first time it is read,
|
|
289
|
+
* so color detection runs once per process. Changes to `NO_COLOR` after the
|
|
290
|
+
* first prompt do not affect the default theme.
|
|
291
|
+
*
|
|
292
|
+
* @stability unstable
|
|
293
|
+
* @category services
|
|
294
|
+
* @since 4.0.0
|
|
295
|
+
*/
|
|
296
|
+
const Theme = /*#__PURE__*/ Reference("effect/cli/Prompt/Theme", { defaultValue: makeTheme });
|
|
297
|
+
const getTheme = (options) => map$1(Theme, (theme) => ({
|
|
298
|
+
...theme,
|
|
299
|
+
...options.theme
|
|
300
|
+
}));
|
|
301
|
+
const annotateErrorLine = (theme, line) => annotate(theme.colors, line, combine(italicized, theme.errorColor));
|
|
302
|
+
const annotateSymbol = (theme, symbol, ...styles) => symbol.length === 0 ? "" : annotate(theme.colors, symbol, ...styles);
|
|
303
|
+
const separateSymbol = (symbol, text) => symbol.length === 0 ? text : symbol + " " + text;
|
|
304
|
+
const renderPagingPrefix = (theme, showArrowUp, showArrowDown) => {
|
|
305
|
+
const width = Math.max(theme.arrowUp.length, theme.arrowDown.length);
|
|
306
|
+
if (showArrowUp) return theme.arrowUp.padEnd(width);
|
|
307
|
+
if (showArrowDown) return theme.arrowDown.padEnd(width);
|
|
308
|
+
return " ".repeat(width);
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Creates a confirmation prompt that asks the user to choose a boolean yes/no
|
|
312
|
+
* value.
|
|
313
|
+
*
|
|
314
|
+
* **When to use**
|
|
315
|
+
*
|
|
316
|
+
* Use to ask for a yes/no answer that can be submitted directly.
|
|
317
|
+
*
|
|
318
|
+
* **Details**
|
|
319
|
+
*
|
|
320
|
+
* `initial` defaults to `false`. Enter submits the current default, yes-style
|
|
321
|
+
* input submits `true`, no-style input submits `false`, and other input beeps.
|
|
322
|
+
*
|
|
323
|
+
* @see {@link Toggle} for an interactive switch-before-submit boolean prompt
|
|
324
|
+
*
|
|
325
|
+
* @stability unstable
|
|
326
|
+
* @category constructors
|
|
327
|
+
* @since 4.0.0
|
|
328
|
+
*/
|
|
329
|
+
const Confirm = (options) => {
|
|
330
|
+
const opts = {
|
|
331
|
+
initial: false,
|
|
332
|
+
...options,
|
|
333
|
+
label: {
|
|
334
|
+
confirm: "yes",
|
|
335
|
+
deny: "no",
|
|
336
|
+
...options.label
|
|
337
|
+
},
|
|
338
|
+
placeholder: {
|
|
339
|
+
defaultConfirm: "(Y/n)",
|
|
340
|
+
defaultDeny: "(y/N)",
|
|
341
|
+
...options.placeholder
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
const initialState = { value: opts.initial };
|
|
345
|
+
return Custom(initialState, {
|
|
346
|
+
render: handleConfirmRender(opts),
|
|
347
|
+
process: (input) => handleConfirmProcess(input, opts.initial),
|
|
348
|
+
clear: handleConfirmClear(opts)
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* Creates a custom `Prompt` from the specified initial state and handlers.
|
|
353
|
+
*
|
|
354
|
+
* **Details**
|
|
355
|
+
*
|
|
356
|
+
* The initial state can either be a pure value or an `Effect`. This is
|
|
357
|
+
* particularly useful when the initial state of the `Prompt` must be computed
|
|
358
|
+
* by performing an effectful computation, such as reading data from the file
|
|
359
|
+
* system. A `Prompt` runs as a render loop: `render` returns ANSI output for
|
|
360
|
+
* the current frame, the `Terminal` obtains user input, `process` returns the
|
|
361
|
+
* next prompt action, and `clear` returns ANSI output used to clear the previous
|
|
362
|
+
* frame.
|
|
363
|
+
*
|
|
364
|
+
* Optionally, an external `events` dequeue can be provided as the third
|
|
365
|
+
* argument. When present, the render loop will race user input against events
|
|
366
|
+
* from the dequeue, allowing background events to trigger re-renders without
|
|
367
|
+
* waiting for a keypress. When an event is received from the dequeue, the
|
|
368
|
+
* `receive` handler is called instead of `process`.
|
|
369
|
+
*
|
|
370
|
+
* @stability unstable
|
|
371
|
+
* @category constructors
|
|
372
|
+
* @since 4.0.0
|
|
373
|
+
*/
|
|
374
|
+
const Custom = (initialState, ...args) => {
|
|
375
|
+
const [events, handlers] = args.length === 1 ? [void 0, args[0]] : [args[0], args[1]];
|
|
376
|
+
const op = Object.create(proto);
|
|
377
|
+
op._tag = "Loop";
|
|
378
|
+
op.initialState = initialState;
|
|
379
|
+
op.render = handlers.render;
|
|
380
|
+
op.process = handlers.process;
|
|
381
|
+
op.clear = handlers.clear;
|
|
382
|
+
op.events = events;
|
|
383
|
+
return op;
|
|
384
|
+
};
|
|
385
|
+
/**
|
|
386
|
+
* Creates a date prompt that lets the user edit a formatted date value and
|
|
387
|
+
* validates the final `Date` before submission.
|
|
388
|
+
*
|
|
389
|
+
* **Details**
|
|
390
|
+
*
|
|
391
|
+
* `initial` defaults to the current `Date`, `dateMask` defaults to
|
|
392
|
+
* `YYYY-MM-DD HH:mm:ss`, mask parsing creates editable date parts plus literal
|
|
393
|
+
* tokens, `locales` customizes month and weekday labels, and `validate` runs on
|
|
394
|
+
* submission.
|
|
395
|
+
*
|
|
396
|
+
* **Gotchas**
|
|
397
|
+
*
|
|
398
|
+
* A supplied `initial` `Date` is edited in place during prompt interaction.
|
|
399
|
+
* Date edits use JavaScript `Date` setters, so out-of-range typed values can
|
|
400
|
+
* normalize before validation. If the prompt is meant to be editable,
|
|
401
|
+
* `dateMask` should contain at least one editable date token.
|
|
402
|
+
*
|
|
403
|
+
* @stability unstable
|
|
404
|
+
* @category constructors
|
|
405
|
+
* @since 4.0.0
|
|
406
|
+
*/
|
|
407
|
+
const Date = (options) => {
|
|
408
|
+
const opts = {
|
|
409
|
+
initial: new globalThis.Date(),
|
|
410
|
+
dateMask: "YYYY-MM-DD HH:mm:ss",
|
|
411
|
+
validate: succeed$1,
|
|
412
|
+
...options,
|
|
413
|
+
locales: {
|
|
414
|
+
...defaultLocales,
|
|
415
|
+
...options.locales
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
const dateParts = makeDateParts(opts.dateMask, opts.initial, opts.locales);
|
|
419
|
+
const initialState = {
|
|
420
|
+
dateParts,
|
|
421
|
+
typed: "",
|
|
422
|
+
cursor: dateParts.findIndex((part) => !part.isToken()),
|
|
423
|
+
value: opts.initial,
|
|
424
|
+
error: none()
|
|
425
|
+
};
|
|
426
|
+
return Custom(initialState, {
|
|
427
|
+
render: handleDateRender(opts),
|
|
428
|
+
process: handleDateProcess(opts),
|
|
429
|
+
clear: handleDateClear(opts)
|
|
430
|
+
});
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* Composes prompts by using the output of this prompt to create the next prompt.
|
|
434
|
+
*
|
|
435
|
+
* @stability unstable
|
|
436
|
+
* @category combinators
|
|
437
|
+
* @since 4.0.0
|
|
438
|
+
*/
|
|
439
|
+
const flatMap = /*#__PURE__*/ dual(2, (self, f) => {
|
|
440
|
+
const op = Object.create(proto);
|
|
441
|
+
op._tag = "OnSuccess";
|
|
442
|
+
op.prompt = self;
|
|
443
|
+
op.onSuccess = f;
|
|
444
|
+
return op;
|
|
445
|
+
});
|
|
446
|
+
/**
|
|
447
|
+
* Creates a floating-point number prompt.
|
|
448
|
+
*
|
|
449
|
+
* **Details**
|
|
450
|
+
*
|
|
451
|
+
* The prompt supports minimum and maximum bounds, keyboard step sizes, display
|
|
452
|
+
* precision, and additional validation before submission.
|
|
453
|
+
*
|
|
454
|
+
* @stability unstable
|
|
455
|
+
* @category constructors
|
|
456
|
+
* @since 4.0.0
|
|
457
|
+
*/
|
|
458
|
+
const Number = (options) => {
|
|
459
|
+
const opts = {
|
|
460
|
+
default: 0,
|
|
461
|
+
min: globalThis.Number.NEGATIVE_INFINITY,
|
|
462
|
+
max: globalThis.Number.POSITIVE_INFINITY,
|
|
463
|
+
incrementBy: 1,
|
|
464
|
+
decrementBy: 1,
|
|
465
|
+
precision: 2,
|
|
466
|
+
validate: (n) => {
|
|
467
|
+
if (n < opts.min) return fail(`${n} must be greater than or equal to ${opts.min}`);
|
|
468
|
+
if (n > opts.max) return fail(`${n} must be less than or equal to ${opts.max}`);
|
|
469
|
+
return succeed$1(n);
|
|
470
|
+
},
|
|
471
|
+
...options
|
|
472
|
+
};
|
|
473
|
+
const initialValue = options.default === void 0 ? "" : `${opts.default}`;
|
|
474
|
+
const initialState = {
|
|
475
|
+
cursor: initialValue.length,
|
|
476
|
+
value: initialValue,
|
|
477
|
+
error: none()
|
|
478
|
+
};
|
|
479
|
+
return Custom(initialState, {
|
|
480
|
+
render: handleRenderFloat(opts),
|
|
481
|
+
process: handleProcessFloat(opts),
|
|
482
|
+
clear: handleNumberClear(opts)
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
/**
|
|
486
|
+
* Creates an integer prompt.
|
|
487
|
+
*
|
|
488
|
+
* **Details**
|
|
489
|
+
*
|
|
490
|
+
* The prompt supports minimum and maximum bounds, keyboard step sizes, and
|
|
491
|
+
* additional validation before submission.
|
|
492
|
+
*
|
|
493
|
+
* @stability unstable
|
|
494
|
+
* @category constructors
|
|
495
|
+
* @since 4.0.0
|
|
496
|
+
*/
|
|
497
|
+
const Int = (options) => {
|
|
498
|
+
const opts = {
|
|
499
|
+
default: 0,
|
|
500
|
+
min: globalThis.Number.NEGATIVE_INFINITY,
|
|
501
|
+
max: globalThis.Number.POSITIVE_INFINITY,
|
|
502
|
+
incrementBy: 1,
|
|
503
|
+
decrementBy: 1,
|
|
504
|
+
validate: (n) => {
|
|
505
|
+
if (n < opts.min) return fail(`${n} must be greater than or equal to ${opts.min}`);
|
|
506
|
+
if (n > opts.max) return fail(`${n} must be less than or equal to ${opts.max}`);
|
|
507
|
+
return succeed$1(n);
|
|
508
|
+
},
|
|
509
|
+
...options
|
|
510
|
+
};
|
|
511
|
+
const initialValue = options.default === void 0 ? "" : `${opts.default}`;
|
|
512
|
+
const initialState = {
|
|
513
|
+
cursor: initialValue.length,
|
|
514
|
+
value: initialValue,
|
|
515
|
+
error: none()
|
|
516
|
+
};
|
|
517
|
+
return Custom(initialState, {
|
|
518
|
+
render: handleRenderInteger(opts),
|
|
519
|
+
process: handleProcessInteger(opts),
|
|
520
|
+
clear: handleNumberClear(opts)
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
/**
|
|
524
|
+
* Transforms the output value produced by a prompt.
|
|
525
|
+
*
|
|
526
|
+
* @stability unstable
|
|
527
|
+
* @category combinators
|
|
528
|
+
* @since 4.0.0
|
|
529
|
+
*/
|
|
530
|
+
const map = /*#__PURE__*/ dual(2, (self, f) => flatMap(self, (a) => succeed(f(a))));
|
|
531
|
+
/**
|
|
532
|
+
* Creates a password prompt that masks typed input and returns the submitted
|
|
533
|
+
* value wrapped in `Redacted`.
|
|
534
|
+
*
|
|
535
|
+
* @stability unstable
|
|
536
|
+
* @category constructors
|
|
537
|
+
* @since 4.0.0
|
|
538
|
+
*/
|
|
539
|
+
const Password = (options) => basePrompt(options, "password").pipe(map(make$1));
|
|
540
|
+
/**
|
|
541
|
+
* Runs a prompt by reading terminal input and rendering prompt frames until the
|
|
542
|
+
* prompt submits a value.
|
|
543
|
+
*
|
|
544
|
+
* **Gotchas**
|
|
545
|
+
*
|
|
546
|
+
* The returned effect may fail with `Terminal.QuitError` if terminal input ends
|
|
547
|
+
* or the prompt is quit.
|
|
548
|
+
*
|
|
549
|
+
* @stability unstable
|
|
550
|
+
* @category running
|
|
551
|
+
* @since 4.0.0
|
|
552
|
+
*/
|
|
553
|
+
const run = /*#__PURE__*/ fnUntraced(function* (self) {
|
|
554
|
+
const terminal = yield* Terminal;
|
|
555
|
+
const input = yield* cached(terminal.readInput);
|
|
556
|
+
return yield* runWithInput(self, terminal, input);
|
|
557
|
+
}, /*#__PURE__*/ mapError(() => new QuitError({})), scoped);
|
|
558
|
+
const getSelectInitialIndex = (choices) => {
|
|
559
|
+
let initialIndex = 0;
|
|
560
|
+
let seenSelected = -1;
|
|
561
|
+
for (let i = 0; i < choices.length; i++) if (choices[i].selected === true) {
|
|
562
|
+
if (seenSelected !== -1) throw new Error("InvalidArgumentException: only a single choice can be selected by default for Prompt.Select");
|
|
563
|
+
seenSelected = i;
|
|
564
|
+
}
|
|
565
|
+
if (seenSelected !== -1) initialIndex = seenSelected;
|
|
566
|
+
return initialIndex;
|
|
567
|
+
};
|
|
568
|
+
/**
|
|
569
|
+
* Creates a prompt that lets the user select a single value from a list of
|
|
570
|
+
* choices.
|
|
571
|
+
*
|
|
572
|
+
* **Gotchas**
|
|
573
|
+
*
|
|
574
|
+
* At most one choice may be marked as selected by default.
|
|
575
|
+
*
|
|
576
|
+
* @stability unstable
|
|
577
|
+
* @category constructors
|
|
578
|
+
* @since 4.0.0
|
|
579
|
+
*/
|
|
580
|
+
const Select = (options) => {
|
|
581
|
+
const opts = {
|
|
582
|
+
maxPerPage: 10,
|
|
583
|
+
...options
|
|
584
|
+
};
|
|
585
|
+
const initialIndex = getSelectInitialIndex(opts.choices);
|
|
586
|
+
return Custom(initialIndex, {
|
|
587
|
+
render: handleSelectRender(opts),
|
|
588
|
+
process: handleSelectProcess(opts),
|
|
589
|
+
clear: handleSelectClear(opts)
|
|
590
|
+
});
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* Creates a `Prompt` which immediately succeeds with the specified value.
|
|
594
|
+
*
|
|
595
|
+
* **Details**
|
|
596
|
+
*
|
|
597
|
+
* This prompt does not attempt to obtain user input or render anything to the
|
|
598
|
+
* screen.
|
|
599
|
+
*
|
|
600
|
+
* @stability unstable
|
|
601
|
+
* @category constructors
|
|
602
|
+
* @since 4.0.0
|
|
603
|
+
*/
|
|
604
|
+
const succeed = (value) => {
|
|
605
|
+
const op = Object.create(proto);
|
|
606
|
+
op._tag = "Succeed";
|
|
607
|
+
op.value = value;
|
|
608
|
+
return op;
|
|
609
|
+
};
|
|
610
|
+
/**
|
|
611
|
+
* Creates a text-entry prompt that echoes input and returns the submitted
|
|
612
|
+
* string after validation.
|
|
613
|
+
*
|
|
614
|
+
* @stability unstable
|
|
615
|
+
* @category constructors
|
|
616
|
+
* @since 4.0.0
|
|
617
|
+
*/
|
|
618
|
+
const String = (options) => basePrompt(options, "text");
|
|
619
|
+
/**
|
|
620
|
+
* Creates a toggle prompt that lets the user switch between active and inactive
|
|
621
|
+
* states and returns the selected boolean value.
|
|
622
|
+
*
|
|
623
|
+
* @stability unstable
|
|
624
|
+
* @category constructors
|
|
625
|
+
* @since 4.0.0
|
|
626
|
+
*/
|
|
627
|
+
const Toggle = (options) => {
|
|
628
|
+
const opts = {
|
|
629
|
+
initial: false,
|
|
630
|
+
active: "on",
|
|
631
|
+
inactive: "off",
|
|
632
|
+
...options
|
|
633
|
+
};
|
|
634
|
+
return Custom(opts.initial, {
|
|
635
|
+
render: handleToggleRender(opts),
|
|
636
|
+
process: handleToggleProcess,
|
|
637
|
+
clear: () => handleToggleClear(opts)
|
|
638
|
+
});
|
|
639
|
+
};
|
|
640
|
+
const proto = {
|
|
641
|
+
.../*#__PURE__*/ Prototype({
|
|
642
|
+
label: "Prompt",
|
|
643
|
+
evaluate() {
|
|
644
|
+
return run(this);
|
|
645
|
+
}
|
|
646
|
+
}),
|
|
647
|
+
[TypeId]: { _Output: (_) => _ }
|
|
648
|
+
};
|
|
649
|
+
const runWithInput = (prompt, terminal, input) => suspend(() => {
|
|
650
|
+
const op = prompt;
|
|
651
|
+
switch (op._tag) {
|
|
652
|
+
case "Loop": return flatMap$1(input, (queue) => runLoop(op, terminal, queue));
|
|
653
|
+
case "OnSuccess": return flatMap$1(runWithInput(op.prompt, terminal, input), (a) => runWithInput(op.onSuccess(a), terminal, input));
|
|
654
|
+
case "Succeed": return succeed$1(op.value);
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
const runLoop = /*#__PURE__*/ fnUntraced(function* (loop, terminal, input) {
|
|
658
|
+
let state = isEffect(loop.initialState) ? yield* loop.initialState : loop.initialState;
|
|
659
|
+
let action = Action.NextFrame({ state });
|
|
660
|
+
let clear = "";
|
|
661
|
+
while (true) {
|
|
662
|
+
const msg = yield* loop.render(state, action);
|
|
663
|
+
yield* orDie(terminal.display(clear + msg));
|
|
664
|
+
clear = "";
|
|
665
|
+
if (loop.events) {
|
|
666
|
+
const takeInput = take(input).pipe(map$1((input) => ({
|
|
667
|
+
_tag: "Input",
|
|
668
|
+
input
|
|
669
|
+
})));
|
|
670
|
+
const result = yield* raceFirst(takeInput, take(loop.events).pipe(map$1((value) => ({
|
|
671
|
+
_tag: "Event",
|
|
672
|
+
value
|
|
673
|
+
}))));
|
|
674
|
+
action = yield* loop.process(result, state);
|
|
675
|
+
} else {
|
|
676
|
+
const result = yield* take(input);
|
|
677
|
+
action = yield* loop.process(result, state);
|
|
678
|
+
}
|
|
679
|
+
switch (action._tag) {
|
|
680
|
+
case "Beep": continue;
|
|
681
|
+
case "NextFrame":
|
|
682
|
+
clear = yield* loop.clear(state, action);
|
|
683
|
+
state = action.state;
|
|
684
|
+
continue;
|
|
685
|
+
case "Submit": {
|
|
686
|
+
clear = yield* loop.clear(state, action);
|
|
687
|
+
const msg = yield* loop.render(state, action);
|
|
688
|
+
yield* orDie(terminal.display(clear + msg));
|
|
689
|
+
return action.value;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}, (effect, _, terminal) => ensuring(effect, orDie(terminal.display(cursorShow))));
|
|
694
|
+
const Action = /*#__PURE__*/ taggedEnum();
|
|
695
|
+
/**
|
|
696
|
+
* Clears all lines taken up by the specified `text`.
|
|
697
|
+
*/
|
|
698
|
+
const eraseText = (text, columns) => {
|
|
699
|
+
if (columns === 0) return eraseLine + cursorTo(0);
|
|
700
|
+
let rows = 0;
|
|
701
|
+
const lines = text.split(NEWLINE_REGEXP);
|
|
702
|
+
for (const line of lines) rows += 1 + Math.floor(Math.max(line.length - 1, 0) / columns);
|
|
703
|
+
return eraseLines(rows);
|
|
704
|
+
};
|
|
705
|
+
const lines = (prompt, columns) => {
|
|
706
|
+
const lines = prompt.split(NEWLINE_REGEXP);
|
|
707
|
+
return columns === 0 ? lines.length : pipe(map$2(lines, (line) => Math.ceil(line.length / columns)), reduce(0, (left, right) => left + right));
|
|
708
|
+
};
|
|
709
|
+
const clearOutputWithError = (outputText, columns, errorText) => {
|
|
710
|
+
if (errorText !== void 0 && errorText.length > 0) return cursorDown(lines(errorText, columns)) + eraseText(`\n${errorText}`, columns) + eraseText(outputText, columns);
|
|
711
|
+
return eraseText(outputText, columns);
|
|
712
|
+
};
|
|
713
|
+
const renderBeep = "\x07";
|
|
714
|
+
const NEWLINE_REGEXP = /\r?\n/;
|
|
715
|
+
const handleConfirmClear = (options) => {
|
|
716
|
+
return fnUntraced(function* (state, _) {
|
|
717
|
+
const columns = yield* (yield* Terminal).columns;
|
|
718
|
+
const figures = yield* getTheme(options);
|
|
719
|
+
const confirmMessage = state.value ? options.placeholder.defaultConfirm : options.placeholder.defaultDeny;
|
|
720
|
+
const promptText = renderPrompt(confirmMessage, options.message, figures.prefix, figures.pointerSmall, figures, { plain: true });
|
|
721
|
+
return eraseText(promptText, columns) + (eraseLine + "\x1B[G");
|
|
722
|
+
});
|
|
723
|
+
};
|
|
724
|
+
const renderConfirmNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
725
|
+
const figures = yield* getTheme(options);
|
|
726
|
+
const leadingSymbol = annotateSymbol(figures, figures.prefix, figures.primaryColor);
|
|
727
|
+
const trailingSymbol = annotateSymbol(figures, figures.pointerSmall, figures.mutedColor);
|
|
728
|
+
const confirmMessage = state.value ? options.placeholder.defaultConfirm : options.placeholder.defaultDeny;
|
|
729
|
+
const confirm = annotate(figures.colors, confirmMessage, figures.mutedColor);
|
|
730
|
+
const promptMsg = renderPrompt(confirm, options.message, leadingSymbol, trailingSymbol, figures);
|
|
731
|
+
return cursorHide + promptMsg;
|
|
732
|
+
});
|
|
733
|
+
const renderConfirmSubmission = /*#__PURE__*/ fnUntraced(function* (value, options) {
|
|
734
|
+
const figures = yield* getTheme(options);
|
|
735
|
+
const leadingSymbol = annotateSymbol(figures, figures.tick, figures.successColor);
|
|
736
|
+
const trailingSymbol = annotateSymbol(figures, figures.ellipsis, figures.mutedColor);
|
|
737
|
+
const confirmMessage = value ? options.label.confirm : options.label.deny;
|
|
738
|
+
return renderPrompt(confirmMessage, options.message, leadingSymbol, trailingSymbol, figures) + "\n";
|
|
739
|
+
});
|
|
740
|
+
const handleConfirmRender = (options) => {
|
|
741
|
+
return (_, action) => {
|
|
742
|
+
return Action.$match(action, {
|
|
743
|
+
Beep: () => succeed$1(renderBeep),
|
|
744
|
+
NextFrame: ({ state }) => renderConfirmNextFrame(state, options),
|
|
745
|
+
Submit: ({ value }) => renderConfirmSubmission(value, options)
|
|
746
|
+
});
|
|
747
|
+
};
|
|
748
|
+
};
|
|
749
|
+
const TRUE_VALUE_REGEXP = /^y|t$/;
|
|
750
|
+
const FALSE_VALUE_REGEXP = /^n|f$/;
|
|
751
|
+
const handleConfirmProcess = (input, defaultValue) => {
|
|
752
|
+
const value = getOrElse(input.input, () => "");
|
|
753
|
+
if (input.key.name === "enter" || input.key.name === "return") return succeed$1(Action.Submit({ value: defaultValue }));
|
|
754
|
+
if (TRUE_VALUE_REGEXP.test(value.toLowerCase())) return succeed$1(Action.Submit({ value: true }));
|
|
755
|
+
if (FALSE_VALUE_REGEXP.test(value.toLowerCase())) return succeed$1(Action.Submit({ value: false }));
|
|
756
|
+
return succeed$1(Action.Beep());
|
|
757
|
+
};
|
|
758
|
+
const handleDateClear = (options) => {
|
|
759
|
+
return fnUntraced(function* (state, _) {
|
|
760
|
+
const columns = yield* (yield* Terminal).columns;
|
|
761
|
+
const figures = yield* getTheme(options);
|
|
762
|
+
const resetCurrentLine = eraseLine + "\x1B[G";
|
|
763
|
+
const parts = reduce(state.dateParts, "", (doc, part) => doc + part.toString());
|
|
764
|
+
const promptText = renderPrompt(parts, options.message, figures.prefix, figures.pointerSmall, figures, { plain: true });
|
|
765
|
+
const errorText = isSome(state.error) ? match$2(state.error.value.split(NEWLINE_REGEXP), {
|
|
766
|
+
onEmpty: () => "",
|
|
767
|
+
onNonEmpty: (errorLines) => separateSymbol(figures.pointerSmall, errorLines.join("\n"))
|
|
768
|
+
}) : "";
|
|
769
|
+
return clearOutputWithError(promptText, columns, errorText) + resetCurrentLine;
|
|
770
|
+
});
|
|
771
|
+
};
|
|
772
|
+
const renderDateError = (state, pointer, theme) => {
|
|
773
|
+
if (isSome(state.error)) {
|
|
774
|
+
const errorLines = state.error.value.split(NEWLINE_REGEXP);
|
|
775
|
+
if (isReadonlyArrayNonEmpty(errorLines)) {
|
|
776
|
+
const prefix = annotateSymbol(theme, pointer, theme.errorColor);
|
|
777
|
+
const lines = map$2(errorLines, (str) => annotateErrorLine(theme, str));
|
|
778
|
+
return "\x1B[s\n" + separateSymbol(prefix, lines.join("\n")) + "\x1B[u";
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return "";
|
|
782
|
+
};
|
|
783
|
+
const renderParts = (state, theme, submitted = false) => {
|
|
784
|
+
return reduce(state.dateParts, "", (doc, part, currentIndex) => {
|
|
785
|
+
const partDoc = part.toString();
|
|
786
|
+
if (currentIndex === state.cursor && !submitted) {
|
|
787
|
+
const annotation = combine(underlined, theme.primaryColor);
|
|
788
|
+
return doc + annotate(theme.colors, partDoc, annotation);
|
|
789
|
+
}
|
|
790
|
+
return doc + partDoc;
|
|
791
|
+
});
|
|
792
|
+
};
|
|
793
|
+
const renderDateNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
794
|
+
const figures = yield* getTheme(options);
|
|
795
|
+
const leadingSymbol = annotateSymbol(figures, figures.prefix, figures.primaryColor);
|
|
796
|
+
const trailingSymbol = annotateSymbol(figures, figures.pointerSmall, figures.mutedColor);
|
|
797
|
+
const parts = renderParts(state, figures);
|
|
798
|
+
const promptMsg = renderPrompt(parts, options.message, leadingSymbol, trailingSymbol, figures);
|
|
799
|
+
const errorMsg = renderDateError(state, figures.pointerSmall, figures);
|
|
800
|
+
return cursorHide + promptMsg + errorMsg;
|
|
801
|
+
});
|
|
802
|
+
const renderDateSubmission = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
803
|
+
const figures = yield* getTheme(options);
|
|
804
|
+
const leadingSymbol = annotateSymbol(figures, figures.tick, figures.successColor);
|
|
805
|
+
const trailingSymbol = annotateSymbol(figures, figures.ellipsis, figures.mutedColor);
|
|
806
|
+
const parts = renderParts(state, figures, true);
|
|
807
|
+
return renderPrompt(parts, options.message, leadingSymbol, trailingSymbol, figures) + "\n";
|
|
808
|
+
});
|
|
809
|
+
const processUp = (state) => {
|
|
810
|
+
state.dateParts[state.cursor].increment();
|
|
811
|
+
return Action.NextFrame({ state: {
|
|
812
|
+
...state,
|
|
813
|
+
typed: ""
|
|
814
|
+
} });
|
|
815
|
+
};
|
|
816
|
+
const processDown = (state) => {
|
|
817
|
+
state.dateParts[state.cursor].decrement();
|
|
818
|
+
return Action.NextFrame({ state: {
|
|
819
|
+
...state,
|
|
820
|
+
typed: ""
|
|
821
|
+
} });
|
|
822
|
+
};
|
|
823
|
+
const processDateCursorLeft = (state) => {
|
|
824
|
+
const previous = state.dateParts[state.cursor].previousPart();
|
|
825
|
+
if (isSome(previous)) return Action.NextFrame({ state: {
|
|
826
|
+
...state,
|
|
827
|
+
typed: "",
|
|
828
|
+
cursor: state.dateParts.indexOf(previous.value)
|
|
829
|
+
} });
|
|
830
|
+
return Action.Beep();
|
|
831
|
+
};
|
|
832
|
+
const processDateCursorRight = (state) => {
|
|
833
|
+
const next = state.dateParts[state.cursor].nextPart();
|
|
834
|
+
if (isSome(next)) return Action.NextFrame({ state: {
|
|
835
|
+
...state,
|
|
836
|
+
typed: "",
|
|
837
|
+
cursor: state.dateParts.indexOf(next.value)
|
|
838
|
+
} });
|
|
839
|
+
return Action.Beep();
|
|
840
|
+
};
|
|
841
|
+
const processDateNext = (state) => {
|
|
842
|
+
const next = state.dateParts[state.cursor].nextPart();
|
|
843
|
+
const cursor = match(next, {
|
|
844
|
+
onNone: () => state.dateParts.findIndex((part) => !part.isToken()),
|
|
845
|
+
onSome: (next) => state.dateParts.indexOf(next)
|
|
846
|
+
});
|
|
847
|
+
return Action.NextFrame({ state: {
|
|
848
|
+
...state,
|
|
849
|
+
typed: "",
|
|
850
|
+
cursor
|
|
851
|
+
} });
|
|
852
|
+
};
|
|
853
|
+
const defaultDateProcessor = (value, state) => {
|
|
854
|
+
if (/\d/.test(value)) {
|
|
855
|
+
const typed = state.typed + value;
|
|
856
|
+
state.dateParts[state.cursor].setValue(typed);
|
|
857
|
+
return Action.NextFrame({ state: {
|
|
858
|
+
...state,
|
|
859
|
+
typed
|
|
860
|
+
} });
|
|
861
|
+
}
|
|
862
|
+
return Action.Beep();
|
|
863
|
+
};
|
|
864
|
+
const defaultLocales = {
|
|
865
|
+
months: [
|
|
866
|
+
"January",
|
|
867
|
+
"February",
|
|
868
|
+
"March",
|
|
869
|
+
"April",
|
|
870
|
+
"May",
|
|
871
|
+
"June",
|
|
872
|
+
"July",
|
|
873
|
+
"August",
|
|
874
|
+
"September",
|
|
875
|
+
"October",
|
|
876
|
+
"November",
|
|
877
|
+
"December"
|
|
878
|
+
],
|
|
879
|
+
monthsShort: [
|
|
880
|
+
"Jan",
|
|
881
|
+
"Feb",
|
|
882
|
+
"Mar",
|
|
883
|
+
"Apr",
|
|
884
|
+
"May",
|
|
885
|
+
"Jun",
|
|
886
|
+
"Jul",
|
|
887
|
+
"Aug",
|
|
888
|
+
"Sep",
|
|
889
|
+
"Oct",
|
|
890
|
+
"Nov",
|
|
891
|
+
"Dec"
|
|
892
|
+
],
|
|
893
|
+
weekdays: [
|
|
894
|
+
"Sunday",
|
|
895
|
+
"Monday",
|
|
896
|
+
"Tuesday",
|
|
897
|
+
"Wednesday",
|
|
898
|
+
"Thursday",
|
|
899
|
+
"Friday",
|
|
900
|
+
"Saturday"
|
|
901
|
+
],
|
|
902
|
+
weekdaysShort: [
|
|
903
|
+
"Sun",
|
|
904
|
+
"Mon",
|
|
905
|
+
"Tue",
|
|
906
|
+
"Wed",
|
|
907
|
+
"Thu",
|
|
908
|
+
"Fri",
|
|
909
|
+
"Sat"
|
|
910
|
+
]
|
|
911
|
+
};
|
|
912
|
+
const handleDateRender = (options) => {
|
|
913
|
+
return (state, action) => {
|
|
914
|
+
return Action.$match(action, {
|
|
915
|
+
Beep: () => succeed$1(renderBeep),
|
|
916
|
+
NextFrame: ({ state }) => renderDateNextFrame(state, options),
|
|
917
|
+
Submit: () => renderDateSubmission(state, options)
|
|
918
|
+
});
|
|
919
|
+
};
|
|
920
|
+
};
|
|
921
|
+
const handleDateProcess = (options) => {
|
|
922
|
+
return (input, state) => {
|
|
923
|
+
switch (input.key.name) {
|
|
924
|
+
case "left": return succeed$1(processDateCursorLeft(state));
|
|
925
|
+
case "right": return succeed$1(processDateCursorRight(state));
|
|
926
|
+
case "k":
|
|
927
|
+
case "up": return succeed$1(processUp(state));
|
|
928
|
+
case "j":
|
|
929
|
+
case "down": return succeed$1(processDown(state));
|
|
930
|
+
case "tab": return succeed$1(processDateNext(state));
|
|
931
|
+
case "enter":
|
|
932
|
+
case "return": return match$1(options.validate(state.value), {
|
|
933
|
+
onFailure: (error) => Action.NextFrame({ state: {
|
|
934
|
+
...state,
|
|
935
|
+
error: some(error)
|
|
936
|
+
} }),
|
|
937
|
+
onSuccess: (value) => Action.Submit({ value })
|
|
938
|
+
});
|
|
939
|
+
default: return succeed$1(defaultDateProcessor(getOrElse(input.input, () => ""), state));
|
|
940
|
+
}
|
|
941
|
+
};
|
|
942
|
+
};
|
|
943
|
+
const DATE_PART_REGEXP = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g;
|
|
944
|
+
const regExpGroups = {
|
|
945
|
+
1: ({ token, ...opts }) => new Token({
|
|
946
|
+
token: token.replace(/\\(.)/g, "$1"),
|
|
947
|
+
...opts
|
|
948
|
+
}),
|
|
949
|
+
2: (opts) => new Day(opts),
|
|
950
|
+
3: (opts) => new Month(opts),
|
|
951
|
+
4: (opts) => new Year(opts),
|
|
952
|
+
5: (opts) => new Meridiem(opts),
|
|
953
|
+
6: (opts) => new Hours(opts),
|
|
954
|
+
7: (opts) => new Minutes(opts),
|
|
955
|
+
8: (opts) => new Seconds(opts),
|
|
956
|
+
9: (opts) => new Milliseconds(opts)
|
|
957
|
+
};
|
|
958
|
+
const makeDateParts = (dateMask, date, locales) => {
|
|
959
|
+
const parts = [];
|
|
960
|
+
let result = null;
|
|
961
|
+
while (result = DATE_PART_REGEXP.exec(dateMask)) {
|
|
962
|
+
const match = result.shift();
|
|
963
|
+
const index = result.findIndex((group) => group !== void 0);
|
|
964
|
+
if (index in regExpGroups) {
|
|
965
|
+
const token = result[index] || match;
|
|
966
|
+
parts.push(regExpGroups[index]({
|
|
967
|
+
token,
|
|
968
|
+
date,
|
|
969
|
+
parts,
|
|
970
|
+
locales
|
|
971
|
+
}));
|
|
972
|
+
} else parts.push(new Token({
|
|
973
|
+
token: result[index] || match,
|
|
974
|
+
date,
|
|
975
|
+
parts,
|
|
976
|
+
locales
|
|
977
|
+
}));
|
|
978
|
+
}
|
|
979
|
+
const orderedParts = parts.reduce((array, element) => {
|
|
980
|
+
const lastElement = array[array.length - 1];
|
|
981
|
+
if (element.isToken() && lastElement !== void 0 && lastElement.isToken()) lastElement.setValue(element.token);
|
|
982
|
+
else array.push(element);
|
|
983
|
+
return array;
|
|
984
|
+
}, empty());
|
|
985
|
+
parts.splice(0, parts.length, ...orderedParts);
|
|
986
|
+
return parts;
|
|
987
|
+
};
|
|
988
|
+
var DatePart = class {
|
|
989
|
+
token;
|
|
990
|
+
date;
|
|
991
|
+
parts;
|
|
992
|
+
locales;
|
|
993
|
+
constructor(params) {
|
|
994
|
+
this.token = params.token;
|
|
995
|
+
this.locales = params.locales;
|
|
996
|
+
this.date = params.date || new globalThis.Date();
|
|
997
|
+
this.parts = params.parts || [this];
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Returns `true` if this `DatePart` is a `Token`, `false` otherwise.
|
|
1001
|
+
*/
|
|
1002
|
+
isToken() {
|
|
1003
|
+
return false;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Retrieves the next date part in the list of parts.
|
|
1007
|
+
*/
|
|
1008
|
+
nextPart() {
|
|
1009
|
+
const currentPartIndex = getOrElse(findFirstIndex(this.parts, (part) => part === this), () => 0);
|
|
1010
|
+
return findFirst(this.parts.slice(currentPartIndex + 1), (part) => !part.isToken());
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Retrieves the previous date part in the list of parts.
|
|
1014
|
+
*/
|
|
1015
|
+
previousPart() {
|
|
1016
|
+
const currentPartIndex = findFirstIndex(this.parts, (part) => part === this);
|
|
1017
|
+
if (isSome(currentPartIndex)) return findLast(this.parts.slice(0, currentPartIndex.value), (part) => !part.isToken());
|
|
1018
|
+
return none();
|
|
1019
|
+
}
|
|
1020
|
+
toString() {
|
|
1021
|
+
return globalThis.String(this.date);
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
var Token = class extends DatePart {
|
|
1025
|
+
increment() {}
|
|
1026
|
+
decrement() {}
|
|
1027
|
+
setValue(value) {
|
|
1028
|
+
this.token = this.token + value;
|
|
1029
|
+
}
|
|
1030
|
+
isToken() {
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
toString() {
|
|
1034
|
+
return this.token;
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
var Milliseconds = class extends DatePart {
|
|
1038
|
+
increment() {
|
|
1039
|
+
this.date.setMilliseconds(this.date.getMilliseconds() + 1);
|
|
1040
|
+
}
|
|
1041
|
+
decrement() {
|
|
1042
|
+
this.date.setMilliseconds(this.date.getMilliseconds() - 1);
|
|
1043
|
+
}
|
|
1044
|
+
setValue(value) {
|
|
1045
|
+
this.date.setMilliseconds(globalThis.Number.parseInt(value.slice(-this.token.length)));
|
|
1046
|
+
}
|
|
1047
|
+
toString() {
|
|
1048
|
+
return `${this.date.getMilliseconds()}`.padStart(4, "0").substring(0, this.token.length);
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
var Seconds = class extends DatePart {
|
|
1052
|
+
increment() {
|
|
1053
|
+
this.date.setSeconds(this.date.getSeconds() + 1);
|
|
1054
|
+
}
|
|
1055
|
+
decrement() {
|
|
1056
|
+
this.date.setSeconds(this.date.getSeconds() - 1);
|
|
1057
|
+
}
|
|
1058
|
+
setValue(value) {
|
|
1059
|
+
this.date.setSeconds(globalThis.Number.parseInt(value.slice(-2)));
|
|
1060
|
+
}
|
|
1061
|
+
toString() {
|
|
1062
|
+
const seconds = `${this.date.getSeconds()}`;
|
|
1063
|
+
return this.token.length > 1 ? seconds.padStart(2, "0") : seconds;
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
var Minutes = class extends DatePart {
|
|
1067
|
+
increment() {
|
|
1068
|
+
this.date.setMinutes(this.date.getMinutes() + 1);
|
|
1069
|
+
}
|
|
1070
|
+
decrement() {
|
|
1071
|
+
this.date.setMinutes(this.date.getMinutes() - 1);
|
|
1072
|
+
}
|
|
1073
|
+
setValue(value) {
|
|
1074
|
+
this.date.setMinutes(globalThis.Number.parseInt(value.slice(-2)));
|
|
1075
|
+
}
|
|
1076
|
+
toString() {
|
|
1077
|
+
const minutes = `${this.date.getMinutes()}`;
|
|
1078
|
+
return this.token.length > 1 ? minutes.padStart(2, "0") : minutes;
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
var Hours = class extends DatePart {
|
|
1082
|
+
increment() {
|
|
1083
|
+
this.date.setHours(this.date.getHours() + 1);
|
|
1084
|
+
}
|
|
1085
|
+
decrement() {
|
|
1086
|
+
this.date.setHours(this.date.getHours() - 1);
|
|
1087
|
+
}
|
|
1088
|
+
setValue(value) {
|
|
1089
|
+
this.date.setHours(globalThis.Number.parseInt(value.slice(-2)));
|
|
1090
|
+
}
|
|
1091
|
+
toString() {
|
|
1092
|
+
const hours = /h/.test(this.token) ? this.date.getHours() % 12 || 12 : this.date.getHours();
|
|
1093
|
+
return this.token.length > 1 ? `${hours}`.padStart(2, "0") : `${hours}`;
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
var Day = class extends DatePart {
|
|
1097
|
+
increment() {
|
|
1098
|
+
this.date.setDate(this.date.getDate() + 1);
|
|
1099
|
+
}
|
|
1100
|
+
decrement() {
|
|
1101
|
+
this.date.setDate(this.date.getDate() - 1);
|
|
1102
|
+
}
|
|
1103
|
+
setValue(value) {
|
|
1104
|
+
this.date.setDate(globalThis.Number.parseInt(value.slice(-2)));
|
|
1105
|
+
}
|
|
1106
|
+
toString() {
|
|
1107
|
+
const date = this.date.getDate();
|
|
1108
|
+
const day = this.date.getDay();
|
|
1109
|
+
switch (this.token) {
|
|
1110
|
+
case "DD": return `${date}`.padStart(2, "0");
|
|
1111
|
+
case "Do": return `${date}${this.ordinalIndicator(date)}`;
|
|
1112
|
+
case "d": return `${day + 1}`;
|
|
1113
|
+
case "ddd": return this.locales.weekdaysShort[day];
|
|
1114
|
+
case "dddd": return this.locales.weekdays[day];
|
|
1115
|
+
default: return `${date}`;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
ordinalIndicator(day) {
|
|
1119
|
+
if (day >= 11 && day <= 13) return "th";
|
|
1120
|
+
switch (day % 10) {
|
|
1121
|
+
case 1: return "st";
|
|
1122
|
+
case 2: return "nd";
|
|
1123
|
+
case 3: return "rd";
|
|
1124
|
+
default: return "th";
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
var Month = class extends DatePart {
|
|
1129
|
+
increment() {
|
|
1130
|
+
this.date.setMonth(this.date.getMonth() + 1);
|
|
1131
|
+
}
|
|
1132
|
+
decrement() {
|
|
1133
|
+
this.date.setMonth(this.date.getMonth() - 1);
|
|
1134
|
+
}
|
|
1135
|
+
setValue(value) {
|
|
1136
|
+
const month = globalThis.Number.parseInt(value.slice(-2)) - 1;
|
|
1137
|
+
this.date.setMonth(month < 0 ? 0 : month);
|
|
1138
|
+
}
|
|
1139
|
+
toString() {
|
|
1140
|
+
const month = this.date.getMonth();
|
|
1141
|
+
switch (this.token.length) {
|
|
1142
|
+
case 2: return `${month + 1}`.padStart(2, "0");
|
|
1143
|
+
case 3: return this.locales.monthsShort[month];
|
|
1144
|
+
case 4: return this.locales.months[month];
|
|
1145
|
+
default: return `${month + 1}`;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
var Year = class extends DatePart {
|
|
1150
|
+
increment() {
|
|
1151
|
+
this.date.setFullYear(this.date.getFullYear() + 1);
|
|
1152
|
+
}
|
|
1153
|
+
decrement() {
|
|
1154
|
+
this.date.setFullYear(this.date.getFullYear() - 1);
|
|
1155
|
+
}
|
|
1156
|
+
setValue(value) {
|
|
1157
|
+
this.date.setFullYear(globalThis.Number.parseInt(value.slice(-4)));
|
|
1158
|
+
}
|
|
1159
|
+
toString() {
|
|
1160
|
+
const year = `${this.date.getFullYear()}`.padStart(4, "0");
|
|
1161
|
+
return this.token.length === 2 ? year.slice(-2) : year;
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
var Meridiem = class extends DatePart {
|
|
1165
|
+
increment() {
|
|
1166
|
+
this.date.setHours((this.date.getHours() + 12) % 24);
|
|
1167
|
+
}
|
|
1168
|
+
decrement() {
|
|
1169
|
+
this.increment();
|
|
1170
|
+
}
|
|
1171
|
+
setValue(_value) {}
|
|
1172
|
+
toString() {
|
|
1173
|
+
const meridiem = this.date.getHours() >= 12 ? "pm" : "am";
|
|
1174
|
+
return /A/.test(this.token) ? meridiem.toUpperCase() : meridiem;
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
const renderPrompt = (confirm, message, leadingSymbol, trailingSymbol, theme, options) => {
|
|
1178
|
+
const prefix = leadingSymbol.length === 0 ? "" : leadingSymbol + " ";
|
|
1179
|
+
const renderLine = (line) => {
|
|
1180
|
+
let output = prefix + line;
|
|
1181
|
+
if (trailingSymbol.length > 0) output += " " + trailingSymbol;
|
|
1182
|
+
if (confirm.length > 0) output += " " + confirm;
|
|
1183
|
+
else if (trailingSymbol.length > 0) output += " ";
|
|
1184
|
+
return output;
|
|
1185
|
+
};
|
|
1186
|
+
return match$2(message.split(NEWLINE_REGEXP), {
|
|
1187
|
+
onEmpty: () => renderLine(""),
|
|
1188
|
+
onNonEmpty: (promptLines) => {
|
|
1189
|
+
const lines = options?.plain === true ? promptLines : map$2(promptLines, (line) => annotate(theme.colors, line, bold));
|
|
1190
|
+
return renderLine(lines.join("\n"));
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
};
|
|
1194
|
+
const renderChoiceDescription = (choice, isActive, theme, renderOptions) => {
|
|
1195
|
+
if (!choice.disabled && choice.description && isActive) {
|
|
1196
|
+
const text = theme.descriptionSeparator + choice.description;
|
|
1197
|
+
return renderOptions?.plain === true ? text : annotate(theme.colors, text, theme.mutedColor);
|
|
1198
|
+
}
|
|
1199
|
+
return "";
|
|
1200
|
+
};
|
|
1201
|
+
const handleNumberClear = (options) => {
|
|
1202
|
+
return fnUntraced(function* (state, _) {
|
|
1203
|
+
const columns = yield* (yield* Terminal).columns;
|
|
1204
|
+
const figures = yield* getTheme(options);
|
|
1205
|
+
const resetCurrentLine = eraseLine + "\x1B[G";
|
|
1206
|
+
const errorText = renderNumberError(state, figures.pointerSmall, figures, { plain: true });
|
|
1207
|
+
const promptText = renderNumberOutput(state, figures.prefix, figures.pointerSmall, options, figures, { plain: true });
|
|
1208
|
+
return clearOutputWithError(promptText, columns, errorText) + resetCurrentLine;
|
|
1209
|
+
});
|
|
1210
|
+
};
|
|
1211
|
+
const renderNumberInput = (state, submitted, theme, renderOptions) => {
|
|
1212
|
+
const value = state.value === "" ? "" : `${state.value}`;
|
|
1213
|
+
if (submitted || renderOptions?.plain === true) return value;
|
|
1214
|
+
const annotation = isSome(state.error) ? theme.errorColor : combine(underlined, theme.primaryColor);
|
|
1215
|
+
return annotate(theme.colors, value, annotation);
|
|
1216
|
+
};
|
|
1217
|
+
const renderNumberError = (state, pointer, theme, renderOptions) => {
|
|
1218
|
+
if (isSome(state.error)) return match$2(state.error.value.split(NEWLINE_REGEXP), {
|
|
1219
|
+
onEmpty: () => "",
|
|
1220
|
+
onNonEmpty: (errorLines) => {
|
|
1221
|
+
if (renderOptions?.plain === true) return separateSymbol(pointer, errorLines.join("\n"));
|
|
1222
|
+
const prefix = annotateSymbol(theme, pointer, theme.errorColor);
|
|
1223
|
+
const lines = map$2(errorLines, (str) => annotateErrorLine(theme, str));
|
|
1224
|
+
return "\x1B[s\n" + separateSymbol(prefix, lines.join("\n")) + "\x1B[u";
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
return "";
|
|
1228
|
+
};
|
|
1229
|
+
const renderNumberOutput = (state, leadingSymbol, trailingSymbol, options, theme, renderOptions, submitted = false) => {
|
|
1230
|
+
const value = renderNumberInput(state, submitted, theme, renderOptions);
|
|
1231
|
+
return renderPrompt(value, options.message, leadingSymbol, trailingSymbol, theme, renderOptions);
|
|
1232
|
+
};
|
|
1233
|
+
const renderNumberNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1234
|
+
const figures = yield* getTheme(options);
|
|
1235
|
+
const leadingSymbol = annotateSymbol(figures, figures.prefix, figures.primaryColor);
|
|
1236
|
+
const trailingSymbol = annotateSymbol(figures, figures.pointerSmall, figures.mutedColor);
|
|
1237
|
+
const errorMsg = renderNumberError(state, figures.pointerSmall, figures);
|
|
1238
|
+
return renderNumberOutput(state, leadingSymbol, trailingSymbol, options, figures) + errorMsg;
|
|
1239
|
+
});
|
|
1240
|
+
const renderNumberSubmission = /*#__PURE__*/ fnUntraced(function* (nextState, options) {
|
|
1241
|
+
const figures = yield* getTheme(options);
|
|
1242
|
+
const leadingSymbol = annotateSymbol(figures, figures.tick, figures.successColor);
|
|
1243
|
+
const trailingSymbol = annotateSymbol(figures, figures.ellipsis, figures.mutedColor);
|
|
1244
|
+
return renderNumberOutput(nextState, leadingSymbol, trailingSymbol, options, figures, void 0, true) + "\n";
|
|
1245
|
+
});
|
|
1246
|
+
const processNumberBackspace = (state) => {
|
|
1247
|
+
if (state.value.length <= 0) return succeed$1(Action.Beep());
|
|
1248
|
+
const value = state.value.slice(0, state.value.length - 1);
|
|
1249
|
+
return succeed$1(Action.NextFrame({ state: {
|
|
1250
|
+
...state,
|
|
1251
|
+
value,
|
|
1252
|
+
error: none()
|
|
1253
|
+
} }));
|
|
1254
|
+
};
|
|
1255
|
+
const processNumberClear = (state) => succeed$1(Action.NextFrame({ state: {
|
|
1256
|
+
...state,
|
|
1257
|
+
cursor: 0,
|
|
1258
|
+
value: "",
|
|
1259
|
+
error: none()
|
|
1260
|
+
} }));
|
|
1261
|
+
const defaultIntProcessor = (input, state) => {
|
|
1262
|
+
if (state.value.length === 0 && input === "-") return succeed$1(Action.NextFrame({ state: {
|
|
1263
|
+
...state,
|
|
1264
|
+
value: "-",
|
|
1265
|
+
error: none()
|
|
1266
|
+
} }));
|
|
1267
|
+
const parsed = globalThis.Number.parseInt(state.value + input);
|
|
1268
|
+
if (globalThis.Number.isNaN(parsed)) return succeed$1(Action.Beep());
|
|
1269
|
+
else return succeed$1(Action.NextFrame({ state: {
|
|
1270
|
+
...state,
|
|
1271
|
+
value: `${parsed}`,
|
|
1272
|
+
error: none()
|
|
1273
|
+
} }));
|
|
1274
|
+
};
|
|
1275
|
+
const defaultFloatProcessor = (input, state) => {
|
|
1276
|
+
if (input === "." && state.value.includes(".")) return succeed$1(Action.Beep());
|
|
1277
|
+
if (state.value.length === 0 && input === "-") return succeed$1(Action.NextFrame({ state: {
|
|
1278
|
+
...state,
|
|
1279
|
+
value: "-",
|
|
1280
|
+
error: none()
|
|
1281
|
+
} }));
|
|
1282
|
+
const parsed = globalThis.Number.parseFloat(state.value + input);
|
|
1283
|
+
if (globalThis.Number.isNaN(parsed)) return succeed$1(Action.Beep());
|
|
1284
|
+
else return succeed$1(Action.NextFrame({ state: {
|
|
1285
|
+
...state,
|
|
1286
|
+
value: input === "." ? `${parsed}.` : state.value.includes(".") && /^\d$/.test(input) ? state.value + input : `${parsed}`,
|
|
1287
|
+
error: none()
|
|
1288
|
+
} }));
|
|
1289
|
+
};
|
|
1290
|
+
const handleRenderInteger = (options) => {
|
|
1291
|
+
return (state, action) => {
|
|
1292
|
+
return Action.$match(action, {
|
|
1293
|
+
Beep: () => succeed$1(renderBeep),
|
|
1294
|
+
NextFrame: ({ state }) => renderNumberNextFrame(state, options),
|
|
1295
|
+
Submit: () => renderNumberSubmission(state, options)
|
|
1296
|
+
});
|
|
1297
|
+
};
|
|
1298
|
+
};
|
|
1299
|
+
const handleProcessInteger = (options) => {
|
|
1300
|
+
return (input, state) => {
|
|
1301
|
+
if (input.key.ctrl && input.key.name === "u") return processNumberClear(state);
|
|
1302
|
+
switch (input.key.name) {
|
|
1303
|
+
case "backspace": return processNumberBackspace(state);
|
|
1304
|
+
case "k":
|
|
1305
|
+
case "up": return succeed$1(Action.NextFrame({ state: {
|
|
1306
|
+
...state,
|
|
1307
|
+
value: state.value === "" || state.value === "-" ? `${options.incrementBy}` : `${globalThis.Number.parseInt(state.value) + options.incrementBy}`,
|
|
1308
|
+
error: none()
|
|
1309
|
+
} }));
|
|
1310
|
+
case "j":
|
|
1311
|
+
case "down": return succeed$1(Action.NextFrame({ state: {
|
|
1312
|
+
...state,
|
|
1313
|
+
value: state.value === "" || state.value === "-" ? `-${options.decrementBy}` : `${globalThis.Number.parseInt(state.value) - options.decrementBy}`,
|
|
1314
|
+
error: none()
|
|
1315
|
+
} }));
|
|
1316
|
+
case "enter":
|
|
1317
|
+
case "return": {
|
|
1318
|
+
const parsed = globalThis.Number.parseInt(state.value);
|
|
1319
|
+
if (globalThis.Number.isNaN(parsed)) return succeed$1(Action.NextFrame({ state: {
|
|
1320
|
+
...state,
|
|
1321
|
+
error: some("Must provide an integer value")
|
|
1322
|
+
} }));
|
|
1323
|
+
else return match$1(options.validate(parsed), {
|
|
1324
|
+
onFailure: (error) => Action.NextFrame({ state: {
|
|
1325
|
+
...state,
|
|
1326
|
+
error: some(error)
|
|
1327
|
+
} }),
|
|
1328
|
+
onSuccess: (value) => Action.Submit({ value })
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
default: return defaultIntProcessor(getOrElse(input.input, () => ""), state);
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
};
|
|
1335
|
+
const handleRenderFloat = (options) => {
|
|
1336
|
+
return (state, action) => {
|
|
1337
|
+
return Action.$match(action, {
|
|
1338
|
+
Beep: () => succeed$1(renderBeep),
|
|
1339
|
+
NextFrame: ({ state }) => renderNumberNextFrame(state, options),
|
|
1340
|
+
Submit: () => renderNumberSubmission(state, options)
|
|
1341
|
+
});
|
|
1342
|
+
};
|
|
1343
|
+
};
|
|
1344
|
+
const handleProcessFloat = (options) => {
|
|
1345
|
+
return (input, state) => {
|
|
1346
|
+
if (input.key.ctrl && input.key.name === "u") return processNumberClear(state);
|
|
1347
|
+
switch (input.key.name) {
|
|
1348
|
+
case "backspace": return processNumberBackspace(state);
|
|
1349
|
+
case "k":
|
|
1350
|
+
case "up": return succeed$1(Action.NextFrame({ state: {
|
|
1351
|
+
...state,
|
|
1352
|
+
value: state.value === "" || state.value === "-" ? `${options.incrementBy}` : `${globalThis.Number.parseFloat(state.value) + options.incrementBy}`,
|
|
1353
|
+
error: none()
|
|
1354
|
+
} }));
|
|
1355
|
+
case "j":
|
|
1356
|
+
case "down": return succeed$1(Action.NextFrame({ state: {
|
|
1357
|
+
...state,
|
|
1358
|
+
value: state.value === "" || state.value === "-" ? `-${options.decrementBy}` : `${globalThis.Number.parseFloat(state.value) - options.decrementBy}`,
|
|
1359
|
+
error: none()
|
|
1360
|
+
} }));
|
|
1361
|
+
case "enter":
|
|
1362
|
+
case "return": {
|
|
1363
|
+
const parsed = globalThis.Number.parseFloat(state.value);
|
|
1364
|
+
if (globalThis.Number.isNaN(parsed)) return succeed$1(Action.NextFrame({ state: {
|
|
1365
|
+
...state,
|
|
1366
|
+
error: some("Must provide a floating point value")
|
|
1367
|
+
} }));
|
|
1368
|
+
else return flatMap$1(sync(() => round(parsed, options.precision)), (rounded) => match$1(options.validate(rounded), {
|
|
1369
|
+
onFailure: (error) => Action.NextFrame({ state: {
|
|
1370
|
+
...state,
|
|
1371
|
+
error: some(error)
|
|
1372
|
+
} }),
|
|
1373
|
+
onSuccess: (value) => Action.Submit({ value })
|
|
1374
|
+
}));
|
|
1375
|
+
}
|
|
1376
|
+
default: return defaultFloatProcessor(getOrElse(input.input, () => ""), state);
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
};
|
|
1380
|
+
const renderSelectOutput = (leadingSymbol, trailingSymbol, options, theme, renderOptions) => options.message === void 0 ? void 0 : renderPrompt("", options.message, leadingSymbol, trailingSymbol, theme, renderOptions);
|
|
1381
|
+
const withSelectHeader = (header, body) => header === void 0 ? body : header + "\n" + body;
|
|
1382
|
+
const renderChoicePrefix = (state, choices, toDisplay, currentIndex, figures, renderOptions) => {
|
|
1383
|
+
const prefix = renderPagingPrefix(figures, currentIndex === toDisplay.startIndex && toDisplay.startIndex > 0, currentIndex === toDisplay.endIndex - 1 && toDisplay.endIndex < choices.length);
|
|
1384
|
+
if (renderOptions?.plain === true) return state === currentIndex ? figures.pointer + prefix : prefix + " ".repeat(figures.pointer.length);
|
|
1385
|
+
if (choices[currentIndex].disabled) {
|
|
1386
|
+
const annotation = combine(bold, figures.mutedColor);
|
|
1387
|
+
return state === currentIndex ? annotateSymbol(figures, figures.pointer, annotation) + prefix : prefix + " ".repeat(figures.pointer.length);
|
|
1388
|
+
}
|
|
1389
|
+
return state === currentIndex ? annotateSymbol(figures, figures.pointer, figures.primaryColor) + prefix : prefix + " ".repeat(figures.pointer.length);
|
|
1390
|
+
};
|
|
1391
|
+
const renderChoiceTitle = (choice, isSelected, theme, renderOptions) => {
|
|
1392
|
+
if (renderOptions?.plain === true) return choice.title;
|
|
1393
|
+
const title = choice.title;
|
|
1394
|
+
if (isSelected) return choice.disabled ? annotate(theme.colors, title, combine(underlined, theme.mutedColor)) : annotate(theme.colors, title, combine(underlined, theme.primaryColor));
|
|
1395
|
+
return choice.disabled ? annotate(theme.colors, title, combine(strikethrough, theme.mutedColor)) : title;
|
|
1396
|
+
};
|
|
1397
|
+
const renderSelectChoices = (state, options, figures, renderOptions) => {
|
|
1398
|
+
const choices = options.choices;
|
|
1399
|
+
const toDisplay = entriesToDisplay(state, choices.length, options.maxPerPage);
|
|
1400
|
+
const documents = [];
|
|
1401
|
+
for (let index = toDisplay.startIndex; index < toDisplay.endIndex; index++) {
|
|
1402
|
+
const choice = choices[index];
|
|
1403
|
+
const isSelected = state === index;
|
|
1404
|
+
const prefix = renderChoicePrefix(state, choices, toDisplay, index, figures, renderOptions);
|
|
1405
|
+
const title = renderChoiceTitle(choice, isSelected, figures, renderOptions);
|
|
1406
|
+
const description = renderChoiceDescription(choice, isSelected, figures, renderOptions);
|
|
1407
|
+
documents.push(prefix + title + " " + description);
|
|
1408
|
+
}
|
|
1409
|
+
return documents.join("\n");
|
|
1410
|
+
};
|
|
1411
|
+
const renderSelectNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1412
|
+
const figures = yield* getTheme(options);
|
|
1413
|
+
const choices = renderSelectChoices(state, options, figures);
|
|
1414
|
+
const leadingSymbol = annotateSymbol(figures, figures.prefix, figures.primaryColor);
|
|
1415
|
+
const trailingSymbol = annotateSymbol(figures, figures.pointerSmall, figures.mutedColor);
|
|
1416
|
+
const promptMsg = renderSelectOutput(leadingSymbol, trailingSymbol, options, figures);
|
|
1417
|
+
return cursorHide + withSelectHeader(promptMsg, choices);
|
|
1418
|
+
});
|
|
1419
|
+
const renderSelectSubmission = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1420
|
+
const figures = yield* getTheme(options);
|
|
1421
|
+
const selected = options.choices[state].title;
|
|
1422
|
+
const leadingSymbol = annotateSymbol(figures, figures.tick, figures.successColor);
|
|
1423
|
+
const trailingSymbol = annotateSymbol(figures, figures.ellipsis, figures.mutedColor);
|
|
1424
|
+
return (renderSelectOutput(leadingSymbol, trailingSymbol, options, figures) ?? leadingSymbol) + " " + annotate(figures.colors, selected, figures.submittedColor) + "\n";
|
|
1425
|
+
});
|
|
1426
|
+
const processSelectCursorUp = (state, choices) => {
|
|
1427
|
+
if (state === 0) return succeed$1(Action.NextFrame({ state: choices.length - 1 }));
|
|
1428
|
+
return succeed$1(Action.NextFrame({ state: state - 1 }));
|
|
1429
|
+
};
|
|
1430
|
+
const processSelectCursorDown = (state, choices) => {
|
|
1431
|
+
if (state === choices.length - 1) return succeed$1(Action.NextFrame({ state: 0 }));
|
|
1432
|
+
return succeed$1(Action.NextFrame({ state: state + 1 }));
|
|
1433
|
+
};
|
|
1434
|
+
const processSelectNext = (state, choices) => {
|
|
1435
|
+
return succeed$1(Action.NextFrame({ state: (state + 1) % choices.length }));
|
|
1436
|
+
};
|
|
1437
|
+
const handleSelectRender = (options) => {
|
|
1438
|
+
return (state, action) => {
|
|
1439
|
+
return Action.$match(action, {
|
|
1440
|
+
Beep: () => succeed$1(renderBeep),
|
|
1441
|
+
NextFrame: ({ state }) => renderSelectNextFrame(state, options),
|
|
1442
|
+
Submit: () => renderSelectSubmission(state, options)
|
|
1443
|
+
});
|
|
1444
|
+
};
|
|
1445
|
+
};
|
|
1446
|
+
const handleSelectClear = (options) => fnUntraced(function* (state, _) {
|
|
1447
|
+
const columns = yield* (yield* Terminal).columns;
|
|
1448
|
+
const figures = yield* getTheme(options);
|
|
1449
|
+
const clearPrompt = eraseLine + "\x1B[G";
|
|
1450
|
+
const promptText = renderSelectOutput(figures.prefix, figures.pointerSmall, options, figures, { plain: true });
|
|
1451
|
+
const choicesText = renderSelectChoices(state, options, figures, { plain: true });
|
|
1452
|
+
return eraseText(withSelectHeader(promptText, choicesText), columns) + clearPrompt;
|
|
1453
|
+
});
|
|
1454
|
+
const handleSelectProcess = (options) => {
|
|
1455
|
+
return (input, state) => {
|
|
1456
|
+
switch (input.key.name) {
|
|
1457
|
+
case "k":
|
|
1458
|
+
case "up": return processSelectCursorUp(state, options.choices);
|
|
1459
|
+
case "j":
|
|
1460
|
+
case "down": return processSelectCursorDown(state, options.choices);
|
|
1461
|
+
case "tab": return processSelectNext(state, options.choices);
|
|
1462
|
+
case "enter":
|
|
1463
|
+
case "return": {
|
|
1464
|
+
const selected = options.choices[state];
|
|
1465
|
+
if (selected.disabled) return succeed$1(Action.Beep());
|
|
1466
|
+
return succeed$1(Action.Submit({ value: selected.value }));
|
|
1467
|
+
}
|
|
1468
|
+
default: return succeed$1(Action.Beep());
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
};
|
|
1472
|
+
const renderClearScreen = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1473
|
+
const columns = yield* (yield* Terminal).columns;
|
|
1474
|
+
const figures = yield* getTheme(options);
|
|
1475
|
+
const resetCurrentLine = eraseLine + "\x1B[G";
|
|
1476
|
+
const errorText = renderTextError(state, figures.pointerSmall, figures, { plain: true });
|
|
1477
|
+
return clearOutputWithError(renderTextOutput(state, figures.prefix, figures.pointerSmall, options, figures, { plain: true }), columns, errorText) + resetCurrentLine;
|
|
1478
|
+
});
|
|
1479
|
+
const renderTextInput = (nextState, options, theme, submitted, renderOptions) => {
|
|
1480
|
+
const text = nextState.value;
|
|
1481
|
+
if (renderOptions?.plain === true) switch (options.type) {
|
|
1482
|
+
case "hidden": return "";
|
|
1483
|
+
case "password": return theme.passwordMask.repeat(text.length);
|
|
1484
|
+
case "text": return text;
|
|
1485
|
+
}
|
|
1486
|
+
if (text.length === 0) return "";
|
|
1487
|
+
const annotation = isSome(nextState.error) ? theme.errorColor : submitted ? theme.submittedColor : combine(underlined, theme.primaryColor);
|
|
1488
|
+
switch (options.type) {
|
|
1489
|
+
case "hidden": return "";
|
|
1490
|
+
case "password": return annotateSymbol(theme, theme.passwordMask.repeat(text.length), annotation);
|
|
1491
|
+
case "text": return annotate(theme.colors, text, annotation);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
const renderTextError = (nextState, pointer, theme, renderOptions) => {
|
|
1495
|
+
if (isSome(nextState.error)) return match$2(nextState.error.value.split(NEWLINE_REGEXP), {
|
|
1496
|
+
onEmpty: () => "",
|
|
1497
|
+
onNonEmpty: (errorLines) => {
|
|
1498
|
+
if (renderOptions?.plain === true) return separateSymbol(pointer, errorLines.join("\n"));
|
|
1499
|
+
const prefix = annotateSymbol(theme, pointer, theme.errorColor);
|
|
1500
|
+
const lines = map$2(errorLines, (str) => annotateErrorLine(theme, str));
|
|
1501
|
+
return "\x1B[s\n" + separateSymbol(prefix, lines.join("\n")) + "\x1B[u";
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
return "";
|
|
1505
|
+
};
|
|
1506
|
+
const renderTextOutput = (nextState, leadingSymbol, trailingSymbol, options, theme, renderOptions, submitted = false) => {
|
|
1507
|
+
const value = renderTextInput(nextState, options, theme, submitted, renderOptions);
|
|
1508
|
+
return renderPrompt(value, options.message, leadingSymbol, trailingSymbol, theme, renderOptions);
|
|
1509
|
+
};
|
|
1510
|
+
const renderTextNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1511
|
+
const figures = yield* getTheme(options);
|
|
1512
|
+
const leadingSymbol = annotateSymbol(figures, figures.prefix, figures.primaryColor);
|
|
1513
|
+
const trailingSymbol = annotateSymbol(figures, figures.pointerSmall, figures.mutedColor);
|
|
1514
|
+
const promptMsg = renderTextOutput(state, leadingSymbol, trailingSymbol, options, figures);
|
|
1515
|
+
const errorMsg = renderTextError(state, figures.pointerSmall, figures);
|
|
1516
|
+
const cursorWidth = options.type === "password" ? figures.passwordMask.length : 1;
|
|
1517
|
+
const offset = (state.cursor - state.value.length) * cursorWidth;
|
|
1518
|
+
return promptMsg + errorMsg + cursorMove(offset);
|
|
1519
|
+
});
|
|
1520
|
+
const renderTextSubmission = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1521
|
+
const figures = yield* getTheme(options);
|
|
1522
|
+
const leadingSymbol = annotateSymbol(figures, figures.tick, figures.successColor);
|
|
1523
|
+
const trailingSymbol = annotateSymbol(figures, figures.ellipsis, figures.mutedColor);
|
|
1524
|
+
return renderTextOutput(state, leadingSymbol, trailingSymbol, options, figures, void 0, true) + "\n";
|
|
1525
|
+
});
|
|
1526
|
+
const processTextBackspace = (state) => {
|
|
1527
|
+
if (state.cursor <= 0) return succeed$1(Action.Beep());
|
|
1528
|
+
const beforeCursor = state.value.slice(0, state.cursor - 1);
|
|
1529
|
+
const afterCursor = state.value.slice(state.cursor);
|
|
1530
|
+
const cursor = state.cursor - 1;
|
|
1531
|
+
const value = `${beforeCursor}${afterCursor}`;
|
|
1532
|
+
return succeed$1(Action.NextFrame({ state: {
|
|
1533
|
+
...state,
|
|
1534
|
+
cursor,
|
|
1535
|
+
value,
|
|
1536
|
+
error: none()
|
|
1537
|
+
} }));
|
|
1538
|
+
};
|
|
1539
|
+
const processTextClear = (state) => succeed$1(Action.NextFrame({ state: {
|
|
1540
|
+
...state,
|
|
1541
|
+
cursor: 0,
|
|
1542
|
+
value: "",
|
|
1543
|
+
error: none()
|
|
1544
|
+
} }));
|
|
1545
|
+
const processTextCursorLeft = (state) => {
|
|
1546
|
+
if (state.cursor <= 0) return succeed$1(Action.Beep());
|
|
1547
|
+
const cursor = state.cursor - 1;
|
|
1548
|
+
return succeed$1(Action.NextFrame({ state: {
|
|
1549
|
+
...state,
|
|
1550
|
+
cursor,
|
|
1551
|
+
error: none()
|
|
1552
|
+
} }));
|
|
1553
|
+
};
|
|
1554
|
+
const processTextCursorRight = (state) => {
|
|
1555
|
+
if (state.cursor >= state.value.length) return succeed$1(Action.Beep());
|
|
1556
|
+
const cursor = Math.min(state.cursor + 1, state.value.length);
|
|
1557
|
+
return succeed$1(Action.NextFrame({ state: {
|
|
1558
|
+
...state,
|
|
1559
|
+
cursor,
|
|
1560
|
+
error: none()
|
|
1561
|
+
} }));
|
|
1562
|
+
};
|
|
1563
|
+
const processTextCursorStart = (state) => succeed$1(Action.NextFrame({ state: {
|
|
1564
|
+
...state,
|
|
1565
|
+
cursor: 0,
|
|
1566
|
+
error: none()
|
|
1567
|
+
} }));
|
|
1568
|
+
const processTextCursorEnd = (state) => succeed$1(Action.NextFrame({ state: {
|
|
1569
|
+
...state,
|
|
1570
|
+
cursor: state.value.length,
|
|
1571
|
+
error: none()
|
|
1572
|
+
} }));
|
|
1573
|
+
const processTab = (state, options) => {
|
|
1574
|
+
if (state.value === options.default) return succeed$1(Action.Beep());
|
|
1575
|
+
const value = state.value.length === 0 ? options.default : state.value;
|
|
1576
|
+
return succeed$1(Action.NextFrame({ state: {
|
|
1577
|
+
...state,
|
|
1578
|
+
value,
|
|
1579
|
+
cursor: value.length,
|
|
1580
|
+
error: none()
|
|
1581
|
+
} }));
|
|
1582
|
+
};
|
|
1583
|
+
const defaultTextProcessor = (input, state) => {
|
|
1584
|
+
const value = `${state.value.slice(0, state.cursor)}${input}${state.value.slice(state.cursor)}`;
|
|
1585
|
+
const cursor = state.cursor + input.length;
|
|
1586
|
+
return succeed$1(Action.NextFrame({ state: {
|
|
1587
|
+
...state,
|
|
1588
|
+
cursor,
|
|
1589
|
+
value,
|
|
1590
|
+
error: none()
|
|
1591
|
+
} }));
|
|
1592
|
+
};
|
|
1593
|
+
const handleTextRender = (options) => {
|
|
1594
|
+
return (state, action) => {
|
|
1595
|
+
return Action.$match(action, {
|
|
1596
|
+
Beep: () => succeed$1(renderBeep),
|
|
1597
|
+
NextFrame: ({ state }) => renderTextNextFrame(state, options),
|
|
1598
|
+
Submit: () => renderTextSubmission(state, options)
|
|
1599
|
+
});
|
|
1600
|
+
};
|
|
1601
|
+
};
|
|
1602
|
+
const handleTextProcess = (options) => {
|
|
1603
|
+
return (input, state) => {
|
|
1604
|
+
if (input.key.ctrl) switch (input.key.name) {
|
|
1605
|
+
case "u": return processTextClear(state);
|
|
1606
|
+
case "a": return processTextCursorStart(state);
|
|
1607
|
+
case "e": return processTextCursorEnd(state);
|
|
1608
|
+
default: return succeed$1(Action.Beep());
|
|
1609
|
+
}
|
|
1610
|
+
switch (input.key.name) {
|
|
1611
|
+
case "backspace": return processTextBackspace(state);
|
|
1612
|
+
case "left": return processTextCursorLeft(state);
|
|
1613
|
+
case "right": return processTextCursorRight(state);
|
|
1614
|
+
case "home": return processTextCursorStart(state);
|
|
1615
|
+
case "end": return processTextCursorEnd(state);
|
|
1616
|
+
case "enter":
|
|
1617
|
+
case "return": {
|
|
1618
|
+
const value = state.value;
|
|
1619
|
+
return match$1(options.validate(value), {
|
|
1620
|
+
onFailure: (error) => Action.NextFrame({ state: {
|
|
1621
|
+
...state,
|
|
1622
|
+
value,
|
|
1623
|
+
error: some(error)
|
|
1624
|
+
} }),
|
|
1625
|
+
onSuccess: (value) => Action.Submit({ value })
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
case "tab": return processTab(state, options);
|
|
1629
|
+
default: return defaultTextProcessor(getOrElse(input.input, () => ""), state);
|
|
1630
|
+
}
|
|
1631
|
+
};
|
|
1632
|
+
};
|
|
1633
|
+
const handleTextClear = (options) => {
|
|
1634
|
+
return (state, _) => {
|
|
1635
|
+
return renderClearScreen(state, options);
|
|
1636
|
+
};
|
|
1637
|
+
};
|
|
1638
|
+
const basePrompt = (options, type) => {
|
|
1639
|
+
const opts = {
|
|
1640
|
+
default: "",
|
|
1641
|
+
type,
|
|
1642
|
+
validate: succeed$1,
|
|
1643
|
+
...options
|
|
1644
|
+
};
|
|
1645
|
+
const initialState = {
|
|
1646
|
+
cursor: opts.default.length,
|
|
1647
|
+
value: opts.default,
|
|
1648
|
+
error: none()
|
|
1649
|
+
};
|
|
1650
|
+
return Custom(initialState, {
|
|
1651
|
+
render: handleTextRender(opts),
|
|
1652
|
+
process: handleTextProcess(opts),
|
|
1653
|
+
clear: handleTextClear(opts)
|
|
1654
|
+
});
|
|
1655
|
+
};
|
|
1656
|
+
const handleToggleClear = /*#__PURE__*/ fnUntraced(function* (options) {
|
|
1657
|
+
const columns = yield* (yield* Terminal).columns;
|
|
1658
|
+
const figures = yield* getTheme(options);
|
|
1659
|
+
const clearPrompt = eraseLine + "\x1B[G";
|
|
1660
|
+
const toggleText = options.active + " " + separateSymbol(figures.toggleSeparator, options.inactive);
|
|
1661
|
+
const promptText = renderPrompt(toggleText, options.message, figures.prefix, figures.pointerSmall, figures, { plain: true });
|
|
1662
|
+
return eraseText(promptText, columns) + clearPrompt;
|
|
1663
|
+
});
|
|
1664
|
+
const renderToggle = (value, options, theme, submitted = false) => {
|
|
1665
|
+
const separator = annotateSymbol(theme, theme.toggleSeparator, theme.mutedColor);
|
|
1666
|
+
const selectedAnnotation = combine(underlined, submitted ? theme.submittedColor : theme.primaryColor);
|
|
1667
|
+
const inactive = value ? options.inactive : annotate(theme.colors, options.inactive, selectedAnnotation);
|
|
1668
|
+
return (value ? annotate(theme.colors, options.active, selectedAnnotation) : options.active) + " " + separateSymbol(separator, inactive);
|
|
1669
|
+
};
|
|
1670
|
+
const renderToggleNextFrame = /*#__PURE__*/ fnUntraced(function* (state, options) {
|
|
1671
|
+
const figures = yield* getTheme(options);
|
|
1672
|
+
const leadingSymbol = annotateSymbol(figures, figures.prefix, figures.primaryColor);
|
|
1673
|
+
const trailingSymbol = annotateSymbol(figures, figures.pointerSmall, figures.mutedColor);
|
|
1674
|
+
const toggle = renderToggle(state, options, figures);
|
|
1675
|
+
const promptMsg = renderPrompt(toggle, options.message, leadingSymbol, trailingSymbol, figures);
|
|
1676
|
+
return cursorHide + promptMsg;
|
|
1677
|
+
});
|
|
1678
|
+
const renderToggleSubmission = /*#__PURE__*/ fnUntraced(function* (value, options) {
|
|
1679
|
+
const figures = yield* getTheme(options);
|
|
1680
|
+
const leadingSymbol = annotateSymbol(figures, figures.tick, figures.successColor);
|
|
1681
|
+
const trailingSymbol = annotateSymbol(figures, figures.ellipsis, figures.mutedColor);
|
|
1682
|
+
const toggle = renderToggle(value, options, figures, true);
|
|
1683
|
+
return renderPrompt(toggle, options.message, leadingSymbol, trailingSymbol, figures) + "\n";
|
|
1684
|
+
});
|
|
1685
|
+
const activate = /*#__PURE__*/ succeed$1(/*#__PURE__*/ Action.NextFrame({ state: true }));
|
|
1686
|
+
const deactivate = /*#__PURE__*/ succeed$1(/*#__PURE__*/ Action.NextFrame({ state: false }));
|
|
1687
|
+
const handleToggleRender = (options) => {
|
|
1688
|
+
return (state, action) => {
|
|
1689
|
+
switch (action._tag) {
|
|
1690
|
+
case "Beep": return succeed$1(renderBeep);
|
|
1691
|
+
case "NextFrame": return renderToggleNextFrame(state, options);
|
|
1692
|
+
case "Submit": return renderToggleSubmission(state, options);
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1696
|
+
const handleToggleProcess = (input, state) => {
|
|
1697
|
+
switch (input.key.name) {
|
|
1698
|
+
case "0":
|
|
1699
|
+
case "j":
|
|
1700
|
+
case "delete":
|
|
1701
|
+
case "right":
|
|
1702
|
+
case "down": return deactivate;
|
|
1703
|
+
case "1":
|
|
1704
|
+
case "k":
|
|
1705
|
+
case "left":
|
|
1706
|
+
case "up": return activate;
|
|
1707
|
+
case " ":
|
|
1708
|
+
case "tab": return state ? deactivate : activate;
|
|
1709
|
+
case "enter":
|
|
1710
|
+
case "return": return succeed$1(Action.Submit({ value: state }));
|
|
1711
|
+
default: return succeed$1(Action.Beep());
|
|
1712
|
+
}
|
|
1713
|
+
};
|
|
1714
|
+
const entriesToDisplay = (cursor, total, maxVisible) => {
|
|
1715
|
+
const max = maxVisible === void 0 ? total : maxVisible;
|
|
1716
|
+
let startIndex = Math.min(total - max, cursor - Math.floor(max / 2));
|
|
1717
|
+
if (startIndex < 0) startIndex = 0;
|
|
1718
|
+
const endIndex = Math.min(startIndex + max, total);
|
|
1719
|
+
return {
|
|
1720
|
+
startIndex,
|
|
1721
|
+
endIndex
|
|
1722
|
+
};
|
|
1723
|
+
};
|
|
1724
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/cli/TerminalCapabilities.js
|
|
1725
|
+
/**
|
|
1726
|
+
* Reference to the terminal capabilities of the current process.
|
|
1727
|
+
*
|
|
1728
|
+
* **When to use**
|
|
1729
|
+
*
|
|
1730
|
+
* Use when application output should share the built-in help, version, and
|
|
1731
|
+
* error output's answer. Provide `layer` to detect through
|
|
1732
|
+
* `ConfigProvider` and `Stdio`, or provide a value to override detection.
|
|
1733
|
+
*
|
|
1734
|
+
* **Details**
|
|
1735
|
+
*
|
|
1736
|
+
* The default is detected from the current process the first time it is
|
|
1737
|
+
* read, so later changes to the environment do not affect it. Without a
|
|
1738
|
+
* `process` global, every flag is `false`.
|
|
1739
|
+
*
|
|
1740
|
+
* @stability unstable
|
|
1741
|
+
* @category services
|
|
1742
|
+
* @since 4.0.0
|
|
1743
|
+
*/
|
|
1744
|
+
const TerminalCapabilities = /*#__PURE__*/ Reference("effect/cli/TerminalCapabilities", { defaultValue: () => fromProcess() });
|
|
1745
|
+
const isPresent = (value) => value !== void 0 && value.length > 0;
|
|
1746
|
+
const isForcingColor = (value) => isPresent(value) && value !== "0" && value.toLowerCase() !== "false";
|
|
1747
|
+
const detect = (input) => {
|
|
1748
|
+
if (input.term === "dumb") return {
|
|
1749
|
+
canColor: false,
|
|
1750
|
+
canAnimate: false,
|
|
1751
|
+
canPrompt: false
|
|
1752
|
+
};
|
|
1753
|
+
return {
|
|
1754
|
+
canColor: !isPresent(input.noColor) && (isForcingColor(input.forceColor) || input.stdoutIsTerminal),
|
|
1755
|
+
canAnimate: input.stdoutIsTerminal,
|
|
1756
|
+
canPrompt: input.stdinIsTerminal && input.stdoutIsTerminal
|
|
1757
|
+
};
|
|
1758
|
+
};
|
|
1759
|
+
const fromProcess = () => {
|
|
1760
|
+
const process = globalThis.process;
|
|
1761
|
+
return detect({
|
|
1762
|
+
noColor: process?.env?.NO_COLOR,
|
|
1763
|
+
forceColor: process?.env?.FORCE_COLOR,
|
|
1764
|
+
term: process?.env?.TERM,
|
|
1765
|
+
stdinIsTerminal: process?.stdin?.isTTY === true,
|
|
1766
|
+
stdoutIsTerminal: process?.stdout?.isTTY === true
|
|
1767
|
+
});
|
|
1768
|
+
};
|
|
1769
|
+
export { isQuitError as C, Terminal as S, green as _, Number as a, white as b, String as c, run as d, annotate as f, detectColors as g, cyanBright as h, Int as i, Theme as l, bold as m, Confirm as n, Password as o, blackBright as p, Date as r, Select as s, TerminalCapabilities as t, Toggle as u, magenta as v, make as w, QuitError as x, red as y };
|