visaljs 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/README.md +12 -4
  2. package/THIRD_PARTY_LICENSES +31 -1
  3. package/cli.js +962 -68
  4. package/node/include/js_node.h +11 -1
  5. package/node/prelude/_http_common.js +29 -0
  6. package/node/prelude/async_hooks.js +50 -11
  7. package/node/prelude/child_process.js +31 -4
  8. package/node/prelude/console.js +311 -143
  9. package/node/prelude/crypto.js +6 -4
  10. package/node/prelude/dgram.js +1169 -0
  11. package/node/prelude/diagnostics_channel.js +3 -1
  12. package/node/prelude/dns.js +250 -45
  13. package/node/prelude/dns_promises.js +8 -2
  14. package/node/prelude/fs_promises.js +9 -1
  15. package/node/prelude/http.js +395 -86
  16. package/node/prelude/https.js +13 -4
  17. package/node/prelude/internal/console_class.js +7 -0
  18. package/node/prelude/internal/console_global.js +25 -0
  19. package/node/prelude/internal/crypto/key_encryption.js +217 -0
  20. package/node/prelude/internal/crypto/keys.js +161 -26
  21. package/node/prelude/internal/crypto/random.js +24 -0
  22. package/node/prelude/internal/crypto/util.js +2 -1
  23. package/node/prelude/internal/crypto_x509.js +161 -0
  24. package/node/prelude/internal/dns_classes.js +6 -0
  25. package/node/prelude/internal/dns_resolver.js +371 -0
  26. package/node/prelude/internal/errors.js +9 -0
  27. package/node/prelude/internal/events_on.js +82 -37
  28. package/node/prelude/internal/features.js +8 -4
  29. package/node/prelude/internal/fs_filehandle.js +10 -4
  30. package/node/prelude/internal/perf_histogram.js +1 -1
  31. package/node/prelude/internal/process_more.js +32 -17
  32. package/node/prelude/internal/process_signals.js +8 -2
  33. package/node/prelude/internal/punycode.ts +163 -0
  34. package/node/prelude/internal/readline.js +648 -274
  35. package/node/prelude/internal/readline_editor.js +1240 -0
  36. package/node/prelude/internal/string_width.js +43 -0
  37. package/node/prelude/internal/tls/common.js +145 -33
  38. package/node/prelude/internal/tls/wrap.js +182 -49
  39. package/node/prelude/internal/tls/x509.js +4 -1
  40. package/node/prelude/internal/udp.js +177 -0
  41. package/node/prelude/net.js +13 -1
  42. package/node/prelude/os.js +24 -6
  43. package/node/prelude/perf_hooks.js +37 -2
  44. package/node/prelude/punycode.js +2 -130
  45. package/node/prelude/readline.js +113 -4
  46. package/node/prelude/readline_promises.js +56 -32
  47. package/node/prelude/tls.js +21 -4
  48. package/node/prelude/util.js +3 -16
  49. package/node/src/host_dns.c +623 -0
  50. package/node/src/host_http.c +12 -0
  51. package/node/src/host_net.c +46 -0
  52. package/node/src/host_os.c +1 -6
  53. package/node/src/host_sys.c +70 -0
  54. package/node/src/host_udp.c +418 -0
  55. package/node/third_party/c-ares/LICENSE.md +24 -0
  56. package/node/third_party/c-ares/config/darwin/ares_config.h +573 -0
  57. package/node/third_party/c-ares/config/freebsd/ares_config.h +573 -0
  58. package/node/third_party/c-ares/config/linux/ares_config.h +573 -0
  59. package/node/third_party/c-ares/config/openbsd/ares_config.h +583 -0
  60. package/node/third_party/c-ares/include/ares.h +1237 -0
  61. package/node/third_party/c-ares/include/ares_build.h +202 -0
  62. package/node/third_party/c-ares/include/ares_dns.h +127 -0
  63. package/node/third_party/c-ares/include/ares_dns_record.h +1119 -0
  64. package/node/third_party/c-ares/include/ares_nameser.h +510 -0
  65. package/node/third_party/c-ares/include/ares_version.h +47 -0
  66. package/node/third_party/c-ares/src/lib/ares_addrinfo2hostent.c +305 -0
  67. package/node/third_party/c-ares/src/lib/ares_addrinfo_localhost.c +245 -0
  68. package/node/third_party/c-ares/src/lib/ares_android.c +496 -0
  69. package/node/third_party/c-ares/src/lib/ares_android.h +38 -0
  70. package/node/third_party/c-ares/src/lib/ares_cancel.c +87 -0
  71. package/node/third_party/c-ares/src/lib/ares_close_sockets.c +137 -0
  72. package/node/third_party/c-ares/src/lib/ares_conn.c +511 -0
  73. package/node/third_party/c-ares/src/lib/ares_conn.h +202 -0
  74. package/node/third_party/c-ares/src/lib/ares_cookie.c +461 -0
  75. package/node/third_party/c-ares/src/lib/ares_data.c +168 -0
  76. package/node/third_party/c-ares/src/lib/ares_data.h +92 -0
  77. package/node/third_party/c-ares/src/lib/ares_destroy.c +159 -0
  78. package/node/third_party/c-ares/src/lib/ares_free_hostent.c +54 -0
  79. package/node/third_party/c-ares/src/lib/ares_free_string.c +33 -0
  80. package/node/third_party/c-ares/src/lib/ares_freeaddrinfo.c +67 -0
  81. package/node/third_party/c-ares/src/lib/ares_getaddrinfo.c +806 -0
  82. package/node/third_party/c-ares/src/lib/ares_getenv.c +38 -0
  83. package/node/third_party/c-ares/src/lib/ares_getenv.h +34 -0
  84. package/node/third_party/c-ares/src/lib/ares_gethostbyaddr.c +229 -0
  85. package/node/third_party/c-ares/src/lib/ares_gethostbyname.c +341 -0
  86. package/node/third_party/c-ares/src/lib/ares_getnameinfo.c +437 -0
  87. package/node/third_party/c-ares/src/lib/ares_hosts_file.c +960 -0
  88. package/node/third_party/c-ares/src/lib/ares_inet_net_pton.h +31 -0
  89. package/node/third_party/c-ares/src/lib/ares_init.c +631 -0
  90. package/node/third_party/c-ares/src/lib/ares_ipv6.h +115 -0
  91. package/node/third_party/c-ares/src/lib/ares_library_init.c +190 -0
  92. package/node/third_party/c-ares/src/lib/ares_metrics.c +261 -0
  93. package/node/third_party/c-ares/src/lib/ares_options.c +492 -0
  94. package/node/third_party/c-ares/src/lib/ares_parse_into_addrinfo.c +179 -0
  95. package/node/third_party/c-ares/src/lib/ares_private.h +648 -0
  96. package/node/third_party/c-ares/src/lib/ares_process.c +1649 -0
  97. package/node/third_party/c-ares/src/lib/ares_qcache.c +442 -0
  98. package/node/third_party/c-ares/src/lib/ares_query.c +151 -0
  99. package/node/third_party/c-ares/src/lib/ares_search.c +623 -0
  100. package/node/third_party/c-ares/src/lib/ares_send.c +300 -0
  101. package/node/third_party/c-ares/src/lib/ares_set_socket_functions.c +590 -0
  102. package/node/third_party/c-ares/src/lib/ares_setup.h +224 -0
  103. package/node/third_party/c-ares/src/lib/ares_socket.c +427 -0
  104. package/node/third_party/c-ares/src/lib/ares_socket.h +163 -0
  105. package/node/third_party/c-ares/src/lib/ares_sortaddrinfo.c +447 -0
  106. package/node/third_party/c-ares/src/lib/ares_strerror.c +91 -0
  107. package/node/third_party/c-ares/src/lib/ares_sysconfig.c +642 -0
  108. package/node/third_party/c-ares/src/lib/ares_sysconfig_files.c +851 -0
  109. package/node/third_party/c-ares/src/lib/ares_sysconfig_mac.c +373 -0
  110. package/node/third_party/c-ares/src/lib/ares_sysconfig_win.c +673 -0
  111. package/node/third_party/c-ares/src/lib/ares_timeout.c +162 -0
  112. package/node/third_party/c-ares/src/lib/ares_update_servers.c +1376 -0
  113. package/node/third_party/c-ares/src/lib/ares_version.c +36 -0
  114. package/node/third_party/c-ares/src/lib/config-dos.h +114 -0
  115. package/node/third_party/c-ares/src/lib/config-win32.h +396 -0
  116. package/node/third_party/c-ares/src/lib/dsa/ares_array.c +409 -0
  117. package/node/third_party/c-ares/src/lib/dsa/ares_htable.c +451 -0
  118. package/node/third_party/c-ares/src/lib/dsa/ares_htable.h +174 -0
  119. package/node/third_party/c-ares/src/lib/dsa/ares_htable_asvp.c +224 -0
  120. package/node/third_party/c-ares/src/lib/dsa/ares_htable_dict.c +230 -0
  121. package/node/third_party/c-ares/src/lib/dsa/ares_htable_strvp.c +210 -0
  122. package/node/third_party/c-ares/src/lib/dsa/ares_htable_szvp.c +188 -0
  123. package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpstr.c +186 -0
  124. package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpvp.c +194 -0
  125. package/node/third_party/c-ares/src/lib/dsa/ares_llist.c +385 -0
  126. package/node/third_party/c-ares/src/lib/dsa/ares_slist.c +479 -0
  127. package/node/third_party/c-ares/src/lib/dsa/ares_slist.h +207 -0
  128. package/node/third_party/c-ares/src/lib/event/ares_event.h +191 -0
  129. package/node/third_party/c-ares/src/lib/event/ares_event_configchg.c +746 -0
  130. package/node/third_party/c-ares/src/lib/event/ares_event_epoll.c +192 -0
  131. package/node/third_party/c-ares/src/lib/event/ares_event_kqueue.c +248 -0
  132. package/node/third_party/c-ares/src/lib/event/ares_event_poll.c +140 -0
  133. package/node/third_party/c-ares/src/lib/event/ares_event_select.c +159 -0
  134. package/node/third_party/c-ares/src/lib/event/ares_event_thread.c +575 -0
  135. package/node/third_party/c-ares/src/lib/event/ares_event_wake_pipe.c +172 -0
  136. package/node/third_party/c-ares/src/lib/event/ares_event_win32.c +981 -0
  137. package/node/third_party/c-ares/src/lib/event/ares_event_win32.h +161 -0
  138. package/node/third_party/c-ares/src/lib/include/ares_array.h +276 -0
  139. package/node/third_party/c-ares/src/lib/include/ares_buf.h +732 -0
  140. package/node/third_party/c-ares/src/lib/include/ares_htable_asvp.h +130 -0
  141. package/node/third_party/c-ares/src/lib/include/ares_htable_dict.h +123 -0
  142. package/node/third_party/c-ares/src/lib/include/ares_htable_strvp.h +130 -0
  143. package/node/third_party/c-ares/src/lib/include/ares_htable_szvp.h +118 -0
  144. package/node/third_party/c-ares/src/lib/include/ares_htable_vpstr.h +111 -0
  145. package/node/third_party/c-ares/src/lib/include/ares_htable_vpvp.h +128 -0
  146. package/node/third_party/c-ares/src/lib/include/ares_llist.h +239 -0
  147. package/node/third_party/c-ares/src/lib/include/ares_mem.h +41 -0
  148. package/node/third_party/c-ares/src/lib/include/ares_str.h +261 -0
  149. package/node/third_party/c-ares/src/lib/inet_net_pton.c +451 -0
  150. package/node/third_party/c-ares/src/lib/inet_ntop.c +219 -0
  151. package/node/third_party/c-ares/src/lib/legacy/ares_create_query.c +78 -0
  152. package/node/third_party/c-ares/src/lib/legacy/ares_expand_name.c +99 -0
  153. package/node/third_party/c-ares/src/lib/legacy/ares_expand_string.c +107 -0
  154. package/node/third_party/c-ares/src/lib/legacy/ares_fds.c +80 -0
  155. package/node/third_party/c-ares/src/lib/legacy/ares_getsock.c +85 -0
  156. package/node/third_party/c-ares/src/lib/legacy/ares_parse_a_reply.c +107 -0
  157. package/node/third_party/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c +109 -0
  158. package/node/third_party/c-ares/src/lib/legacy/ares_parse_caa_reply.c +137 -0
  159. package/node/third_party/c-ares/src/lib/legacy/ares_parse_mx_reply.c +110 -0
  160. package/node/third_party/c-ares/src/lib/legacy/ares_parse_naptr_reply.c +132 -0
  161. package/node/third_party/c-ares/src/lib/legacy/ares_parse_ns_reply.c +154 -0
  162. package/node/third_party/c-ares/src/lib/legacy/ares_parse_ptr_reply.c +213 -0
  163. package/node/third_party/c-ares/src/lib/legacy/ares_parse_soa_reply.c +115 -0
  164. package/node/third_party/c-ares/src/lib/legacy/ares_parse_srv_reply.c +114 -0
  165. package/node/third_party/c-ares/src/lib/legacy/ares_parse_txt_reply.c +144 -0
  166. package/node/third_party/c-ares/src/lib/legacy/ares_parse_uri_reply.c +113 -0
  167. package/node/third_party/c-ares/src/lib/record/ares_dns_mapping.c +982 -0
  168. package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.c +309 -0
  169. package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.h +72 -0
  170. package/node/third_party/c-ares/src/lib/record/ares_dns_name.c +736 -0
  171. package/node/third_party/c-ares/src/lib/record/ares_dns_parse.c +1360 -0
  172. package/node/third_party/c-ares/src/lib/record/ares_dns_private.h +273 -0
  173. package/node/third_party/c-ares/src/lib/record/ares_dns_record.c +1701 -0
  174. package/node/third_party/c-ares/src/lib/record/ares_dns_write.c +1229 -0
  175. package/node/third_party/c-ares/src/lib/str/ares_buf.c +1510 -0
  176. package/node/third_party/c-ares/src/lib/str/ares_str.c +562 -0
  177. package/node/third_party/c-ares/src/lib/str/ares_strsplit.c +90 -0
  178. package/node/third_party/c-ares/src/lib/str/ares_strsplit.h +51 -0
  179. package/node/third_party/c-ares/src/lib/thirdparty/apple/dnsinfo.h +122 -0
  180. package/node/third_party/c-ares/src/lib/util/ares_iface_ips.c +640 -0
  181. package/node/third_party/c-ares/src/lib/util/ares_iface_ips.h +140 -0
  182. package/node/third_party/c-ares/src/lib/util/ares_math.c +167 -0
  183. package/node/third_party/c-ares/src/lib/util/ares_math.h +58 -0
  184. package/node/third_party/c-ares/src/lib/util/ares_rand.c +389 -0
  185. package/node/third_party/c-ares/src/lib/util/ares_rand.h +36 -0
  186. package/node/third_party/c-ares/src/lib/util/ares_threads.c +613 -0
  187. package/node/third_party/c-ares/src/lib/util/ares_threads.h +60 -0
  188. package/node/third_party/c-ares/src/lib/util/ares_time.h +49 -0
  189. package/node/third_party/c-ares/src/lib/util/ares_timeval.c +95 -0
  190. package/node/third_party/c-ares/src/lib/util/ares_uri.c +1627 -0
  191. package/node/third_party/c-ares/src/lib/util/ares_uri.h +252 -0
  192. package/node/third_party/c-ares/src/lib/windows_port.c +29 -0
  193. package/package.json +1 -1
  194. package/prebuilt/darwin-arm64/cares-a6286c65ca9374a3.a +0 -0
  195. package/prebuilt/darwin-x64/cares-a6286c65ca9374a3.a +0 -0
  196. package/prebuilt/linux-arm64/cares-4ba05ac8e948af8e.a +0 -0
  197. package/prebuilt/linux-arm64-musl/cares-4ba05ac8e948af8e.a +0 -0
  198. package/prebuilt/linux-x64/cares-4ba05ac8e948af8e.a +0 -0
  199. package/prebuilt/linux-x64-musl/cares-4ba05ac8e948af8e.a +0 -0
  200. package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
  201. package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
  202. package/prebuilt/win32-x64/cares-49c9ec95162b912d.a +0 -0
  203. package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
  204. package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
  205. package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
  206. package/runtime/include/js_builtins.h +5 -0
  207. package/runtime/include/js_crypto.h +11 -0
  208. package/runtime/include/js_gc.h +13 -10
  209. package/runtime/include/js_jobs.h +2 -0
  210. package/runtime/include/js_object.h +58 -0
  211. package/runtime/include/jscontext.h +1 -0
  212. package/runtime/src/crypto_internal.h +1 -0
  213. package/runtime/src/crypto_subtle.c +66 -7
  214. package/runtime/src/crypto_tls.c +265 -19
  215. package/runtime/src/gc.c +73 -92
  216. package/runtime/src/inspect.c +18 -1
  217. package/runtime/src/jobs.c +37 -22
  218. package/runtime/src/object.c +49 -2
  219. package/runtime/src/os.c +16 -6
  220. package/runtime/src/os.h +2 -0
  221. package/runtime/src/process.c +97 -10
