neonctl 2.27.1 → 2.29.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.
Files changed (136) hide show
  1. package/README.md +35 -3
  2. package/dist/analytics.js +52 -34
  3. package/dist/api.js +643 -13
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +8 -1
  6. package/dist/commands/auth.js +64 -51
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +160 -150
  9. package/dist/commands/bucket.js +183 -146
  10. package/dist/commands/checkout.js +51 -51
  11. package/dist/commands/config.js +228 -82
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +100 -101
  14. package/dist/commands/databases.js +29 -26
  15. package/dist/commands/deploy.js +12 -12
  16. package/dist/commands/dev.js +114 -114
  17. package/dist/commands/env.js +43 -43
  18. package/dist/commands/functions.js +101 -104
  19. package/dist/commands/index.js +27 -25
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +232 -182
  23. package/dist/commands/neon_auth.js +385 -370
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +103 -101
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +27 -24
  29. package/dist/commands/schema_diff.js +25 -26
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +40 -0
  32. package/dist/commands/user.js +5 -5
  33. package/dist/commands/vpc_endpoints.js +50 -50
  34. package/dist/config.js +7 -7
  35. package/dist/config_format.js +5 -5
  36. package/dist/context.js +37 -14
  37. package/dist/current_branch_fast_path.js +55 -0
  38. package/dist/dev/env.js +33 -33
  39. package/dist/dev/functions.js +4 -4
  40. package/dist/dev/inputs.js +6 -6
  41. package/dist/dev/runtime.js +25 -25
  42. package/dist/env.js +14 -14
  43. package/dist/env_file.js +13 -13
  44. package/dist/errors.js +68 -5
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +110 -107
  48. package/dist/log.js +2 -2
  49. package/dist/parameters.gen.js +14 -14
  50. package/dist/pkg.js +5 -5
  51. package/dist/psql/cli.js +4 -2
  52. package/dist/psql/command/cmd_cond.js +61 -61
  53. package/dist/psql/command/cmd_connect.js +159 -154
  54. package/dist/psql/command/cmd_copy.js +107 -97
  55. package/dist/psql/command/cmd_describe.js +368 -363
  56. package/dist/psql/command/cmd_format.js +276 -263
  57. package/dist/psql/command/cmd_io.js +269 -263
  58. package/dist/psql/command/cmd_lo.js +74 -66
  59. package/dist/psql/command/cmd_meta.js +148 -148
  60. package/dist/psql/command/cmd_misc.js +17 -17
  61. package/dist/psql/command/cmd_pipeline.js +142 -135
  62. package/dist/psql/command/cmd_restrict.js +25 -25
  63. package/dist/psql/command/cmd_show.js +183 -168
  64. package/dist/psql/command/dispatch.js +26 -26
  65. package/dist/psql/command/shared.js +14 -14
  66. package/dist/psql/complete/filenames.js +16 -16
  67. package/dist/psql/complete/index.js +4 -4
  68. package/dist/psql/complete/matcher.js +33 -32
  69. package/dist/psql/complete/psqlVars.js +173 -173
  70. package/dist/psql/complete/queries.js +5 -3
  71. package/dist/psql/complete/rules.js +900 -863
  72. package/dist/psql/core/common.js +136 -133
  73. package/dist/psql/core/help.js +343 -343
  74. package/dist/psql/core/mainloop.js +160 -153
  75. package/dist/psql/core/prompt.js +126 -123
  76. package/dist/psql/core/settings.js +111 -111
  77. package/dist/psql/core/sqlHelp.js +150 -150
  78. package/dist/psql/core/startup.js +211 -205
  79. package/dist/psql/core/syncVars.js +14 -14
  80. package/dist/psql/core/variables.js +24 -24
  81. package/dist/psql/describe/formatters.js +302 -289
  82. package/dist/psql/describe/processNamePattern.js +28 -28
  83. package/dist/psql/describe/queries.js +656 -651
  84. package/dist/psql/index.js +436 -411
  85. package/dist/psql/io/history.js +36 -36
  86. package/dist/psql/io/input.js +15 -15
  87. package/dist/psql/io/lineEditor/buffer.js +27 -25
  88. package/dist/psql/io/lineEditor/complete.js +15 -15
  89. package/dist/psql/io/lineEditor/filename.js +22 -22
  90. package/dist/psql/io/lineEditor/index.js +65 -62
  91. package/dist/psql/io/lineEditor/keymap.js +325 -318
  92. package/dist/psql/io/lineEditor/vt100.js +60 -60
  93. package/dist/psql/io/pgpass.js +18 -18
  94. package/dist/psql/io/pgservice.js +14 -14
  95. package/dist/psql/io/psqlrc.js +46 -46
  96. package/dist/psql/print/aligned.js +175 -166
  97. package/dist/psql/print/asciidoc.js +51 -51
  98. package/dist/psql/print/crosstab.js +34 -31
  99. package/dist/psql/print/csv.js +25 -22
  100. package/dist/psql/print/html.js +54 -54
  101. package/dist/psql/print/json.js +12 -12
  102. package/dist/psql/print/latex.js +118 -118
  103. package/dist/psql/print/pager.js +28 -26
  104. package/dist/psql/print/troff.js +48 -48
  105. package/dist/psql/print/unaligned.js +15 -14
  106. package/dist/psql/print/units.js +17 -17
  107. package/dist/psql/scanner/slash.js +48 -46
  108. package/dist/psql/scanner/sql.js +88 -84
  109. package/dist/psql/scanner/stringutils.js +21 -17
  110. package/dist/psql/types/index.js +7 -7
  111. package/dist/psql/types/scanner.js +8 -8
  112. package/dist/psql/wire/connection.js +341 -327
  113. package/dist/psql/wire/copy.js +7 -7
  114. package/dist/psql/wire/pipeline.js +26 -24
  115. package/dist/psql/wire/protocol.js +102 -102
  116. package/dist/psql/wire/sasl.js +62 -62
  117. package/dist/psql/wire/tls.js +79 -73
  118. package/dist/storage_api.js +22 -23
  119. package/dist/test_utils/fixtures.js +74 -41
  120. package/dist/test_utils/oauth_server.js +5 -5
  121. package/dist/utils/api_enums.js +33 -0
  122. package/dist/utils/branch_notice.js +5 -5
  123. package/dist/utils/branch_picker.js +26 -26
  124. package/dist/utils/compute_units.js +4 -4
  125. package/dist/utils/enrichers.js +28 -16
  126. package/dist/utils/esbuild.js +28 -28
  127. package/dist/utils/formats.js +1 -1
  128. package/dist/utils/middlewares.js +3 -3
  129. package/dist/utils/package_manager.js +68 -0
  130. package/dist/utils/point_in_time.js +12 -12
  131. package/dist/utils/psql.js +30 -30
  132. package/dist/utils/string.js +2 -2
  133. package/dist/utils/ui.js +9 -9
  134. package/dist/utils/zip.js +1 -1
  135. package/dist/writer.js +17 -17
  136. package/package.json +10 -12
