neon 3.0.0 → 3.1.1

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 (207) hide show
  1. package/README.md +70 -5
  2. package/dist/_chunks/auth_selection-DGgq6ifc.js +83 -0
  3. package/dist/_chunks/cmd_pipeline-CUbBO9U_.js +2818 -0
  4. package/dist/_chunks/credentials-MYdHdKah.js +188 -0
  5. package/dist/_chunks/env-NbA61JR3.js +585 -0
  6. package/dist/_chunks/env_services-Tz9G4JeT.js +531 -0
  7. package/dist/_chunks/paths-DMq0Lt7a.js +151 -0
  8. package/dist/_chunks/profiles-Ir29rqns.js +217 -0
  9. package/dist/_chunks/psql-DWH-kc69.js +2169 -0
  10. package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  11. package/dist/_chunks/secure_file-BucZj4yQ.js +39 -0
  12. package/dist/analytics.js +163 -207
  13. package/dist/api.js +815 -758
  14. package/dist/auth.js +121 -141
  15. package/dist/auth_context.js +39 -53
  16. package/dist/cli.js +4 -7
  17. package/dist/commands/api.js +220 -250
  18. package/dist/commands/api_keys.js +251 -314
  19. package/dist/commands/auth.js +283 -328
  20. package/dist/commands/bootstrap.js +372 -437
  21. package/dist/commands/branches.js +304 -455
  22. package/dist/commands/bucket.js +374 -514
  23. package/dist/commands/checkout.js +213 -298
  24. package/dist/commands/config.js +573 -690
  25. package/dist/commands/connection_string.js +137 -165
  26. package/dist/commands/data_api.js +238 -260
  27. package/dist/commands/databases.js +67 -76
  28. package/dist/commands/deploy.js +31 -25
  29. package/dist/commands/dev.js +639 -719
  30. package/dist/commands/diff.js +156 -200
  31. package/dist/commands/env.js +255 -305
  32. package/dist/commands/functions.js +275 -355
  33. package/dist/commands/index.js +70 -65
  34. package/dist/commands/init.js +84 -119
  35. package/dist/commands/inspect.js +55 -55
  36. package/dist/commands/ip_allow.js +88 -120
  37. package/dist/commands/link.js +874 -1019
  38. package/dist/commands/logs.js +291 -0
  39. package/dist/commands/neon_auth.js +725 -933
  40. package/dist/commands/operations.js +34 -25
  41. package/dist/commands/orgs.js +28 -18
  42. package/dist/commands/profile.js +615 -846
  43. package/dist/commands/projects.js +313 -373
  44. package/dist/commands/psql.js +60 -58
  45. package/dist/commands/roles.js +55 -58
  46. package/dist/commands/schema_diff.js +87 -131
  47. package/dist/commands/set_context.js +34 -26
  48. package/dist/commands/snapshots.js +288 -413
  49. package/dist/commands/status.js +41 -37
  50. package/dist/commands/user.js +21 -10
  51. package/dist/commands/vpc_endpoints.js +85 -113
  52. package/dist/config.js +7 -6
  53. package/dist/config_format.js +50 -66
  54. package/dist/config_template.js +128 -157
  55. package/dist/context.js +183 -235
  56. package/dist/current_branch_fast_path.js +40 -49
  57. package/dist/dev/env.js +2 -446
  58. package/dist/dev/functions.js +54 -68
  59. package/dist/dev/inputs.js +46 -58
  60. package/dist/dev/runtime.js +135 -164
  61. package/dist/dev/websocket.js +766 -959
  62. package/dist/env.js +27 -33
  63. package/dist/env_file.js +118 -132
  64. package/dist/env_services.js +2 -51
  65. package/dist/errors.js +57 -68
  66. package/dist/functions_api.js +45 -43
  67. package/dist/help.js +189 -140
  68. package/dist/index.js +182 -257
  69. package/dist/init/agents.js +137 -118
  70. package/dist/init/auth.js +58 -68
  71. package/dist/init/bootstrap.js +325 -396
  72. package/dist/init/build_config.js +4 -2
  73. package/dist/init/detect_agent.js +56 -101
  74. package/dist/init/editors.js +35 -52
  75. package/dist/init/enrich_output.js +51 -66
  76. package/dist/init/extension.js +134 -171
  77. package/dist/init/inspect.js +179 -266
  78. package/dist/init/interactive.js +510 -622
  79. package/dist/init/neonctl.js +117 -168
  80. package/dist/init/orchestrate.js +157 -173
  81. package/dist/init/phases/auth.js +188 -202
  82. package/dist/init/phases/cleanup.js +23 -23
  83. package/dist/init/phases/db.js +251 -277
  84. package/dist/init/phases/getting_started.js +213 -223
  85. package/dist/init/phases/mcp.js +174 -224
  86. package/dist/init/phases/migrations.js +247 -248
  87. package/dist/init/phases/neon_auth.js +114 -133
  88. package/dist/init/phases/setup.js +546 -703
  89. package/dist/init/phases/skills.js +75 -86
  90. package/dist/init/phases/status.js +72 -67
  91. package/dist/init/resolve_context.js +102 -99
  92. package/dist/init/route_command.js +91 -98
  93. package/dist/init/skills.js +174 -218
  94. package/dist/init/vsix.js +77 -99
  95. package/dist/log.js +17 -16
  96. package/dist/neon_services.js +104 -129
  97. package/dist/parameters.gen.js +481 -471
  98. package/dist/pkg.js +17 -19
  99. package/dist/profile_keys.js +44 -47
  100. package/dist/psql/cli.js +44 -47
  101. package/dist/psql/command/cmd_cond.js +231 -406
  102. package/dist/psql/command/cmd_connect.js +557 -764
  103. package/dist/psql/command/cmd_copy.js +728 -984
  104. package/dist/psql/command/cmd_describe.js +1499 -1688
  105. package/dist/psql/command/cmd_format.js +733 -905
  106. package/dist/psql/command/cmd_io.js +2 -2193
  107. package/dist/psql/command/cmd_lo.js +297 -359
  108. package/dist/psql/command/cmd_meta.js +727 -878
  109. package/dist/psql/command/cmd_misc.js +138 -172
  110. package/dist/psql/command/cmd_pipeline.js +2 -1148
  111. package/dist/psql/command/cmd_restrict.js +119 -155
  112. package/dist/psql/command/cmd_show.js +529 -688
  113. package/dist/psql/command/dispatch.js +260 -325
  114. package/dist/psql/command/inputQueue.js +35 -33
  115. package/dist/psql/command/shared.js +49 -63
  116. package/dist/psql/complete/filenames.js +90 -133
  117. package/dist/psql/complete/index.js +59 -97
  118. package/dist/psql/complete/matcher.js +236 -300
  119. package/dist/psql/complete/psqlVars.js +218 -223
  120. package/dist/psql/complete/queries.js +159 -177
  121. package/dist/psql/complete/rules.js +1493 -2299
  122. package/dist/psql/core/common.js +2 -1253
  123. package/dist/psql/core/help.js +456 -546
  124. package/dist/psql/core/mainloop.js +692 -1303
  125. package/dist/psql/core/prompt.js +391 -408
  126. package/dist/psql/core/settings.js +429 -644
  127. package/dist/psql/core/sqlHelp.js +480 -554
  128. package/dist/psql/core/startup.js +2 -846
  129. package/dist/psql/core/syncVars.js +67 -110
  130. package/dist/psql/core/variables.js +156 -278
  131. package/dist/psql/describe/formatters.js +884 -1285
  132. package/dist/psql/describe/processNamePattern.js +173 -260
  133. package/dist/psql/describe/queries.js +1368 -2403
  134. package/dist/psql/describe/versionGate.js +32 -41
  135. package/dist/psql/index.js +2 -2030
  136. package/dist/psql/io/history.js +232 -271
  137. package/dist/psql/io/input.js +103 -108
  138. package/dist/psql/io/lineEditor/buffer.js +238 -319
  139. package/dist/psql/io/lineEditor/complete.js +135 -213
  140. package/dist/psql/io/lineEditor/filename.js +139 -148
  141. package/dist/psql/io/lineEditor/index.js +653 -870
  142. package/dist/psql/io/lineEditor/keymap.js +544 -702
  143. package/dist/psql/io/lineEditor/vt100.js +294 -341
  144. package/dist/psql/io/pgpass.js +158 -187
  145. package/dist/psql/io/pgservice.js +146 -183
  146. package/dist/psql/io/psqlrc.js +328 -403
  147. package/dist/psql/print/aligned.js +1020 -1683
  148. package/dist/psql/print/asciidoc.js +180 -214
  149. package/dist/psql/print/crosstab.js +281 -442
  150. package/dist/psql/print/csv.js +48 -70
  151. package/dist/psql/print/html.js +195 -226
  152. package/dist/psql/print/json.js +75 -88
  153. package/dist/psql/print/latex.js +291 -364
  154. package/dist/psql/print/pager.js +171 -242
  155. package/dist/psql/print/troff.js +194 -226
  156. package/dist/psql/print/unaligned.js +69 -95
  157. package/dist/psql/print/units.js +167 -169
  158. package/dist/psql/scanner/slash.js +428 -483
  159. package/dist/psql/scanner/sql.js +445 -889
  160. package/dist/psql/scanner/stringutils.js +309 -379
  161. package/dist/psql/types/index.js +8 -7
  162. package/dist/psql/types/scanner.js +25 -22
  163. package/dist/psql/wire/connection.js +2042 -2803
  164. package/dist/psql/wire/copy.js +84 -100
  165. package/dist/psql/wire/notify.js +39 -59
  166. package/dist/psql/wire/pipeline.js +305 -518
  167. package/dist/psql/wire/protocol.js +349 -417
  168. package/dist/psql/wire/sasl.js +180 -265
  169. package/dist/psql/wire/tls.js +400 -561
  170. package/dist/storage_api.js +115 -129
  171. package/dist/test_utils/fixtures.js +94 -113
  172. package/dist/test_utils/oauth_server.js +10 -7
  173. package/dist/test_utils/project_dir.js +33 -0
  174. package/dist/utils/ai_gateway_notice.js +131 -162
  175. package/dist/utils/api_enums.js +21 -28
  176. package/dist/utils/auth.js +10 -4
  177. package/dist/utils/branch_notice.js +20 -19
  178. package/dist/utils/branch_picker.js +83 -89
  179. package/dist/utils/cli_name.js +15 -12
  180. package/dist/utils/compute_units.js +20 -27
  181. package/dist/utils/config_diff.js +127 -158
  182. package/dist/utils/enrichers.js +95 -148
  183. package/dist/utils/esbuild.js +130 -189
  184. package/dist/utils/flags.js +35 -47
  185. package/dist/utils/formats.js +8 -15
  186. package/dist/utils/git_diff.js +69 -80
  187. package/dist/utils/inspect_db.js +101 -143
  188. package/dist/utils/inspect_queries.js +179 -142
  189. package/dist/utils/middlewares.js +39 -45
  190. package/dist/utils/openapi.js +87 -99
  191. package/dist/utils/package_manager.js +312 -110
  192. package/dist/utils/point_in_time.js +49 -53
  193. package/dist/utils/psql.js +89 -106
  194. package/dist/utils/service_picker.js +55 -58
  195. package/dist/utils/string.js +5 -5
  196. package/dist/utils/ui.js +38 -55
  197. package/dist/utils/write_sync.js +26 -35
  198. package/dist/utils/zip.js +4 -3
  199. package/dist/writer.js +67 -87
  200. package/package.json +11 -6
  201. package/dist/_shared/auth_selection.js +0 -86
  202. package/dist/_shared/credentials.js +0 -209
  203. package/dist/_shared/env-core/env.js +0 -558
  204. package/dist/_shared/env-core/reuse-secrets.js +0 -223
  205. package/dist/_shared/paths.js +0 -148
  206. package/dist/_shared/profiles.js +0 -276
  207. package/dist/_shared/secure_file.js +0 -43