@@ -1,338 +1,712 @@
1
- // node:readline's Interface, which node:readline/promises extends: an input stream read a line at
2
- // a time, as Node's Interface reads one that isn't a terminal: 'line' for each line (ended by \n,
3
- // \r\n or \r), a question's answer to its callback, the prompt written to the output, and the lines
4
- // as an async iterator. A terminal is read in its normal mode, the terminal editing the line and
5
- // echoing it; Node's own editor in raw mode (keys, history, completion) isn't provided, nor is
6
- // emitKeypressEvents. The cursor functions write ANSI escapes.
1
+ // node:readline's Interface (Node's lib/internal/readline/interface.js, utils.js, callbacks.js and
2
+ // the in-memory part of internal/repl/history.js), which node:readline and readline/promises extend.
3
+ // The terminal line editor (raw mode keys, editing, completion, the kill ring, undo, history
4
+ // navigation, emitKeypressEvents) is a feature module, internal/readline_editor.js, linked into
5
+ // programs that may read a terminal; without it an interface on a terminal reads lines as on a pipe.
6
+ // Ported from Node.js (Copyright Node.js contributors, MIT): node/third_party/nodejs/LICENSE.
7
7
  import { EventEmitter } from "../events.js";
8
- import { codeError, invalidArgType, invalidArgValue, notSupported, validateFunction, validateString } from "./errors.js";
9
- import { Readable } from "../stream.js";
10
8
  import { StringDecoder } from "../string_decoder.js";