@@ -35,22 +35,22 @@ export const doubleQuote = (s) => `"${s.replace(/[\\"$`]/g, (m) => `\\${m}`)}"`;
35
35
  export const detectQuoteStyle = (prefix) => {
36
36
  // Walk left-to-right tracking the current quote state. A naive last-quote
37
37
  // approach gets fooled by escaped quotes inside doublequotes.
38
- let style = 'none';
38
+ let style = "none";
39
39
  let i = 0;
40
40
  while (i < prefix.length) {
41
41
  const ch = prefix[i];
42
- if (style === 'none') {
42
+ if (style === "none") {
43
43
  if (ch === "'") {
44
- style = 'single';
44
+ style = "single";
45
45
  i++;
46
46
  continue;
47
47
  }
48
48
  if (ch === '"') {
49
- style = 'double';
49
+ style = "double";
50
50
  i++;
51
51
  continue;
52
52
  }
53
- if (ch === '\\' && i + 1 < prefix.length) {
53
+ if (ch === "\\" && i + 1 < prefix.length) {
54
54
  // Escaped char outside quotes: skip the escape.
55
55
  i += 2;
56
56
  continue;
@@ -58,19 +58,19 @@ export const detectQuoteStyle = (prefix) => {
58
58
  i++;
59
59
  continue;
60
60
  }
61
- if (style === 'single') {
61
+ if (style === "single") {
62
62
  if (ch === "'")
63
- style = 'none';
63
+ style = "none";
64
64
  i++;
65
65
  continue;
66
66
  }
67
67
  // double-quoted
68
68
  if (ch === '"') {
69
- style = 'none';
69
+ style = "none";
70
70
  i++;
71
71
  continue;
72
72
  }
73
- if (ch === '\\' && i + 1 < prefix.length) {
73
+ if (ch === "\\" && i + 1 < prefix.length) {
74
74
  i += 2;
75
75
  continue;
76
76
  }
@@ -91,12 +91,12 @@ export const detectQuoteStyle = (prefix) => {
91
91
  */
92
92
  export const quoteForCompletion = (name, style) => {
93
93
  switch (style) {
94
- case 'none':
94
+ case "none":
95
95
  return needsQuoting(name) ? singleQuote(name) : name;
96
- case 'single':
96
+ case "single":
97
97
  // Inside single quotes, only `'` is special.
98
98
  return name.replace(/'/g, "'\\''");
99
- case 'double':
99
+ case "double":
100
100
  // Inside double quotes: \, ", $, ` need escaping.
101
101
  return name.replace(/[\\"$`]/g, (m) => `\\${m}`);
102
102
  }
@@ -106,23 +106,23 @@ export const quoteForCompletion = (name, style) => {
106
106
  * the caller wants to feed the partial input to a filesystem lookup.
107
107
  */
108
108
  export const unquote = (s) => {
109
- let out = '';
110
- let style = 'none';
109
+ let out = "";
110
+ let style = "none";
111
111
  let i = 0;
112
112
  while (i < s.length) {
113
113
  const ch = s[i];
114
- if (style === 'none') {
114
+ if (style === "none") {
115
115
  if (ch === "'") {
116
- style = 'single';
116
+ style = "single";
117
117
  i++;
118
118
  continue;
119
119
  }
120
120
  if (ch === '"') {
121
- style = 'double';
121
+ style = "double";
122
122
  i++;
123
123
  continue;
124
124
  }
125
- if (ch === '\\' && i + 1 < s.length) {
125
+ if (ch === "\\" && i + 1 < s.length) {
126
126
  out += s[i + 1];
127
127
  i += 2;
128
128
  continue;
@@ -131,9 +131,9 @@ export const unquote = (s) => {
131
131
  i++;
132
132
  continue;
133
133
  }
134
- if (style === 'single') {
134
+ if (style === "single") {
135
135
  if (ch === "'") {
136
- style = 'none';
136
+ style = "none";
137
137
  i++;
138
138
  continue;
139
139
  }
@@ -143,11 +143,11 @@ export const unquote = (s) => {
143
143
  }
144
144
  // double-quoted
145
145
  if (ch === '"') {
146
- style = 'none';
146
+ style = "none";
147
147
  i++;
148
148
  continue;
149
149
  }
150
- if (ch === '\\' && i + 1 < s.length) {
150
+ if (ch === "\\" && i + 1 < s.length) {
151
151
  out += s[i + 1];
152
152
  i += 2;
153
153
  continue;
@@ -37,23 +37,23 @@
37
37
  * breaks come from explicit `\r\n` only on submit or when we need to
38
38
  * display multi-row output (paste-mode newlines, candidate listings).
39
39
  */
40
- import { LineBuffer } from './buffer.js';
41
- import { dispatch, makeState, } from './keymap.js';
42
- import { CompletionState, formatCandidates, } from './complete.js';
43
- import { BEL, CR, LF, Vt100Decoder, csiClearScreen, csiDown, csiEraseToEol, csiLeft, csiRight, csiUp, disableBracketedPaste, enableBracketedPaste, } from './vt100.js';
40
+ import { LineBuffer } from "./buffer.js";
41
+ import { CompletionState, formatCandidates, } from "./complete.js";
42
+ import { dispatch, makeState, } from "./keymap.js";
43
+ import { BEL, CR, csiClearScreen, csiDown, csiEraseToEol, csiLeft, csiRight, csiUp, disableBracketedPaste, enableBracketedPaste, LF, Vt100Decoder, } from "./vt100.js";
44
44
  /** Thrown when ^C cancels the current line. */
45
45
  export class SignalError extends Error {
46
46
  constructor() {
47
- super('SIGINT');
48
- this.name = 'SignalError';
49
- this.signal = 'SIGINT';
47
+ super("SIGINT");
48
+ this.name = "SignalError";
49
+ this.signal = "SIGINT";
50
50
  }
51
51
  }
52
52
  /**
53
53
  * Sentinel for "Ctrl-D on an empty line". Compared with `===` by callers
54
54
  * so we don't accidentally match a literal string.
55
55
  */
56
- const EOF_SYMBOL = Symbol('LineEditor.EOF');
56
+ const EOF_SYMBOL = Symbol("LineEditor.EOF");
57
57
  export class LineEditor {
58
58
  constructor(opts = {}) {
59
59
  this.EOF = EOF_SYMBOL;
@@ -79,8 +79,8 @@ export class LineEditor {
79
79
  this.stdout = opts.stdout ?? process.stdout;
80
80
  this.bracketedPaste = opts.bracketedPaste ?? true;
81
81
  this.completer = opts.completer;
82
- this.mode = opts.mode ?? 'emacs';
83
- this.state = makeState(opts.history ?? [], this.mode === 'vi' ? 'insert' : 'emacs');
82
+ this.mode = opts.mode ?? "emacs";
83
+ this.state = makeState(opts.history ?? [], this.mode === "vi" ? "insert" : "emacs");
84
84
  this.decoder = new Vt100Decoder({
85
85
  // LineEditor default: 50ms matches GNU readline's `keyseq-timeout`
86
86
  // default — enough to disambiguate Alt-X across all modern terminals
@@ -95,7 +95,7 @@ export class LineEditor {
95
95
  /** Read one line. Resolves on Enter; rejects on Ctrl-C. */
96
96
  readLine(prompt) {
97
97
  if (this.active !== null) {
98
- return Promise.reject(new Error('LineEditor.readLine called re-entrantly'));
98
+ return Promise.reject(new Error("LineEditor.readLine called re-entrantly"));
99
99
  }
100
100
  // Apply any pending setMode() request at this readLine boundary so an
101
101
  // in-flight line keeps its prior dispatch.
@@ -112,14 +112,14 @@ export class LineEditor {
112
112
  // emacs → 'emacs'. This must happen on every readLine so a mid-session
113
113
  // VI_MODE flip is observed (the state machine has its own per-line
114
114
  // mode field that needs to be reset).
115
- if (this.mode === 'vi') {
116
- this.state.mode = 'insert';
115
+ if (this.mode === "vi") {
116
+ this.state.mode = "insert";
117
117
  this.state.viPending = null;
118
118
  }
119
119
  else {
120
- this.state.mode = 'emacs';
120
+ this.state.mode = "emacs";
121
121
  this.state.viPending = null;
122
- this.state.exBuffer = '';
122
+ this.state.exBuffer = "";
123
123
  }
124
124
  this.completion.reset();
125
125
  this.active = {
@@ -179,7 +179,7 @@ export class LineEditor {
179
179
  const a = this.active;
180
180
  this.moveCursorToEnd();
181
181
  this.stdout.write(LF);
182
- const body = text.endsWith('\n') ? text.slice(0, -1) : text;
182
+ const body = text.endsWith("\n") ? text.slice(0, -1) : text;
183
183
  this.stdout.write(body);
184
184
  this.stdout.write(LF);
185
185
  // Reset drawn-state so render() lays out a fresh block under the
@@ -239,19 +239,19 @@ export class LineEditor {
239
239
  this.dataListener = (chunk) => {
240
240
  this.handleChunk(chunk);
241
241
  };
242
- s.on('data', this.dataListener);
242
+ s.on("data", this.dataListener);
243
243
  if (!this.exitListener) {
244
244
  this.exitListener = () => {
245
245
  this.exitRaw();
246
246
  };
247
- process.once('exit', this.exitListener);
248
- process.once('SIGTERM', this.exitListener);
247
+ process.once("exit", this.exitListener);
248
+ process.once("SIGTERM", this.exitListener);
249
249
  }
250
250
  }
251
251
  exitRaw() {
252
252
  const s = this.stdin;
253
253
  if (this.dataListener !== null) {
254
- s.off('data', this.dataListener);
254
+ s.off("data", this.dataListener);
255
255
  this.dataListener = null;
256
256
  }
257
257
  if (isTtyReadStream(s) && !this.wasRaw) {
@@ -271,8 +271,8 @@ export class LineEditor {
271
271
  }
272
272
  }
273
273
  if (this.exitListener !== null) {
274
- process.off('exit', this.exitListener);
275
- process.off('SIGTERM', this.exitListener);
274
+ process.off("exit", this.exitListener);
275
+ process.off("SIGTERM", this.exitListener);
276
276
  this.exitListener = null;
277
277
  }
278
278
  }
@@ -344,16 +344,16 @@ export class LineEditor {
344
344
  return;
345
345
  const a = this.active;
346
346
  switch (action.kind) {
347
- case 'noop':
347
+ case "noop":
348
348
  return;
349
- case 'redraw':
349
+ case "redraw":
350
350
  this.resetCompletion();
351
351
  this.render();
352
352
  return;
353
- case 'bell':
353
+ case "bell":
354
354
  this.stdout.write(BEL);
355
355
  return;
356
- case 'submit': {
356
+ case "submit": {
357
357
  this.resetCompletion();
358
358
  const text = this.state.buffer.text;
359
359
  // Move cursor past the end of the rendered block and emit a newline.
@@ -365,7 +365,7 @@ export class LineEditor {
365
365
  resolve(text);
366
366
  return;
367
367
  }
368
- case 'cancel': {
368
+ case "cancel": {
369
369
  // Upstream psql doesn't echo `^C` to the screen on Ctrl-C — it just
370
370
  // breaks to the next prompt line silently. Match that behaviour.
371
371
  this.resetCompletion();
@@ -377,7 +377,7 @@ export class LineEditor {
377
377
  reject(new SignalError());
378
378
  return;
379
379
  }
380
- case 'eof': {
380
+ case "eof": {
381
381
  this.resetCompletion();
382
382
  this.moveCursorToEnd();
383
383
  this.stdout.write(LF);
@@ -387,7 +387,7 @@ export class LineEditor {
387
387
  resolve(EOF_SYMBOL);
388
388
  return;
389
389
  }
390
- case 'complete': {
390
+ case "complete": {
391
391
  if (!this.completer) {
392
392
  this.stdout.write(BEL);
393
393
  return;
@@ -395,7 +395,7 @@ export class LineEditor {
395
395
  await this.runCompletion();
396
396
  return;
397
397
  }
398
- case 'clear-screen':
398
+ case "clear-screen":
399
399
  this.resetCompletion();
400
400
  this.stdout.write(csiClearScreen());
401
401
  a.rowsDrawn = 0;
@@ -403,21 +403,21 @@ export class LineEditor {
403
403
  a.cursorCol = 0;
404
404
  this.render(true);
405
405
  return;
406
- case 'search-start':
406
+ case "search-start":
407
407
  this.resetCompletion();
408
408
  a.search = {
409
- pattern: '',
409
+ pattern: "",
410
410
  matchIndex: null,
411
411
  savedBuffer: this.state.buffer.text,
412
412
  };
413
413
  this.render();
414
414
  return;
415
- case 'paste-start':
416
- case 'paste-end':
415
+ case "paste-start":
416
+ case "paste-end":
417
417
  // Bracketed paste markers are otherwise transparent.
418
418
  void ev;
419
419
  return;
420
- case 'ex-update':
420
+ case "ex-update":
421
421
  // Vi `:`-ex prompt text changed (entered/typed/backspaced). The
422
422
  // renderer reads `state.mode === 'ex'` and swaps in a `: <buf>` line.
423
423
  this.resetCompletion();
@@ -435,13 +435,13 @@ export class LineEditor {
435
435
  if (this.active === null)
436
436
  return;
437
437
  switch (step.kind) {
438
- case 'bell':
438
+ case "bell":
439
439
  this.stdout.write(BEL);
440
440
  return;
441
- case 'inserted':
441
+ case "inserted":
442
442
  this.render();
443
443
  return;
444
- case 'cycled': {
444
+ case "cycled": {
445
445
  // In-place rewrite of the candidate listing with the new highlight.
446
446
  // If we already have a listing on screen (placed above the current
447
447
  // prompt block by an earlier `list` or `cycled`), navigate up to its
@@ -453,7 +453,7 @@ export class LineEditor {
453
453
  if (cands.length > 0) {
454
454
  const w = this.termWidth();
455
455
  const block = formatCandidates(cands, w, cycleIndex);
456
- const blockRows = block.split('\n').length;
456
+ const blockRows = block.split("\n").length;
457
457
  if (this.active.listingRowsDrawn > 0) {
458
458
  this.rewriteListingInPlace(block, blockRows);
459
459
  }
@@ -466,11 +466,11 @@ export class LineEditor {
466
466
  }
467
467
  return;
468
468
  }
469
- case 'list': {
469
+ case "list": {
470
470
  // Print listing on a new row, then redraw the prompt+line below it.
471
471
  const w = this.termWidth();
472
472
  const block = formatCandidates(step.candidates, w);
473
- const blockRows = block.split('\n').length;
473
+ const blockRows = block.split("\n").length;
474
474
  this.emitListingBelow(block, blockRows);
475
475
  return;
476
476
  }
@@ -523,7 +523,7 @@ export class LineEditor {
523
523
  // 3. Erase each listing row and write the new block. We treat the listing
524
524
  // as `blockRows` lines separated by LF; on the last line we DON'T emit
525
525
  // a trailing LF (otherwise we'd push the prompt down by one row).
526
- const newLines = block.split('\n');
526
+ const newLines = block.split("\n");
527
527
  for (let i = 0; i < newLines.length; i++) {
528
528
  this.stdout.write(csiEraseToEol());
529
529
  this.stdout.write(newLines[i]);
@@ -557,38 +557,41 @@ export class LineEditor {
557
557
  return;
558
558
  const s = this.active.search;
559
559
  // ^G or Escape cancels and restores the saved line.
560
- if ((ev.key === 'char' && ev.ctrl && ev.char === 'g') ||
561
- ev.key === 'escape') {
560
+ if ((ev.key === "char" && ev.ctrl && ev.char === "g") ||
561
+ ev.key === "escape") {
562
562
  this.state.buffer.setText(s.savedBuffer);
563
563
  this.active.search = null;
564
564
  this.render();
565
565
  return;
566
566
  }
567
567
  // Enter accepts the current match (whatever's in the buffer).
568
- if (ev.key === 'enter') {
568
+ if (ev.key === "enter") {
569
569
  this.active.search = null;
570
- await this.applyAction({ kind: 'submit' }, ev);
570
+ await this.applyAction({ kind: "submit" }, ev);
571
571
  return;
572
572
  }
573
573
  // ^C bubbles to cancel.
574
- if (ev.key === 'char' && ev.ctrl && ev.char === 'c') {
575
- await this.applyAction({ kind: 'cancel' }, ev);
574
+ if (ev.key === "char" && ev.ctrl && ev.char === "c") {
575
+ await this.applyAction({ kind: "cancel" }, ev);
576
576
  return;
577
577
  }
578
578
  // ^R again: search further back.
579
- if (ev.key === 'char' && ev.ctrl && ev.char === 'r') {
579
+ if (ev.key === "char" && ev.ctrl && ev.char === "r") {
580
580
  this.searchStep(-1);
581
581
  return;
582
582
  }
583
583
  // Backspace: shrink the pattern.
584
- if (ev.key === 'backspace') {
584
+ if (ev.key === "backspace") {
585
585
  s.pattern = s.pattern.slice(0, -1);
586
586
  s.matchIndex = null;
587
587
  this.searchStep(0);
588
588
  return;
589
589
  }
590
590
  // Printable char: extend the pattern.
591
- if (ev.key === 'char' && !ev.ctrl && !ev.meta && ev.char !== undefined) {
591
+ if (ev.key === "char" &&
592
+ !ev.ctrl &&
593
+ !ev.meta &&
594
+ ev.char !== undefined) {
592
595
  s.pattern += ev.char;
593
596
  s.matchIndex = null;
594
597
  this.searchStep(0);
@@ -606,7 +609,7 @@ export class LineEditor {
606
609
  const hist = this.state.history;
607
610
  const startFrom = s.matchIndex === null ? hist.length - 1 : s.matchIndex + delta;
608
611
  for (let i = startFrom; i >= 0 && i < hist.length; i--) {
609
- if (s.pattern === '' || hist[i].includes(s.pattern)) {
612
+ if (s.pattern === "" || hist[i].includes(s.pattern)) {
610
613
  s.matchIndex = i;
611
614
  this.state.buffer.setText(hist[i]);
612
615
  this.render();
@@ -632,7 +635,7 @@ export class LineEditor {
632
635
  if (!full && a.rowsDrawn > 0) {
633
636
  // Move up to the anchor row.
634
637
  const up = a.cursorRow;
635
- this.stdout.write(CR + (up > 0 ? csiUp(up) : ''));
638
+ this.stdout.write(CR + (up > 0 ? csiUp(up) : ""));
636
639
  }
637
640
  else {
638
641
  this.stdout.write(CR);
@@ -645,15 +648,15 @@ export class LineEditor {
645
648
  // - reverse-i-search: the `(reverse-i-search)\`pat':` preamble,
646
649
  // with the matched pattern highlighted.
647
650
  // - default editing: the caller-supplied prompt + buffer text.
648
- const inExMode = this.state.mode === 'ex';
651
+ const inExMode = this.state.mode === "ex";
649
652
  const promptStr = inExMode
650
- ? ':'
653
+ ? ":"
651
654
  : a.search === null
652
655
  ? a.prompt
653
656
  : `(reverse-i-search)\`${a.search.pattern}': `;
654
657
  const rawText = inExMode
655
658
  ? this.state.exBuffer
656
- : this.state.buffer.text.replace(/\n/g, ''); // newline glyph
659
+ : this.state.buffer.text.replace(/\n/g, ""); // newline glyph
657
660
  // For search rendering we highlight the matched pattern (case-insensitive)
658
661
  // inside the matched entry; otherwise the rendered text equals the raw text.
659
662
  const renderText = !inExMode && a.search !== null && a.search.pattern.length > 0
@@ -724,17 +727,17 @@ export class LineEditor {
724
727
  }
725
728
  termWidth() {
726
729
  const s = this.stdout;
727
- if (typeof s.columns === 'number' && s.columns > 0)
730
+ if (typeof s.columns === "number" && s.columns > 0)
728
731
  return s.columns;
729
732
  return 80;
730
733
  }
731
734
  }
732
- const isTtyReadStream = (s) => typeof s.setRawMode === 'function';
735
+ const isTtyReadStream = (s) => typeof s.setRawMode === "function";
733
736
  // ---------------------------------------------------------------------------
734
737
  // Search-line rendering / highlighting
735
738
  // ---------------------------------------------------------------------------
736
- const SGR_REVERSE = '\x1b[7m';
737
- const SGR_NO_REVERSE = '\x1b[27m';
739
+ const SGR_REVERSE = "\x1b[7m";
740
+ const SGR_NO_REVERSE = "\x1b[27m";
738
741
  /**
739
742
  * Wrap the first case-insensitive occurrence of `pattern` inside `text`
740
743
  * with the reverse-video SGR pair. Returns `text` unchanged when the
@@ -771,7 +774,7 @@ const stripAnsi = (text) =>
771
774
  // Targets the SGR forms we emit (e.g. \x1b[7m, \x1b[27m). Kept narrow on
772
775
  // purpose so it doesn't accidentally eat legitimate `[` characters.
773
776
  // eslint-disable-next-line no-control-regex
774
- text.replace(/\x1b\[[0-9;]*m/g, '');
777
+ text.replace(/\x1b\[[0-9;]*m/g, "");
775
778
  // ---------------------------------------------------------------------------
776
779
  // Display-width helpers (inlined copy of WP-09's tables; kept minimal).
777
780
  // ---------------------------------------------------------------------------
@@ -868,7 +871,7 @@ const positionAfter = (startCol, text, width) => {
868
871
  row += Math.floor(startCol / width);
869
872
  }
870
873
  for (const ch of text) {
871
- if (ch === '\n') {
874
+ if (ch === "\n") {
872
875
  row += 1;
873
876
  col = 0;
874
877
  continue;