@@ -1,227 +1,149 @@
1
- /**
2
- * Tab-completion plumbing for the line editor.
3
- *
4
- * Holds the small bit of state that lives between consecutive Tab presses
5
- * (last completion result, cycle index, last-tab timestamp). The renderer
6
- * calls `apply` on each Tab; the function mutates the buffer in place and
7
- * returns a `CompletionStep` telling the driver whether to ring the bell,
8
- * insert text, or list candidates below the prompt.
9
- *
10
- * State machine:
11
- *
12
- * - First Tab: ask the completer. If 0 candidates → `bell`. If 1, insert
13
- * it. If >1, insert the common prefix (if any) and remember the result.
14
- * - Second Tab within DOUBLE_TAP_MS: emit a `list` action so the driver
15
- * prints the candidates below the prompt.
16
- * - Third Tab and onward: cycle through candidates. The previously
17
- * inserted candidate is removed before inserting the next.
18
- *
19
- * Any non-Tab keystroke (handled by the keymap) calls `reset()` to drop
20
- * the completion state.
21
- */
1
+ //#region src/psql/io/lineEditor/complete.ts
22
2
  /** Threshold for "second Tab" detection. Roughly 500ms by spec. */
23
3
  const DOUBLE_TAP_MS = 500;
24
- export class CompletionState {
25
- constructor() {
26
- /** Most recent completion result. Reset to null after non-Tab input. */
27
- this.result = null;
28
- /** When the previous tab fired. */
29
- this.lastTapAt = 0;
30
- /** How many tabs in a row (the first tab inserts prefix; second lists). */
31
- this.tabCount = 0;
32
- /**
33
- * When cycling, the index of the candidate currently inserted in the
34
- * buffer. -1 means "no candidate inserted yet (common prefix only)".
35
- */
36
- this.cycleIndex = -1;
37
- /** Length (in code points) of the candidate currently inserted. */
38
- this.cycleLen = 0;
39
- }
40
- reset() {
41
- this.result = null;
42
- this.tabCount = 0;
43
- this.cycleIndex = -1;
44
- this.cycleLen = 0;
45
- this.lastTapAt = 0;
46
- }
47
- /**
48
- * Index of the candidate currently inserted in the buffer, or `-1` if no
49
- * specific candidate is active (e.g. the user has only seen the common
50
- * prefix). Used by the listing renderer to reverse-video the active
51
- * candidate while cycling.
52
- */
53
- getCycleIndex() {
54
- return this.cycleIndex;
55
- }
56
- /** Snapshot of the candidate list, for re-rendering during a cycle. */
57
- getCandidates() {
58
- return this.result?.candidates ?? [];
59
- }
60
- async apply(buffer, completer, now = Date.now()) {
61
- const elapsed = now - this.lastTapAt;
62
- this.lastTapAt = now;
63
- if (this.result === null || elapsed > DOUBLE_TAP_MS * 4) {
64
- // Fresh start: ask the completer.
65
- const res = await Promise.resolve(completer(buffer.text, buffer.cursor));
66
- this.result = res;
67
- this.tabCount = 1;
68
- this.cycleIndex = -1;
69
- this.cycleLen = 0;
70
- if (res.candidates.length === 0)
71
- return { kind: "bell" };
72
- if (res.candidates.length === 1) {
73
- // Mirror upstream readline: a unique completion gets a trailing space
74
- // (rl_completion_append_character defaults to ' ') unless the result
75
- // explicitly suppresses it (e.g. schema prefix `public.` that the user
76
- // is expected to continue typing through) or the candidate itself
77
- // already ends in a punctuator that shouldn't be followed by a space.
78
- const cand = res.candidates[0];
79
- const text = shouldAppendSpace(cand, res) ? cand + " " : cand;
80
- replaceBeforeCursor(buffer, res.replaceLength, text);
81
- this.reset();
82
- return { kind: "inserted" };
83
- }
84
- // Multiple candidates: insert the common prefix when it differs from
85
- // what's currently in the buffer at that position. The diff can be
86
- // length (more chars to insert) OR case (COMP_KEYWORD_CASE flipping
87
- // `CO` to `co`) — both should redraw with the canonical form so the
88
- // user sees what they'd commit on the next keystroke.
89
- const before = buffer.text.slice(buffer.cursor - res.replaceLength, buffer.cursor);
90
- if (res.commonPrefix !== before) {
91
- replaceBeforeCursor(buffer, res.replaceLength, res.commonPrefix);
92
- }
93
- // Update the "what's currently inserted" to the common prefix length
94
- // so the cycle path knows how many code points to overwrite when it
95
- // swaps in the next candidate.
96
- this.cycleLen = countCodePoints(res.commonPrefix);
97
- return { kind: "inserted" };
98
- }
99
- // We already have a result, and the second Tab arrived in time.
100
- this.tabCount++;
101
- if (this.tabCount === 2 && elapsed <= DOUBLE_TAP_MS) {
102
- // List the candidates.
103
- return { kind: "list", candidates: this.result.candidates.slice() };
104
- }
105
- // Third or later: cycle.
106
- const cands = this.result.candidates;
107
- this.cycleIndex = (this.cycleIndex + 1) % cands.length;
108
- const cand = cands[this.cycleIndex];
109
- replaceBeforeCursor(buffer, this.cycleLen, cand);
110
- this.cycleLen = countCodePoints(cand);
111
- return { kind: "cycled", candidate: cand };
112
- }
113
- }
4
+ var CompletionState = class {
5
+ constructor() {
6
+ this.result = null;
7
+ this.lastTapAt = 0;
8
+ this.tabCount = 0;
9
+ this.cycleIndex = -1;
10
+ this.cycleLen = 0;
11
+ }
12
+ reset() {
13
+ this.result = null;
14
+ this.tabCount = 0;
15
+ this.cycleIndex = -1;
16
+ this.cycleLen = 0;
17
+ this.lastTapAt = 0;
18
+ }
19
+ /**
20
+ * Index of the candidate currently inserted in the buffer, or `-1` if no
21
+ * specific candidate is active (e.g. the user has only seen the common
22
+ * prefix). Used by the listing renderer to reverse-video the active
23
+ * candidate while cycling.
24
+ */
25
+ getCycleIndex() {
26
+ return this.cycleIndex;
27
+ }
28
+ /** Snapshot of the candidate list, for re-rendering during a cycle. */
29
+ getCandidates() {
30
+ return this.result?.candidates ?? [];
31
+ }
32
+ async apply(buffer, completer, now = Date.now()) {
33
+ const elapsed = now - this.lastTapAt;
34
+ this.lastTapAt = now;
35
+ if (this.result === null || elapsed > DOUBLE_TAP_MS * 4) {
36
+ const res = await Promise.resolve(completer(buffer.text, buffer.cursor));
37
+ this.result = res;
38
+ this.tabCount = 1;
39
+ this.cycleIndex = -1;
40
+ this.cycleLen = 0;
41
+ if (res.candidates.length === 0) return { kind: "bell" };
42
+ if (res.candidates.length === 1) {
43
+ const cand = res.candidates[0];
44
+ const text = shouldAppendSpace(cand, res) ? cand + " " : cand;
45
+ replaceBeforeCursor(buffer, res.replaceLength, text);
46
+ this.reset();
47
+ return { kind: "inserted" };
48
+ }
49
+ const before = buffer.text.slice(buffer.cursor - res.replaceLength, buffer.cursor);
50
+ if (res.commonPrefix !== before) replaceBeforeCursor(buffer, res.replaceLength, res.commonPrefix);
51
+ this.cycleLen = countCodePoints(res.commonPrefix);
52
+ return { kind: "inserted" };
53
+ }
54
+ this.tabCount++;
55
+ if (this.tabCount === 2 && elapsed <= DOUBLE_TAP_MS) return {
56
+ kind: "list",
57
+ candidates: this.result.candidates.slice()
58
+ };
59
+ const cands = this.result.candidates;
60
+ this.cycleIndex = (this.cycleIndex + 1) % cands.length;
61
+ const cand = cands[this.cycleIndex];
62
+ replaceBeforeCursor(buffer, this.cycleLen, cand);
63
+ this.cycleLen = countCodePoints(cand);
64
+ return {
65
+ kind: "cycled",
66
+ candidate: cand
67
+ };
68
+ }
69
+ };
114
70
  /**
115
- * Replace `replaceLen` code points before cursor with `text`. The buffer
116
- * loses an undo entry per call; that's intentional so Ctrl-_ can undo a
117
- * mistaken completion.
118
- */
71
+ * Replace `replaceLen` code points before cursor with `text`. The buffer
72
+ * loses an undo entry per call; that's intentional so Ctrl-_ can undo a
73
+ * mistaken completion.
74
+ */
119
75
  const replaceBeforeCursor = (buffer, replaceLen, text) => {
120
- // Move left over the bytes we're replacing, delete them, then insert.
121
- for (let i = 0; i < replaceLen; i++)
122
- buffer.deleteLeft();
123
- buffer.insert(text);
76
+ for (let i = 0; i < replaceLen; i++) buffer.deleteLeft();
77
+ buffer.insert(text);
124
78
  };