9
+ import { getStringWidth, stripVTControlCharacters } from "./string_width.js";
10
+ import { codeError, invalidArgType, invalidArgValue, outOfRange, validateFunction, validateString } from "./errors.js";
11
+ import { feature, features } from "./features.js";
11
12
 
12
- /* what ends a line; a \r at a chunk's end may be a \r\n split across chunks: a \n first in the
13
- * next chunk, within crlfDelay, belongs to it */
14
- const lineEnding = /\r?\n|\r(?!\n)/g;
15
- const kMinCrlfDelay = 100;
16
- const kPromisifyCustom = Symbol.for("nodejs.util.promisify.custom");
13
+ /* ---- utils (Node's internal/readline/utils.js) ---------------------------------------------- */
17
14
 
18
- export const kQuestion = Symbol("question");
19
- export const kQuestionCancel = Symbol("questionCancel");
15
+ const kUTF16SurrogateThreshold = 0x10000;
16
+ const kEscape = "\x1b";
17
+ export const kSubstringSearch = Symbol("kSubstringSearch");
20
18
 
21
- function validateSignal(signal, name) {
22
- if (signal !== undefined && (signal === null || typeof signal !== "object" || !("aborted" in signal))) {
23
- throw invalidArgType(name, "an instance of AbortSignal", signal);
19
+ export function CSI(strings, ...args) {
20
+ let ret = `${kEscape}[`;
21
+ for (let n = 0; n < strings.length; n++) {
22
+ ret += strings[n];
23
+ if (n < args.length) ret += args[n];
24
+ }
25
+ return ret;
26
+ }
27
+ CSI.kEscape = kEscape;
28
+ CSI.kClearToLineBeginning = CSI`1K`;
29
+ CSI.kClearToLineEnd = CSI`0K`;
30
+ CSI.kClearLine = CSI`2K`;
31
+ CSI.kClearScreenDown = CSI`0J`;
32
+
33
+ export function charLengthLeft(str, i) {
34
+ if (i <= 0) return 0;
35
+ if ((i > 1 && str.codePointAt(i - 2) >= kUTF16SurrogateThreshold) || str.codePointAt(i - 1) >= kUTF16SurrogateThreshold) return 2;
36
+ return 1;
37
+ }
38
+
39
+ export function charLengthAt(str, i) {
40
+ if (str.length <= i) {
41
+ /* pretend there's a character at the end, so the cursor can move past the line */
42
+ return 1;
24
43
  }
44
+ return str.codePointAt(i) >= kUTF16SurrogateThreshold ? 2 : 1;
25
45
  }
26
46
 
27
- /** Node's AbortError: name and code, the signal's reason as its cause. */
28
- export function abortError(signal) {
29
- const error = new Error("The operation was aborted", { cause: signal?.reason });
47
+ /* the line's parts in reverse: history keeps a multiline entry's lines last to first */
48
+ function reverseString(line, from = "\r", to = "\r") {
49
+ const parts = line.split(from);
50
+ let result = "";
51
+ for (let i = parts.length - 1; i > 0; i--) result += parts[i] + to;
52
+ result += parts[0];
53
+ return result;
54
+ }
55
+
56
+ /* ---- errors and validation ------------------------------------------------------------------- */
57
+
58
+ const useAfterClose = () => codeError(Error, "ERR_USE_AFTER_CLOSE", "readline was closed");
59
+
60
+ /* Node's AbortError: name and code, the signal's reason as its cause */
61
+ export function abortError(message = "The operation was aborted", options = undefined) {
62
+ const error = new Error(message, options);
30
63
  error.code = "ABORT_ERR";
31
64
  error.name = "AbortError";
32
65
  return error;
33
66
  }
34
67
 
35
- /** Interface(input, output, completer, terminal), or Interface({ input, output, … }). A function,
36
- * as Node's is: callable without new. */
37
- export function Interface(input, output, completer, terminal) {
38
- if (!(this instanceof Interface)) return new Interface(input, output, completer, terminal);
68
+ export function validateAbortSignal(signal, name) {
69
+ if (signal !== undefined && (signal === null || typeof signal !== "object" || !("aborted" in signal))) {
70
+ throw invalidArgType(name, "an instance of AbortSignal", signal);
71
+ }
72
+ }
73
+
74
+ /* Node's addAbortListener: the listener once, and a disposable that removes it */
75
+ export function addAbortListener(signal, listener) {
76
+ if (signal.aborted) {
77
+ queueMicrotask(() => listener());
78
+ return { [Symbol.dispose]() {} };
79
+ }
80
+ signal.addEventListener("abort", listener, { once: true });
81
+ return { [Symbol.dispose]: () => signal.removeEventListener("abort", listener) };
82
+ }
83
+
84
+ function validateUint32(value, name, positive) {
85
+ if (typeof value !== "number") throw invalidArgType(name, "of type number", value);
86
+ if (!Number.isInteger(value)) throw outOfRange(name, "an integer", value);
87
+ const min = positive ? 1 : 0;
88
+ if (value < min || value > 4294967295) throw outOfRange(name, `>= ${min} && <= 4294967295`, value);
89
+ }
90
+
91
+ /* ---- the cursor functions (Node's internal/readline/callbacks.js) ---------------------------- */
92
+
93
+ const done = (callback) => {
94
+ if (typeof callback === "function") process.nextTick(callback, null);
95
+ return true;
96
+ };
97
+
98
+ export function cursorTo(stream, x, y, callback) {
99
+ if (callback !== undefined) validateFunction(callback, "callback");
100
+ if (typeof y === "function") {
101
+ callback = y;
102
+ y = undefined;
103
+ }
104
+ if (Number.isNaN(x)) throw invalidArgValue("x", "is invalid", x);
105
+ if (Number.isNaN(y)) throw invalidArgValue("y", "is invalid", y);
106
+ if (stream == null || (typeof x !== "number" && typeof y !== "number")) return done(callback);
107
+ if (typeof x !== "number") throw codeError(TypeError, "ERR_INVALID_CURSOR_POS", "Cannot set cursor row without setting its column");
108
+ const data = typeof y !== "number" ? CSI`${x + 1}G` : CSI`${y + 1};${x + 1}H`;
109
+ return stream.write(data, callback);
110
+ }
111
+
112
+ export function moveCursor(stream, dx, dy, callback) {
113
+ if (callback !== undefined) validateFunction(callback, "callback");
114
+ if (stream == null || !(dx || dy)) return done(callback);
115
+ let data = "";
116
+ if (dx < 0) data += CSI`${-dx}D`;
117
+ else if (dx > 0) data += CSI`${dx}C`;
118
+ if (dy < 0) data += CSI`${-dy}A`;
119
+ else if (dy > 0) data += CSI`${dy}B`;
120
+ return stream.write(data, callback);
121
+ }
122
+
123
+ export function clearLine(stream, dir, callback) {
124
+ if (callback !== undefined) validateFunction(callback, "callback");
125
+ if (stream === null || stream === undefined) return done(callback);
126
+ const type = dir < 0 ? CSI.kClearToLineBeginning : dir > 0 ? CSI.kClearToLineEnd : CSI.kClearLine;
127
+ return stream.write(type, callback);
128
+ }
129
+
130
+ export function clearScreenDown(stream, callback) {
131
+ if (callback !== undefined) validateFunction(callback, "callback");
132
+ if (stream === null || stream === undefined) return done(callback);
133
+ return stream.write(CSI.kClearScreenDown, callback);
134
+ }
135
+
136
+ /* ---- history (Node's ReplHistory, without the REPL's file) ----------------------------------- */
137
+
138
+ const kHistorySize = 30;
139
+
140
+ class ReplHistory {
141
+ #context;
142
+ #removeHistoryDuplicates;
143
+ #size;
144
+ #history;
145
+ #index = -1;
146
+
147
+ constructor(context, options) {
148
+ if (options.history !== undefined && !Array.isArray(options.history)) throw invalidArgType("history", "an instance of Array", options.history);
149
+ if (options.size !== undefined) {
150
+ if (typeof options.size !== "number") throw invalidArgType("size", "of type number", options.size);
151
+ if (options.size < 0 || Number.isNaN(options.size)) throw outOfRange("size", ">= 0", options.size);
152
+ }
153
+ this.#context = context;
154
+ this.#removeHistoryDuplicates = options.removeHistoryDuplicates || false;
155
+ this.#size = options.size ?? context.historySize ?? kHistorySize;
156
+ this.#history = options.history ?? [];
157
+ }
158
+
159
+ addHistory(isMultiline, lastCommandErrored) {
160
+ const line = this.#context.line;
161
+ if (line.length === 0) return "";
162
+ if (this.#size === 0) return line;
163
+ if (line.trim().length === 0) return line;
164
+ /* a multiline entry replaces the line it continues; a failed command isn't kept */
165
+ if ((isMultiline && this.#index === -1) || lastCommandErrored) this.#history.shift();
166
+ const normalizedLine = reverseString(line, "\n", "\r");
167
+ if (this.#history.length === 0 || this.#history[0] !== normalizedLine) {
168
+ if (this.#removeHistoryDuplicates) {
169
+ const dupIndex = this.#history.indexOf(normalizedLine);
170
+ if (dupIndex !== -1) this.#history.splice(dupIndex, 1);
171
+ }
172
+ this.#history.unshift(normalizedLine);
173
+ if (this.#history.length > this.#size) this.#history.pop();
174
+ }
175
+ this.#index = -1;
176
+ const finalLine = isMultiline ? reverseString(this.#history[0]) : this.#history[0];
177
+ this.#context.emit("history", this.#history);
178
+ return finalLine;
179
+ }
180
+
181
+ canNavigateToNext() {
182
+ return this.#index > -1 && this.#history.length > 0;
183
+ }
184
+
185
+ navigateToNext(substringSearch) {
186
+ if (!this.canNavigateToNext()) return null;
187
+ const search = substringSearch || "";
188
+ let index = this.#index - 1;
189
+ while (index >= 0 && (!this.#history[index].startsWith(search) || this.#context.line === this.#history[index])) index--;
190
+ this.#index = index;
191
+ if (index === -1) return search;
192
+ return reverseString(this.#history[index], "\r", "\n");
193
+ }
194
+
195
+ canNavigateToPrevious() {
196
+ return this.#history.length !== this.#index && this.#history.length > 0;
197
+ }
198
+
199
+ navigateToPrevious(substringSearch = "") {
200
+ if (!this.canNavigateToPrevious()) return null;
201
+ const search = substringSearch || "";
202
+ let index = this.#index + 1;
203
+ while (index < this.#history.length && (!this.#history[index].startsWith(search) || this.#context.line === this.#history[index])) index++;
204
+ this.#index = index;
205
+ if (index === this.#history.length) return search;
206
+ return reverseString(this.#history[index], "\r", "\n");
207
+ }
208
+
209
+ get size() { return this.#size; }
210
+ get isFlushing() { return false; }
211
+ get history() { return this.#history; }
212
+ set history(value) { this.#history = value; }
213
+ get index() { return this.#index; }
214
+ set index(value) { this.#index = value; }
215
+ }
216
+
217
+ /* ---- Interface ------------------------------------------------------------------------------- */
218
+
219
+ const kMincrlfDelay = 100;
220
+ /* \r\n, \n, \r (not one that a \n may follow in the next chunk), and the Unicode line separators */
221
+ const lineEnding = /\r?\n|\r(?!\n)|\u2028|\u2029/g;
222
+ const ESCAPE_CODE_TIMEOUT = 500;
223
+ /* events.on's option (internal/events_on.js) */
224
+ const kFirstEventParam = Symbol.for("visaljs.events.kFirstEventParam");
225
+
226
+ export const kLineObjectStream = Symbol("line object stream");
227
+ export const kQuestionCancel = Symbol("kQuestionCancel");
228
+ export const kQuestion = Symbol("kQuestion");
229
+ export const kMultilinePrompt = Symbol("| ");
230
+
231
+ export const kAddHistory = Symbol("_addHistory");
232
+ export const kBeforeEdit = Symbol("_beforeEdit");
233
+ export const kDecoder = Symbol("_decoder");
234
+ export const kDeleteLeft = Symbol("_deleteLeft");
235
+ export const kDeleteLineLeft = Symbol("_deleteLineLeft");
236
+ export const kDeleteLineRight = Symbol("_deleteLineRight");
237
+ export const kDeleteRight = Symbol("_deleteRight");
238
+ export const kDeleteWordLeft = Symbol("_deleteWordLeft");
239
+ export const kDeleteWordRight = Symbol("_deleteWordRight");
240
+ export const kGetDisplayPos = Symbol("_getDisplayPos");
241
+ export const kHistoryNext = Symbol("_historyNext");
242
+ export const kMoveDownOrHistoryNext = Symbol("_moveDownOrHistoryNext");
243
+ export const kHistoryPrev = Symbol("_historyPrev");
244
+ export const kMoveUpOrHistoryPrev = Symbol("_moveUpOrHistoryPrev");
245
+ export const kInsertString = Symbol("_insertString");
246
+ export const kLine = Symbol("_line");
247
+ export const kLine_buffer = Symbol("_line_buffer");
248
+ export const kKillRing = Symbol("_killRing");
249
+ export const kKillRingCursor = Symbol("_killRingCursor");
250
+ export const kMoveCursor = Symbol("_moveCursor");
251
+ export const kNormalWrite = Symbol("_normalWrite");
252
+ export const kOldPrompt = Symbol("_oldPrompt");
253
+ export const kOnLine = Symbol("_onLine");
254
+ export const kSetLine = Symbol("_setLine");
255
+ export const kPreviousKey = Symbol("_previousKey");
256
+ export const kPrompt = Symbol("_prompt");
257
+ export const kPushToKillRing = Symbol("_pushToKillRing");
258
+ export const kPushToUndoStack = Symbol("_pushToUndoStack");
259
+ export const kQuestionCallback = Symbol("_questionCallback");
260
+ export const kLastCommandErrored = Symbol("_lastCommandErrored");
261
+ export const kQuestionReject = Symbol("_questionReject");
262
+ export const kRedo = Symbol("_redo");
263
+ export const kRedoStack = Symbol("_redoStack");
264
+ export const kRefreshLine = Symbol("_refreshLine");
265
+ export const kSawKeyPress = Symbol("_sawKeyPress");
266
+ export const kSawReturnAt = Symbol("_sawReturnAt");
267
+ export const kSetRawMode = Symbol("_setRawMode");
268
+ export const kTabComplete = Symbol("_tabComplete");
269
+ export const kTabCompleter = Symbol("_tabCompleter");
270
+ export const kTtyWrite = Symbol("_ttyWrite");
271
+ export const kUndo = Symbol("_undo");
272
+ export const kUndoStack = Symbol("_undoStack");
273
+ export const kIsMultiline = Symbol("_isMultiline");
274
+ export const kWordLeft = Symbol("_wordLeft");
275
+ export const kWordRight = Symbol("_wordRight");
276
+ export const kWriteToOutput = Symbol("_writeToOutput");
277
+ export const kYank = Symbol("_yank");
278
+ export const kYanking = Symbol("_yanking");
279
+ export const kYankPop = Symbol("_yankPop");
280
+ export const kSavePreviousState = Symbol("_savePreviousState");
281
+ export const kRestorePreviousState = Symbol("_restorePreviousState");
282
+ export const kPreviousLine = Symbol("_previousLine");
283
+ export const kPreviousCursor = Symbol("_previousCursor");
284
+ export const kPreviousCursorCols = Symbol("_previousCursorCols");
285
+ export const kMultilineMove = Symbol("_multilineMove");
286
+ export const kPreviousPrevRows = Symbol("_previousPrevRows");
287
+ export const kAddNewLineOnTTY = Symbol("_addNewLineOnTTY");
288
+
289
+ export function InterfaceConstructor(input, output, completer, terminal) {
290
+ this[kSawReturnAt] = 0;
291
+ this.isCompletionEnabled = true;
292
+ this[kSawKeyPress] = false;
293
+ this[kPreviousKey] = null;
294
+ this.escapeCodeTimeout = ESCAPE_CODE_TIMEOUT;
295
+ this.tabSize = 8;
296
+
39
297
  EventEmitter.call(this);
40
- let prompt = "> ";
298
+
41
299
  let crlfDelay;
300
+ let prompt = "> ";
42
301
  let signal;
302
+ let historyOptions;
303
+
43
304
  if (input?.input) {
44
- ({ output, completer, terminal, signal, crlfDelay } = input);
305
+ /* an options object */
306
+ output = input.output;
307
+ completer = input.completer;
308
+ terminal = input.terminal;
309
+ signal = input.signal;
310
+ const historySize = input.historySize;
311
+ const history = input.history;
312
+ const removeHistoryDuplicates = input.removeHistoryDuplicates;
313
+ if (input.tabSize !== undefined) {
314
+ validateUint32(input.tabSize, "tabSize", true);
315
+ this.tabSize = input.tabSize;
316
+ }
45
317
  if (input.prompt !== undefined) prompt = input.prompt;
318
+ if (input.escapeCodeTimeout !== undefined) {
319
+ if (Number.isFinite(input.escapeCodeTimeout)) this.escapeCodeTimeout = input.escapeCodeTimeout;
320
+ else throw invalidArgValue("input.escapeCodeTimeout", "is invalid", this.escapeCodeTimeout);
321
+ }
322
+ if (signal) validateAbortSignal(signal, "options.signal");
323
+ crlfDelay = input.crlfDelay;
46
324
  input = input.input;
325
+ historyOptions = { __proto__: null, size: historySize, history, removeHistoryDuplicates };
47
326
  }
48
- if (completer !== undefined && typeof completer !== "function") throw invalidArgValue("completer", "must be a function", completer);
49
- validateSignal(signal, "options.signal");
50
- this.input = input;
327
+
328
+ this.setupHistoryManager(historyOptions ?? input);
329
+
330
+ if (completer !== undefined && typeof completer !== "function") throw invalidArgValue("completer", "is invalid", completer);
331
+
332
+ /* the output's isTTY, when terminal isn't given (Node's backwards compatibility) */
333
+ if (terminal === undefined && !(output === null || output === undefined)) terminal = !!output.isTTY;
334
+
335
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
336
+ const self = this;
337
+
338
+ this.line = "";
339
+ this[kIsMultiline] = false;
340
+ this[kSubstringSearch] = null;
51
341
  this.output = output;
342
+ this.input = input;
343
+ this[kUndoStack] = [];
344
+ this[kRedoStack] = [];
345
+ this[kPreviousCursorCols] = -1;
346
+ /* the kill ring: what was deleted, the latest first, yanked back (Emacs's) */
347
+ this[kKillRing] = [];
348
+ this[kKillRingCursor] = 0;
349
+
350
+ this.crlfDelay = crlfDelay ? Math.max(kMincrlfDelay, crlfDelay) : kMincrlfDelay;
52
351
  this.completer = completer;
53
- this.terminal = terminal === undefined ? Boolean(output?.isTTY) : Boolean(terminal);
54
- this.crlfDelay = crlfDelay ? Math.max(kMinCrlfDelay, crlfDelay) : kMinCrlfDelay;
55
- this.line = "";
56
- this.cursor = 0;
57
- this.history = [];
58
- this.closed = false;
59
- this.paused = false;
60
- this._prompt = prompt;
61
- this._oldPrompt = prompt;
62
- this._questionCallback = null;
63
- this._lineBuffer = null;
64
- this._sawReturnAt = 0;
65
- this._decoder = new StringDecoder("utf8");
66
- this._lines = undefined;
67
-
68
- const ondata = (data) => this._normalWrite(data);
69
- const onend = () => {
70
- if (typeof this._lineBuffer === "string" && this._lineBuffer.length > 0) this.emit("line", this._lineBuffer);
71
- this.close();
72
- };
73
- const onerror = (err) => this.emit("error", err);
352
+
353
+ this.setPrompt(prompt);
354
+
355
+ /* a terminal needs the line editor: a program that doesn't link it reads lines as from a pipe */
356
+ this.terminal = !!terminal && features.readlineEditor !== undefined;
357
+
358
+ function onerror(err) {
359
+ self.emit("error", err);
360
+ }
361
+
362
+ function ondata(data) {
363
+ self[kNormalWrite](data);
364
+ }
365
+
366
+ function onend() {
367
+ if (typeof self[kLine_buffer] === "string" && self[kLine_buffer].length > 0) self.emit("line", self[kLine_buffer]);
368
+ self.close();
369
+ }
370
+
371
+ function ontermend() {
372
+ if (typeof self.line === "string" && self.line.length > 0) self.emit("line", self.line);
373
+ self.close();
374
+ }
375
+
376
+ function onkeypress(s, key) {
377
+ self[kTtyWrite](s, key);
378
+ if (key?.sequence) {
379
+ /* half a surrogate pair: refreshed, so the character shows once it's whole */
380
+ const ch = key.sequence.codePointAt(0);
381
+ if (ch >= 0xd800 && ch <= 0xdfff) self[kRefreshLine]();
382
+ }
383
+ }
384
+
385
+ function onresize() {
386
+ self[kRefreshLine]();
387
+ }
388
+
389
+ this[kLineObjectStream] = undefined;
390
+
74
391
  input.on("error", onerror);
75
- input.on("data", ondata);
76
- input.on("end", onend);
77
- this.once("close", () => {
78
- input.removeListener("error", onerror);
79
- input.removeListener("data", ondata);
80
- input.removeListener("end", onend);
81
- });
392
+
393
+ if (!this.terminal) {
394
+ function onSelfCloseWithoutTerminal() {
395
+ input.removeListener("data", ondata);
396
+ input.removeListener("error", onerror);
397
+ input.removeListener("end", onend);
398
+ }
399
+ input.on("data", ondata);
400
+ input.on("end", onend);
401
+ self.once("close", onSelfCloseWithoutTerminal);
402
+ this[kDecoder] = new StringDecoder("utf8");
403
+ } else {
404
+ function onSelfCloseWithTerminal() {
405
+ input.removeListener("keypress", onkeypress);
406
+ input.removeListener("error", onerror);
407
+ input.removeListener("end", ontermend);
408
+ if (output !== null && output !== undefined) output.removeListener("resize", onresize);
409
+ }
410
+ features.emitKeypressEvents(input, this);
411
+ input.on("keypress", onkeypress);
412
+ input.on("end", ontermend);
413
+ this[kSetRawMode](true);
414
+ this.terminal = true;
415
+ this.cursor = 0;
416
+ if (output !== null && output !== undefined) output.on("resize", onresize);
417
+ self.once("close", onSelfCloseWithTerminal);
418
+ }
419
+
82
420
  if (signal) {
83
- const onAbort = () => this.close();
84
- if (signal.aborted) process.nextTick(onAbort);
85
- else {
86
- signal.addEventListener("abort", onAbort, { once: true });
87
- this.once("close", () => signal.removeEventListener("abort", onAbort));
421
+ const onAborted = () => self.close();
422
+ if (signal.aborted) {
423
+ process.nextTick(onAborted);
424
+ } else {
425
+ const disposable = addAbortListener(signal, onAborted);
426
+ self.once("close", disposable[Symbol.dispose]);
88
427
  }
89
428
  }
429
+
430
+ this[kSetLine]("");
431
+
90
432
  input.resume();
91
433
  }
92
- Object.setPrototypeOf(Interface.prototype, EventEmitter.prototype);
93
- Object.setPrototypeOf(Interface, EventEmitter);
94
434
 
95
- Interface.prototype.setPrompt = function setPrompt(prompt) {
96
- this._prompt = prompt;
435
+ Object.setPrototypeOf(InterfaceConstructor.prototype, EventEmitter.prototype);
436
+ Object.setPrototypeOf(InterfaceConstructor, EventEmitter);
437
+
438
+ /* the history accessors each instance gets */
439
+ const kHistoryAccessorDescriptors = {
440
+ __proto__: null,
441
+ history: {
442
+ __proto__: null, configurable: true, enumerable: true,
443
+ get() { return this.historyManager.history; },
444
+ set(newHistory) { return this.historyManager.history = newHistory; },
445
+ },
446
+ historyIndex: {
447
+ __proto__: null, configurable: true, enumerable: true,
448
+ get() { return this.historyManager.index; },
449
+ set(historyIndex) { return this.historyManager.index = historyIndex; },
450
+ },
451
+ historySize: {
452
+ __proto__: null, configurable: true, enumerable: true,
453
+ get() { return this.historyManager.size; },
454
+ },
455
+ isFlushing: {
456
+ __proto__: null, configurable: true, enumerable: true,
457
+ get() { return this.historyManager.isFlushing; },
458
+ },
97
459
  };
98
460
 
99
- Interface.prototype.getPrompt = function getPrompt() {
100
- return this._prompt;
101
- };
461
+ export class Interface extends InterfaceConstructor {
462
+ get columns() {
463
+ if (this.output?.columns) return this.output.columns;
464
+ return Infinity;
465
+ }
102
466
 
103
- Interface.prototype._writeToOutput = function _writeToOutput(text) {
104
- validateString(text, "stringToWrite");
105
- if (this.output !== null && this.output !== undefined) this.output.write(text);
106
- };
467
+ setPrompt(prompt) {
468
+ this[kPrompt] = prompt;
469
+ }
107
470
 
108
- /** Writes the prompt, and reads again if paused. */
109
- Interface.prototype.prompt = function prompt() {
110
- if (this.paused) this.resume();
111
- if (this.closed) throw codeError(Error, "ERR_USE_AFTER_CLOSE", "readline was closed");
112
- this._writeToOutput(this._prompt);
113
- };
471
+ getPrompt() {
472
+ return this[kPrompt];
473
+ }
114
474
 
115
- Interface.prototype[kQuestion] = function question(query, cb) {
116
- if (this.closed) throw codeError(Error, "ERR_USE_AFTER_CLOSE", "readline was closed");
117
- if (this._questionCallback) this.prompt();
118
- else {
119
- this._oldPrompt = this._prompt;
120
- this.setPrompt(query);
121
- this._questionCallback = cb;
122
- this.prompt();
475
+ setupHistoryManager(options) {
476
+ this.historyManager = new ReplHistory(this, options);
477
+ Object.defineProperties(this, kHistoryAccessorDescriptors);
123
478
  }
124
- };
125
479
 
126
- /* a question given up: its prompt goes, and the line is cleared, as Node's clearLine */
127
- Interface.prototype[kQuestionCancel] = function questionCancel() {
128
- if (!this._questionCallback) return;
129
- this._questionCallback = null;
130
- this.setPrompt(this._oldPrompt);
131
- this._writeToOutput("\r\n");
132
- this.line = "";
133
- this.cursor = 0;
134
- };
480
+ [kSetRawMode](mode) {
481
+ const wasInRawMode = this.input.isRaw;
482
+ if (typeof this.input.setRawMode === "function") this.input.setRawMode(mode);
483
+ return wasInRawMode;
484
+ }
135
485
 
136
- /** question(query[, { signal }], cb): writes the query, and gives the next line to cb instead of
137
- * 'line'. */
138
- Interface.prototype.question = function question(query, options, cb) {
139
- cb = typeof options === "function" ? options : cb;
140
- if (options !== null && typeof options === "object") {
141
- const { signal } = options;
142
- if (signal) {
143
- validateSignal(signal, "options.signal");
144
- if (signal.aborted) return;
145
- const onAbort = () => this[kQuestionCancel]();
146
- signal.addEventListener("abort", onAbort, { once: true });
147
- const cleanup = () => signal.removeEventListener("abort", onAbort);
148
- const original = cb;
149
- cb = typeof cb === "function" ? (answer) => {
150
- cleanup();
151
- return original(answer);
152
- } : cleanup;
486
+ prompt(preserveCursor) {
487
+ if (this.paused) this.resume();
488
+ if (this.terminal && process.env.TERM !== "dumb") {
489
+ if (!preserveCursor) this.cursor = 0;
490
+ this[kRefreshLine]();
491
+ } else {
492
+ this[kWriteToOutput](this[kPrompt]);
153
493
  }
154
494
  }
155
- if (typeof cb === "function") this[kQuestion](query, cb);
156
- };
157
495
 
158
- /* util.promisify(rl.question): the answer, or an AbortError */
159
- Interface.prototype.question[kPromisifyCustom] = function question(query, options) {
160
- if (options === null || typeof options !== "object") options = {};
161
- return new Promise((resolve, reject) => {
162
- let cb = resolve;
163
- const { signal } = options;
164
- if (signal) {
165
- validateSignal(signal, "options.signal");
166
- if (signal.aborted) return reject(abortError(signal));
167
- const onAbort = () => reject(abortError(signal));
168
- signal.addEventListener("abort", onAbort, { once: true });
169
- cb = (answer) => {
170
- signal.removeEventListener("abort", onAbort);
171
- resolve(answer);
172
- };
496
+ [kQuestion](query, cb) {
497
+ if (this.closed) throw useAfterClose();
498
+ if (this[kQuestionCallback]) {
499
+ this.prompt();
500
+ } else {
501
+ this[kOldPrompt] = this[kPrompt];
502
+ this.setPrompt(query);
503
+ this[kQuestionCallback] = cb;
504
+ this.prompt();
173
505
  }
174
- this.question(query, options, cb);
175
- });
176
- };
506
+ }
177
507
 
178
- Interface.prototype.pause = function pause() {
179
- if (this.paused) return;
180
- this.input.pause();
181
- this.paused = true;
182
- this.emit("pause");
183
- return this;
184
- };
508
+ [kSetLine](line = "") {
509
+ this.line = line;
510
+ this[kIsMultiline] = line.includes("\n");
511
+ }
185
512
 
186
- Interface.prototype.resume = function resume() {
187
- if (!this.paused) return;
188
- this.input.resume();
189
- this.paused = false;
190
- this.emit("resume");
191
- return this;
192
- };
513
+ [kOnLine](line) {
514
+ if (this[kQuestionCallback]) {
515
+ const cb = this[kQuestionCallback];
516
+ this[kQuestionCallback] = null;
517
+ this.setPrompt(this[kOldPrompt]);
518
+ cb(line);
519
+ } else {
520
+ this.emit("line", line);
521
+ }
522
+ }
193
523
 
194
- /** Ends reading: the input is paused and 'close' emitted, once. */
195
- Interface.prototype.close = function close() {
196
- if (this.closed) return;
197
- this.pause();
198
- this.closed = true;
199
- this.emit("close");
200
- };
524
+ [kBeforeEdit](oldText, oldCursor) {
525
+ this[kPushToUndoStack](oldText, oldCursor);
526
+ }
201
527
 
202
- /** Data as if it had come from the input. */
203
- Interface.prototype.write = function write(data) {
204
- if (this.closed) throw codeError(Error, "ERR_USE_AFTER_CLOSE", "readline was closed");
205
- if (this.paused) this.resume();
206
- this._normalWrite(data);
207
- };
528
+ [kQuestionCancel]() {
529
+ if (this[kQuestionCallback]) {
530
+ this[kQuestionCallback] = null;
531
+ this.setPrompt(this[kOldPrompt]);
532
+ this.clearLine();
533
+ }
534
+ }
208
535
 
209
- Interface.prototype._onLine = function _onLine(line) {
210
- if (this._questionCallback) {
211
- const cb = this._questionCallback;
212
- this._questionCallback = null;
213
- this.setPrompt(this._oldPrompt);
214
- cb(line);
215
- } else this.emit("line", line);
216
- };
536
+ [kWriteToOutput](stringToWrite) {
537
+ validateString(stringToWrite, "stringToWrite");
538
+ if (this.output !== null && this.output !== undefined) this.output.write(stringToWrite);
539
+ }
217
540
 
218
- /* Node's _normalWrite: the chunk decoded, split into lines; what follows the last ending waits */
219
- Interface.prototype._normalWrite = function _normalWrite(chunk) {
220
- if (chunk === undefined) return;
221
- let string = this._decoder.write(chunk);
222
- if (this._sawReturnAt && Date.now() - this._sawReturnAt <= this.crlfDelay) {
223
- if (string.codePointAt(0) === 10) string = string.slice(1);
224
- this._sawReturnAt = 0;
225
- }
226
- lineEnding.lastIndex = 0;
227
- let match = lineEnding.exec(string);
228
- if (match === null) {
229
- if (string) this._lineBuffer = this._lineBuffer ? this._lineBuffer + string : string;
230
- return;
231
- }
232
- if (this._lineBuffer) {
233
- string = this._lineBuffer + string;
234
- this._lineBuffer = null;
235
- lineEnding.lastIndex = 0;
236
- match = lineEnding.exec(string);
237
- }
238
- this._sawReturnAt = string.endsWith("\r") ? Date.now() : 0;
239
- const indexes = [0, match.index, lineEnding.lastIndex];
240
- while ((match = lineEnding.exec(string)) !== null) indexes.push(match.index, lineEnding.lastIndex);
241
- const last = indexes.length - 1;
242
- this._lineBuffer = string.slice(indexes[last]);
243
- for (let i = 1; i < last; i += 2) {
244
- this._onLine(string.slice(indexes[i - 1], indexes[i]));
245
- if (this.closed) break;
541
+ [kAddHistory]() {
542
+ return this.historyManager.addHistory(this[kIsMultiline], this[kLastCommandErrored]);
246
543
  }
247
- };
248
544
 
249
- /** The lines, as an async iterator; reading pauses while the iterator's buffer is full. */
250
- Interface.prototype[Symbol.asyncIterator] = function asyncIterator() {
251
- if (this._lines === undefined) {
252
- const onLine = (line) => {
253
- if (!readable.push(line)) this.pause();
254
- };
255
- const onClose = () => readable.push(null);
256
- const onError = (err) => readable.destroy(err);
257
- const readable = new Readable({
258
- objectMode: true,
259
- read: () => this.resume(),
260
- destroy: (err, cb) => {
261
- this.off("line", onLine);
262
- this.off("close", onClose);
263
- this.off("error", onError);
264
- this.close();
265
- cb(err);
266
- },
267
- });
268
- this.on("error", onError);
269
- this.on("line", onLine);
270
- this.on("close", onClose);
271
- this._lines = readable;
272
- }
273
- return this._lines[Symbol.asyncIterator]();
274
- };
545
+ [kRefreshLine]() {
546
+ const line = this[kPrompt] + this.line;
547
+ const dispPos = this[kGetDisplayPos](line);
548
+ const lineCols = dispPos.cols;
549
+ const lineRows = dispPos.rows;
550
+ const cursorPos = this.getCursorPos();
551
+ /* to the bottom of the line, from the cursor; to its left edge; cleared */
552
+ const prevRows = this.prevRows || 0;
553
+ if (prevRows > 0) moveCursor(this.output, 0, -prevRows);
554
+ cursorTo(this.output, 0);
555
+ clearScreenDown(this.output);
556
+ if (this[kIsMultiline]) {
557
+ const lines = this.line.split("\n");
558
+ this[kWriteToOutput](this[kPrompt] + lines[0]);
559
+ for (let i = 1; i < lines.length; i++) this[kWriteToOutput](`\n${kMultilinePrompt.description}` + lines[i]);
560
+ } else {
561
+ this[kWriteToOutput](line);
562
+ }
563
+ /* the terminal makes a new line once something is on it */
564
+ if (lineCols === 0) this[kWriteToOutput](" ");
565
+ cursorTo(this.output, cursorPos.cols);
566
+ const diff = lineRows - cursorPos.rows;
567
+ if (diff > 0) moveCursor(this.output, 0, -diff);
568
+ this.prevRows = cursorPos.rows;
569
+ }
275
570
 
276
- export function createInterface(input, output, completer, terminal) {
277
- return new Interface(input, output, completer, terminal);
278
- }
571
+ close() {
572
+ if (this.closed) return;
573
+ this.pause();
574
+ if (this.terminal) this[kSetRawMode](false);
575
+ this.closed = true;
576
+ this.emit("close");
577
+ }
279
578
 
280
- /* ---- the cursor: ANSI escapes ------------------------------------------------------------ */
579
+ pause() {
580
+ if (this.closed) throw useAfterClose();
581
+ if (this.paused) return;
582
+ this.input.pause();
583
+ this.paused = true;
584
+ this.emit("pause");
585
+ return this;
586
+ }
281
587
 
282
- const CSI = "\x1b[";
588
+ resume() {
589
+ if (this.closed) throw useAfterClose();
590
+ if (!this.paused) return;
591
+ this.input.resume();
592
+ this.paused = false;
593
+ this.emit("resume");
594
+ return this;
595
+ }
283
596
 
284
- /* a write, or with no stream the callback on a later tick */
285
- function writeTo(stream, data, callback) {
286
- if (callback !== undefined) validateFunction(callback, "callback");
287
- if (stream === null || stream === undefined || data === "") {
288
- if (typeof callback === "function") process.nextTick(callback, null);
289
- return true;
597
+ write(d, key) {
598
+ if (this.closed) throw useAfterClose();
599
+ if (this.paused) this.resume();
600
+ if (this.terminal) this[kTtyWrite](d, key);
601
+ else this[kNormalWrite](d);
290
602
  }
291
- return stream.write(data, callback);
292
- }
293
603
 
294
- /** The escape that clears the line: to its start (dir < 0), its end (dir > 0) or all of it. */
295
- export function clearLineEscape(dir) {
296
- return dir < 0 ? CSI + "1K" : dir > 0 ? CSI + "0K" : CSI + "2K";
297
- }
604
+ [kNormalWrite](b) {
605
+ if (b === undefined) return;
606
+ let string = this[kDecoder].write(b);
607
+ if (this[kSawReturnAt] && Date.now() - this[kSawReturnAt] <= this.crlfDelay) {
608
+ if (string.codePointAt() === 10) string = string.slice(1);
609
+ this[kSawReturnAt] = 0;
610
+ }
611
+ if (!string) return;
612
+ /* the new chunk split, not the whole buffer: a plain split when it has none of the rarer endings */
613
+ const lines = string.includes("\r") || string.includes("\u2028") || string.includes("\u2029") ? string.split(lineEnding) : string.split("\n");
614
+ const lastIndex = lines.length - 1;
615
+ if (lastIndex === 0) {
616
+ if (this[kLine_buffer]) this[kLine_buffer] += string;
617
+ else this[kLine_buffer] = string;
618
+ return;
619
+ }
620
+ this[kSawReturnAt] = string.endsWith("\r") ? Date.now() : 0;
621
+ let first = lines[0];
622
+ if (this[kLine_buffer]) first = this[kLine_buffer] + first;
623
+ /* '' or the next line's start */
624
+ this[kLine_buffer] = lines[lastIndex];
625
+ this[kOnLine](first);
626
+ for (let i = 1; i < lastIndex; i++) this[kOnLine](lines[i]);
627
+ }
298
628
 
299
- export function cursorToEscape(x, y) {
300
- if (Number.isNaN(x)) throw codeError(TypeError, "ERR_INVALID_ARG_VALUE", "The argument 'x' is invalid. Received NaN");
301
- if (Number.isNaN(y)) throw codeError(TypeError, "ERR_INVALID_ARG_VALUE", "The argument 'y' is invalid. Received NaN");
302
- if (typeof x !== "number") throw codeError(TypeError, "ERR_INVALID_CURSOR_POS", "Cannot set cursor row without setting its column");
303
- return typeof y !== "number" ? CSI + (x + 1) + "G" : CSI + (y + 1) + ";" + (x + 1) + "H";
304
- }
629
+ [kSavePreviousState]() {
630
+ this[kPreviousLine] = this.line;
631
+ this[kPreviousCursor] = this.cursor;
632
+ this[kPreviousPrevRows] = this.prevRows;
633
+ }
305
634
 
306
- export function moveCursorEscape(dx, dy) {
307
- let data = "";
308
- if (dx < 0) data += CSI + -dx + "D";
309
- else if (dx > 0) data += CSI + dx + "C";
310
- if (dy < 0) data += CSI + -dy + "A";
311
- else if (dy > 0) data += CSI + dy + "B";
312
- return data;
313
- }
635
+ [kRestorePreviousState]() {
636
+ this[kSetLine](this[kPreviousLine]);
637
+ this.cursor = this[kPreviousCursor];
638
+ this.prevRows = this[kPreviousPrevRows];
639
+ }
314
640
 
315
- export function clearLine(stream, dir, callback) {
316
- return writeTo(stream, clearLineEscape(dir), callback);
317
- }
641
+ clearLine() {
642
+ this[kMoveCursor](+Infinity);
643
+ this[kWriteToOutput]("\r\n");
644
+ this[kSetLine]("");
645
+ this.cursor = 0;
646
+ this.prevRows = 0;
647
+ }
318
648
 
319
- export function clearScreenDown(stream, callback) {
320
- return writeTo(stream, CSI + "0J", callback);
321
- }
649
+ [kPushToUndoStack](text, cursor) {
650
+ if (this[kUndoStack].push({ text, cursor }) > 2048) this[kUndoStack].shift();
651
+ }
322
652
 
323
- export function cursorTo(stream, x, y, callback) {
324
- if (typeof y === "function") {
325
- callback = y;
326
- y = undefined;
653
+ /* where `str` ends on the screen: its rows and the column on the last */
654
+ [kGetDisplayPos](str) {
655
+ let offset = 0;
656
+ const col = this.columns;
657
+ let rows = 0;
658
+ str = stripVTControlCharacters(str);
659
+ for (const char of str) {
660
+ if (char === "\n") {
661
+ rows += Math.ceil(offset / col) || 1;
662
+ offset = this[kIsMultiline] ? kMultilinePrompt.description.length : 0;
663
+ continue;
664
+ }
665
+ if (char === "\t") {
666
+ offset += this.tabSize - (offset % this.tabSize);
667
+ continue;
668
+ }
669
+ const width = getStringWidth(char, false);
670
+ if (width === 0 || width === 1) {
671
+ offset += width;
672
+ } else {
673
+ /* a wide character doesn't fit in the last column: it starts the next row */
674
+ if ((offset + 1) % col === 0) offset++;
675
+ offset += 2;
676
+ }
677
+ }
678
+ const cols = offset % col;
679
+ rows += (offset - cols) / col;
680
+ return { cols, rows };
327
681
  }
328
- if (stream === null || stream === undefined || (typeof x !== "number" && typeof y !== "number")) return writeTo(null, "", callback);
329
- return writeTo(stream, cursorToEscape(x, y), callback);
330
- }
331
682
 
332
- export function moveCursor(stream, dx, dy, callback) {
333
- return writeTo(stream, moveCursorEscape(dx, dy), callback);
334
- }
683
+ getCursorPos() {
684
+ const strBeforeCursor = this[kPrompt] + this.line.slice(0, this.cursor);
685
+ return this[kGetDisplayPos](strBeforeCursor);
686
+ }
687
+
688
+ [kMoveCursor](dx) {
689
+ if (dx === 0) return;
690
+ const oldPos = this.getCursorPos();
691
+ this.cursor += dx;
692
+ if (this.cursor < 0) this.cursor = 0;
693
+ else if (this.cursor > this.line.length) this.cursor = this.line.length;
694
+ const newPos = this.getCursorPos();
695
+ /* on the same row: moved; across rows: the line redrawn */
696
+ if (oldPos.rows === newPos.rows) moveCursor(this.output, newPos.cols - oldPos.cols, 0);
697
+ else this[kRefreshLine]();
698
+ }
335
699
 
336
- export function emitKeypressEvents() {
337
- throw notSupported("readline.emitKeypressEvents");
700
+ /* events.on (internal/events_on.js, linked into readline programs that iterate) */
701
+ [Symbol.asyncIterator]() {
702
+ if (this[kLineObjectStream] === undefined) {
703
+ this[kLineObjectStream] = feature("on")(this, "line", { close: ["close"], highWaterMark: 1024, [kFirstEventParam]: true });
704
+ }
705
+ return this[kLineObjectStream];
706
+ }
338
707
  }
708
+
709
+ Interface.prototype[Symbol.dispose] = function () {
710
+ this.close();
711
+ };
712
+ Object.defineProperty(Interface.prototype[Symbol.dispose], "name", { value: "[Symbol.dispose]" });