125
79
  const countCodePoints = (s) => Array.from(s).length;
126
80
  /**
127
- * Decide whether to append a trailing space after a unique completion.
128
- * Mirrors upstream readline's `rl_completion_append_character` convention:
129
- * default is `' '`, but psql clears it for partial completions the user
130
- * is expected to continue typing (schema prefix, open-quoted identifier,
131
- * directory path).
132
- *
133
- * Rules:
134
- * - If the result explicitly sets `suppressTrailingSpace: true`, don't.
135
- * - Candidates already ending in whitespace are left untouched.
136
- * - Candidates ending in `.`, `/`, `(` are "in progress" (schema
137
- * namespace, path component, function open-paren) — no space.
138
- * - Candidates ending in `'` or `"` get a space only when quote count
139
- * is BALANCED (closed string / closed quoted identifier). An odd
140
- * count means the user is still inside the quoted region.
141
- * - Everything else gets a space.
142
- */
81
+ * Decide whether to append a trailing space after a unique completion.
82
+ * Mirrors upstream readline's `rl_completion_append_character` convention:
83
+ * default is `' '`, but psql clears it for partial completions the user
84
+ * is expected to continue typing (schema prefix, open-quoted identifier,
85
+ * directory path).
86
+ *
87
+ * Rules:
88
+ * - If the result explicitly sets `suppressTrailingSpace: true`, don't.
89
+ * - Candidates already ending in whitespace are left untouched.
90
+ * - Candidates ending in `.`, `/`, `(` are "in progress" (schema
91
+ * namespace, path component, function open-paren) — no space.
92
+ * - Candidates ending in `'` or `"` get a space only when quote count
93
+ * is BALANCED (closed string / closed quoted identifier). An odd
94
+ * count means the user is still inside the quoted region.
95
+ * - Everything else gets a space.
96
+ */
143
97
  const shouldAppendSpace = (candidate, result) => {
144
- if (result.suppressTrailingSpace === true)
145
- return false;
146
- if (candidate.length === 0)
147
- return false;
148
- const last = candidate[candidate.length - 1];
149
- if (last === " " || last === "\t" || last === "\n")
150
- return false;
151
- if (last === "." || last === "/" || last === "(")
152
- return false;
153
- if (last === '"') {
154
- // Even count means quotes are balanced (e.g. `"mixedName"`) — completed
155
- // identifier, append a space. Odd count means we're still inside an
156
- // open quote (e.g. `"foo`) — leave the user to type more.
157
- const count = countChar(candidate, '"');
158
- return count % 2 === 0;
159
- }
160
- if (last === "'") {
161
- const count = countChar(candidate, "'");
162
- return count % 2 === 0;
163
- }
164
- return true;
98
+ if (result.suppressTrailingSpace === true) return false;
99
+ if (candidate.length === 0) return false;
100
+ const last = candidate[candidate.length - 1];
101
+ if (last === " " || last === " " || last === "\n") return false;
102
+ if (last === "." || last === "/" || last === "(") return false;
103
+ if (last === "\"") return countChar(candidate, "\"") % 2 === 0;
104
+ if (last === "'") return countChar(candidate, "'") % 2 === 0;
105
+ return true;
165
106
  };
166
107
  const countChar = (s, ch) => {
167
- let n = 0;
168
- for (const c of s)
169
- if (c === ch)
170
- n++;
171
- return n;
108
+ let n = 0;
109
+ for (const c of s) if (c === ch) n++;
110
+ return n;
172
111
  };
173
- // ---------------------------------------------------------------------------
174
- // Listing helper: format candidates in column layout for display.
175
- // ---------------------------------------------------------------------------
176
112
  /** ANSI reverse-video escape (SGR 7) used to mark the active candidate. */
177
- const SGR_REVERSE = "\x1b[7m";
178
- const SGR_NO_REVERSE = "\x1b[27m";
113
+ const SGR_REVERSE = "\x1B[7m";
114
+ const SGR_NO_REVERSE = "\x1B[27m";
179
115
  /**
180
- * Lay out candidates into a multi-column block. Returns the formatted
181
- * string (without a trailing newline — caller decides). Columns are sized
182
- * to fit `termWidth`; we use the longest candidate plus a 2-space gutter.
183
- *
184
- * Falls back to one-per-line if `termWidth` is too narrow.
185
- *
186
- * If `highlightIndex` is provided and points to a valid candidate, that
187
- * candidate is wrapped in `\x1b[7m...\x1b[27m` (reverse video) so the user
188
- * can see which entry is currently inserted in the line during a Tab cycle.
189
- * Out-of-range indices are silently ignored.
190
- */
191
- export const formatCandidates = (candidates, termWidth, highlightIndex) => {
192
- if (candidates.length === 0)
193
- return "";
194
- const maxLen = candidates.reduce((m, c) => Math.max(m, c.length), 0);
195
- const colWidth = maxLen + 2;
196
- const cols = Math.max(1, Math.floor(termWidth / colWidth));
197
- const rows = Math.ceil(candidates.length / cols);
198
- const hl = highlightIndex !== undefined &&
199
- highlightIndex >= 0 &&
200
- highlightIndex < candidates.length
201
- ? highlightIndex
202
- : -1;
203
- const lines = [];
204
- for (let r = 0; r < rows; r++) {
205
- const parts = [];
206
- for (let c = 0; c < cols; c++) {
207
- const idx = r * cols + c;
208
- if (idx >= candidates.length)
209
- break;
210
- const cand = candidates[idx];
211
- const padded = cand + " ".repeat(colWidth - cand.length);
212
- if (idx === hl) {
213
- // Wrap only the candidate text, not the gutter spaces, so adjacent
214
- // columns don't get a colored stripe between them.
215
- parts.push(SGR_REVERSE +
216
- cand +
217
- SGR_NO_REVERSE +
218
- " ".repeat(colWidth - cand.length));
219
- }
220
- else {
221
- parts.push(padded);
222
- }
223
- }
224
- lines.push(parts.join("").trimEnd());
225
- }
226
- return lines.join("\n");
116
+ * Lay out candidates into a multi-column block. Returns the formatted
117
+ * string (without a trailing newline — caller decides). Columns are sized
118
+ * to fit `termWidth`; we use the longest candidate plus a 2-space gutter.
119
+ *
120
+ * Falls back to one-per-line if `termWidth` is too narrow.
121
+ *
122
+ * If `highlightIndex` is provided and points to a valid candidate, that
123
+ * candidate is wrapped in `\x1b[7m...\x1b[27m` (reverse video) so the user
124
+ * can see which entry is currently inserted in the line during a Tab cycle.
125
+ * Out-of-range indices are silently ignored.
126
+ */
127
+ const formatCandidates = (candidates, termWidth, highlightIndex) => {
128
+ if (candidates.length === 0) return "";
129
+ const colWidth = candidates.reduce((m, c) => Math.max(m, c.length), 0) + 2;
130
+ const cols = Math.max(1, Math.floor(termWidth / colWidth));
131
+ const rows = Math.ceil(candidates.length / cols);
132
+ const hl = highlightIndex !== void 0 && highlightIndex >= 0 && highlightIndex < candidates.length ? highlightIndex : -1;
133
+ const lines = [];
134
+ for (let r = 0; r < rows; r++) {
135
+ const parts = [];
136
+ for (let c = 0; c < cols; c++) {
137
+ const idx = r * cols + c;
138
+ if (idx >= candidates.length) break;
139
+ const cand = candidates[idx];
140
+ const padded = cand + " ".repeat(colWidth - cand.length);
141
+ if (idx === hl) parts.push(SGR_REVERSE + cand + SGR_NO_REVERSE + " ".repeat(colWidth - cand.length));
142
+ else parts.push(padded);
143
+ }
144
+ lines.push(parts.join("").trimEnd());
145
+ }
146
+ return lines.join("\n");
227
147
  };
148
+ //#endregion
149
+ export { CompletionState, formatCandidates };