neon 2.47.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/_shared/auth_selection.js +76 -79
- package/dist/_shared/credentials.js +166 -187
- package/dist/_shared/env-core/env.js +395 -0
- package/dist/_shared/env-core/reuse-secrets.js +179 -0
- package/dist/_shared/paths.js +129 -126
- package/dist/_shared/profiles.js +192 -242
- package/dist/_shared/secure_file.js +36 -38
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/analytics.js +163 -207
- package/dist/api.js +815 -758
- package/dist/auth.js +121 -141
- package/dist/auth_context.js +39 -53
- package/dist/cli.js +4 -7
- package/dist/commands/api.js +220 -250
- package/dist/commands/api_keys.js +251 -314
- package/dist/commands/auth.js +283 -328
- package/dist/commands/bootstrap.js +372 -437
- package/dist/commands/branches.js +304 -455
- package/dist/commands/bucket.js +374 -514
- package/dist/commands/checkout.js +213 -298
- package/dist/commands/config.js +575 -658
- package/dist/commands/connection_string.js +137 -165
- package/dist/commands/data_api.js +238 -260
- package/dist/commands/databases.js +67 -76
- package/dist/commands/deploy.js +31 -25
- package/dist/commands/dev.js +642 -681
- package/dist/commands/diff.js +156 -200
- package/dist/commands/env.js +243 -303
- package/dist/commands/functions.js +275 -341
- package/dist/commands/index.js +70 -65
- package/dist/commands/init.js +84 -119
- package/dist/commands/inspect.js +55 -55
- package/dist/commands/ip_allow.js +88 -120
- package/dist/commands/link.js +874 -1019
- package/dist/commands/logs.js +291 -0
- package/dist/commands/neon_auth.js +725 -933
- package/dist/commands/operations.js +34 -25
- package/dist/commands/orgs.js +28 -18
- package/dist/commands/profile.js +614 -845
- package/dist/commands/projects.js +313 -373
- package/dist/commands/psql.js +60 -58
- package/dist/commands/roles.js +55 -58
- package/dist/commands/schema_diff.js +87 -131
- package/dist/commands/set_context.js +34 -26
- package/dist/commands/snapshots.js +288 -413
- package/dist/commands/status.js +41 -37
- package/dist/commands/user.js +21 -10
- package/dist/commands/vpc_endpoints.js +85 -113
- package/dist/config.js +7 -6
- package/dist/config_format.js +50 -66
- package/dist/config_template.js +128 -157
- package/dist/context.js +183 -235
- package/dist/current_branch_fast_path.js +40 -49
- package/dist/dev/env.js +313 -394
- package/dist/dev/functions.js +54 -64
- package/dist/dev/inputs.js +46 -58
- package/dist/dev/runtime.js +135 -164
- package/dist/dev/websocket.js +766 -959
- package/dist/env.js +27 -33
- package/dist/env_file.js +118 -132
- package/dist/env_services.js +36 -38
- package/dist/errors.js +57 -68
- package/dist/functions_api.js +45 -43
- package/dist/help.js +189 -140
- package/dist/index.js +182 -257
- package/dist/init/agents.js +137 -118
- package/dist/init/auth.js +58 -68
- package/dist/init/bootstrap.js +325 -396
- package/dist/init/build_config.js +4 -2
- package/dist/init/detect_agent.js +56 -101
- package/dist/init/editors.js +35 -52
- package/dist/init/enrich_output.js +51 -66
- package/dist/init/extension.js +134 -171
- package/dist/init/inspect.js +179 -266
- package/dist/init/interactive.js +510 -622
- package/dist/init/neonctl.js +117 -168
- package/dist/init/orchestrate.js +157 -173
- package/dist/init/phases/auth.js +188 -202
- package/dist/init/phases/cleanup.js +23 -23
- package/dist/init/phases/db.js +251 -277
- package/dist/init/phases/getting_started.js +213 -223
- package/dist/init/phases/mcp.js +174 -224
- package/dist/init/phases/migrations.js +247 -248
- package/dist/init/phases/neon_auth.js +114 -133
- package/dist/init/phases/setup.js +546 -703
- package/dist/init/phases/skills.js +75 -86
- package/dist/init/phases/status.js +72 -67
- package/dist/init/resolve_context.js +102 -99
- package/dist/init/route_command.js +91 -98
- package/dist/init/skills.js +174 -218
- package/dist/init/vsix.js +77 -99
- package/dist/log.js +17 -16
- package/dist/neon_services.js +104 -129
- package/dist/parameters.gen.js +481 -471
- package/dist/pkg.js +17 -19
- package/dist/profile_keys.js +44 -47
- package/dist/psql/cli.js +44 -47
- package/dist/psql/command/cmd_cond.js +231 -406
- package/dist/psql/command/cmd_connect.js +557 -764
- package/dist/psql/command/cmd_copy.js +727 -983
- package/dist/psql/command/cmd_describe.js +1499 -1688
- package/dist/psql/command/cmd_format.js +733 -905
- package/dist/psql/command/cmd_io.js +1293 -2082
- package/dist/psql/command/cmd_lo.js +297 -359
- package/dist/psql/command/cmd_meta.js +727 -878
- package/dist/psql/command/cmd_misc.js +138 -172
- package/dist/psql/command/cmd_pipeline.js +547 -1099
- package/dist/psql/command/cmd_restrict.js +119 -155
- package/dist/psql/command/cmd_show.js +529 -688
- package/dist/psql/command/dispatch.js +261 -325
- package/dist/psql/command/inputQueue.js +35 -33
- package/dist/psql/command/shared.js +49 -63
- package/dist/psql/complete/filenames.js +90 -133
- package/dist/psql/complete/index.js +59 -97
- package/dist/psql/complete/matcher.js +236 -300
- package/dist/psql/complete/psqlVars.js +218 -223
- package/dist/psql/complete/queries.js +159 -177
- package/dist/psql/complete/rules.js +1493 -2299
- package/dist/psql/core/common.js +762 -1180
- package/dist/psql/core/help.js +456 -546
- package/dist/psql/core/mainloop.js +692 -1302
- package/dist/psql/core/prompt.js +391 -408
- package/dist/psql/core/settings.js +429 -644
- package/dist/psql/core/sqlHelp.js +480 -554
- package/dist/psql/core/startup.js +626 -815
- package/dist/psql/core/syncVars.js +67 -110
- package/dist/psql/core/variables.js +156 -278
- package/dist/psql/describe/formatters.js +884 -1285
- package/dist/psql/describe/processNamePattern.js +173 -260
- package/dist/psql/describe/queries.js +1368 -2403
- package/dist/psql/describe/versionGate.js +32 -41
- package/dist/psql/index.js +1414 -1927
- package/dist/psql/io/history.js +232 -271
- package/dist/psql/io/input.js +103 -108
- package/dist/psql/io/lineEditor/buffer.js +238 -319
- package/dist/psql/io/lineEditor/complete.js +135 -213
- package/dist/psql/io/lineEditor/filename.js +139 -148
- package/dist/psql/io/lineEditor/index.js +653 -870
- package/dist/psql/io/lineEditor/keymap.js +544 -702
- package/dist/psql/io/lineEditor/vt100.js +294 -341
- package/dist/psql/io/pgpass.js +158 -187
- package/dist/psql/io/pgservice.js +146 -183
- package/dist/psql/io/psqlrc.js +328 -403
- package/dist/psql/print/aligned.js +1020 -1683
- package/dist/psql/print/asciidoc.js +180 -214
- package/dist/psql/print/crosstab.js +281 -442
- package/dist/psql/print/csv.js +48 -70
- package/dist/psql/print/html.js +195 -226
- package/dist/psql/print/json.js +75 -88
- package/dist/psql/print/latex.js +291 -364
- package/dist/psql/print/pager.js +171 -242
- package/dist/psql/print/troff.js +194 -226
- package/dist/psql/print/unaligned.js +69 -95
- package/dist/psql/print/units.js +167 -169
- package/dist/psql/scanner/slash.js +428 -483
- package/dist/psql/scanner/sql.js +445 -889
- package/dist/psql/scanner/stringutils.js +309 -379
- package/dist/psql/types/index.js +2 -7
- package/dist/psql/types/scanner.js +25 -22
- package/dist/psql/wire/connection.js +2042 -2803
- package/dist/psql/wire/copy.js +84 -100
- package/dist/psql/wire/notify.js +39 -59
- package/dist/psql/wire/pipeline.js +305 -518
- package/dist/psql/wire/protocol.js +349 -417
- package/dist/psql/wire/sasl.js +180 -265
- package/dist/psql/wire/tls.js +400 -561
- package/dist/storage_api.js +115 -129
- package/dist/test_utils/fixtures.js +94 -113
- package/dist/test_utils/oauth_server.js +10 -7
- package/dist/test_utils/project_dir.js +33 -0
- package/dist/utils/ai_gateway_notice.js +131 -162
- package/dist/utils/api_enums.js +21 -28
- package/dist/utils/auth.js +10 -4
- package/dist/utils/branch_notice.js +20 -19
- package/dist/utils/branch_picker.js +83 -89
- package/dist/utils/cli_name.js +15 -12
- package/dist/utils/compute_units.js +20 -27
- package/dist/utils/config_diff.js +127 -158
- package/dist/utils/enrichers.js +95 -148
- package/dist/utils/esbuild.js +133 -147
- package/dist/utils/flags.js +35 -47
- package/dist/utils/formats.js +8 -15
- package/dist/utils/git_diff.js +69 -80
- package/dist/utils/inspect_db.js +101 -143
- package/dist/utils/inspect_queries.js +179 -142
- package/dist/utils/middlewares.js +37 -44
- package/dist/utils/openapi.js +87 -99
- package/dist/utils/package_manager.js +312 -110
- package/dist/utils/point_in_time.js +49 -53
- package/dist/utils/psql.js +89 -106
- package/dist/utils/service_picker.js +55 -58
- package/dist/utils/string.js +5 -5
- package/dist/utils/ui.js +38 -55
- package/dist/utils/write_sync.js +26 -35
- package/dist/utils/zip.js +4 -3
- package/dist/writer.js +67 -87
- package/package.json +9 -7
|
@@ -1,325 +1,244 @@
|
|
|
1
|
+
//#region src/psql/io/lineEditor/buffer.ts
|
|
1
2
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* exposes insert/delete-at-cursor primitives so callers stay code-point
|
|
8
|
-
* aware rather than byte aware.
|
|
9
|
-
*
|
|
10
|
-
* Everything in this module operates on Unicode *code points*. Internally
|
|
11
|
-
* we store the line as an array of code-point strings (each element is one
|
|
12
|
-
* scalar value, typically one UTF-16 code unit but two for astral chars).
|
|
13
|
-
* The `cursor` is an index into that array, in the range `[0, length]`.
|
|
14
|
-
*
|
|
15
|
-
* Editing primitives mutate the state in place and push the previous
|
|
16
|
-
* snapshot onto the undo stack. Killed text (^K, ^U, ^W) is appended to
|
|
17
|
-
* the most recent kill ring entry when killing continues in the same
|
|
18
|
-
* direction; yank pulls from the most recent entry.
|
|
19
|
-
*
|
|
20
|
-
* No I/O, no rendering, no terminal awareness — that lives in
|
|
21
|
-
* `keymap.ts` / `index.ts`. Tests cover this module exhaustively.
|
|
22
|
-
*/
|
|
23
|
-
/**
|
|
24
|
-
* Encode a string as an array of code-point characters. Each element is
|
|
25
|
-
* one Unicode scalar (`"A"`, `"é"`, `"\u{1F600}"`). This lets cursor
|
|
26
|
-
* arithmetic stay code-point-aligned without dealing with surrogate pairs
|
|
27
|
-
* at every callsite.
|
|
28
|
-
*/
|
|
3
|
+
* Encode a string as an array of code-point characters. Each element is
|
|
4
|
+
* one Unicode scalar (`"A"`, `"é"`, `"\u{1F600}"`). This lets cursor
|
|
5
|
+
* arithmetic stay code-point-aligned without dealing with surrogate pairs
|
|
6
|
+
* at every callsite.
|
|
7
|
+
*/
|
|
29
8
|
const toCodePoints = (s) => Array.from(s);
|
|
30
9
|
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// -------------------------------------------------------------------------
|
|
250
|
-
// Undo
|
|
251
|
-
// -------------------------------------------------------------------------
|
|
252
|
-
/** Push the current state onto the undo stack. */
|
|
253
|
-
pushUndo() {
|
|
254
|
-
this.undoStack.push({ text: this.text, cursor: this._cursor });
|
|
255
|
-
if (this.undoStack.length > LineBuffer.UNDO_STACK_MAX) {
|
|
256
|
-
this.undoStack.shift();
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
/** ^_: pop the most recent snapshot. Returns true if anything happened. */
|
|
260
|
-
undo() {
|
|
261
|
-
const snap = this.undoStack.pop();
|
|
262
|
-
if (!snap)
|
|
263
|
-
return false;
|
|
264
|
-
this.chars = toCodePoints(snap.text);
|
|
265
|
-
this._cursor = this.clampCursor(snap.cursor);
|
|
266
|
-
this.lastKill = "none";
|
|
267
|
-
return true;
|
|
268
|
-
}
|
|
269
|
-
// -------------------------------------------------------------------------
|
|
270
|
-
// Internals
|
|
271
|
-
// -------------------------------------------------------------------------
|
|
272
|
-
clampCursor(c) {
|
|
273
|
-
if (c < 0)
|
|
274
|
-
return 0;
|
|
275
|
-
if (c > this.chars.length)
|
|
276
|
-
return this.chars.length;
|
|
277
|
-
return c;
|
|
278
|
-
}
|
|
279
|
-
recordKill(text, dir) {
|
|
280
|
-
if (text.length === 0)
|
|
281
|
-
return;
|
|
282
|
-
if (this.lastKill === dir && this.killRing.length > 0) {
|
|
283
|
-
// Merge with the previous kill so consecutive ^K / ^W feel like one
|
|
284
|
-
// logical kill in the yank ring.
|
|
285
|
-
this.killRing[0] =
|
|
286
|
-
dir === "forward"
|
|
287
|
-
? this.killRing[0] + text
|
|
288
|
-
: text + this.killRing[0];
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
this.killRing.unshift(text);
|
|
292
|
-
if (this.killRing.length > LineBuffer.KILL_RING_MAX) {
|
|
293
|
-
this.killRing.length = LineBuffer.KILL_RING_MAX;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
this.lastKill = dir;
|
|
297
|
-
this.yankIndex = -1;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
LineBuffer.KILL_RING_MAX = 32;
|
|
301
|
-
LineBuffer.UNDO_STACK_MAX = 256;
|
|
10
|
+
* Pure line buffer plus kill ring plus undo. Used by the keymap layer.
|
|
11
|
+
*/
|
|
12
|
+
var LineBuffer = class LineBuffer {
|
|
13
|
+
static {
|
|
14
|
+
this.KILL_RING_MAX = 32;
|
|
15
|
+
}
|
|
16
|
+
static {
|
|
17
|
+
this.UNDO_STACK_MAX = 256;
|
|
18
|
+
}
|
|
19
|
+
constructor(initial = "", cursor) {
|
|
20
|
+
this.chars = [];
|
|
21
|
+
this._cursor = 0;
|
|
22
|
+
this.killRing = [];
|
|
23
|
+
this.yankIndex = -1;
|
|
24
|
+
this.lastKill = "none";
|
|
25
|
+
this.undoStack = [];
|
|
26
|
+
this.chars = toCodePoints(initial);
|
|
27
|
+
this._cursor = cursor === void 0 ? this.chars.length : this.clampCursor(cursor);
|
|
28
|
+
}
|
|
29
|
+
get text() {
|
|
30
|
+
return this.chars.join("");
|
|
31
|
+
}
|
|
32
|
+
get cursor() {
|
|
33
|
+
return this._cursor;
|
|
34
|
+
}
|
|
35
|
+
get length() {
|
|
36
|
+
return this.chars.length;
|
|
37
|
+
}
|
|
38
|
+
snapshot() {
|
|
39
|
+
return {
|
|
40
|
+
text: this.text,
|
|
41
|
+
cursor: this._cursor
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
restore(snap) {
|
|
45
|
+
this.chars = toCodePoints(snap.text);
|
|
46
|
+
this._cursor = this.clampCursor(snap.cursor);
|
|
47
|
+
this.lastKill = "none";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Replace the entire buffer in one go. Used when navigating history or
|
|
51
|
+
* accepting a completion. Does NOT push an undo entry on its own — call
|
|
52
|
+
* `pushUndo()` first if you want to record the previous state.
|
|
53
|
+
*/
|
|
54
|
+
setText(text, cursor) {
|
|
55
|
+
this.chars = toCodePoints(text);
|
|
56
|
+
this._cursor = cursor === void 0 ? this.chars.length : this.clampCursor(cursor);
|
|
57
|
+
this.lastKill = "none";
|
|
58
|
+
}
|
|
59
|
+
moveLeft() {
|
|
60
|
+
if (this._cursor > 0) this._cursor--;
|
|
61
|
+
this.lastKill = "none";
|
|
62
|
+
}
|
|
63
|
+
moveRight() {
|
|
64
|
+
if (this._cursor < this.chars.length) this._cursor++;
|
|
65
|
+
this.lastKill = "none";
|
|
66
|
+
}
|
|
67
|
+
moveHome() {
|
|
68
|
+
this._cursor = 0;
|
|
69
|
+
this.lastKill = "none";
|
|
70
|
+
}
|
|
71
|
+
moveEnd() {
|
|
72
|
+
this._cursor = this.chars.length;
|
|
73
|
+
this.lastKill = "none";
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Move left over one word. Word ≙ run of alphanumerics. Skip the
|
|
77
|
+
* non-alphanumerics immediately to the left first (matches readline's
|
|
78
|
+
* `M-b`). Pure stdlib `\w` is locale-sensitive in some runtimes; we
|
|
79
|
+
* use a `RegExp` against the actual code-point string.
|
|
80
|
+
*/
|
|
81
|
+
moveWordLeft() {
|
|
82
|
+
let i = this._cursor;
|
|
83
|
+
while (i > 0 && !isWordChar(this.chars[i - 1])) i--;
|
|
84
|
+
while (i > 0 && isWordChar(this.chars[i - 1])) i--;
|
|
85
|
+
this._cursor = i;
|
|
86
|
+
this.lastKill = "none";
|
|
87
|
+
}
|
|
88
|
+
moveWordRight() {
|
|
89
|
+
let i = this._cursor;
|
|
90
|
+
while (i < this.chars.length && !isWordChar(this.chars[i])) i++;
|
|
91
|
+
while (i < this.chars.length && isWordChar(this.chars[i])) i++;
|
|
92
|
+
this._cursor = i;
|
|
93
|
+
this.lastKill = "none";
|
|
94
|
+
}
|
|
95
|
+
/** Insert a string at the cursor (split into code points first). */
|
|
96
|
+
insert(s) {
|
|
97
|
+
if (s.length === 0) return;
|
|
98
|
+
this.pushUndo();
|
|
99
|
+
const cps = toCodePoints(s);
|
|
100
|
+
this.chars.splice(this._cursor, 0, ...cps);
|
|
101
|
+
this._cursor += cps.length;
|
|
102
|
+
this.lastKill = "none";
|
|
103
|
+
}
|
|
104
|
+
/** Backspace: delete the code point to the left of cursor. */
|
|
105
|
+
deleteLeft() {
|
|
106
|
+
if (this._cursor === 0) return;
|
|
107
|
+
this.pushUndo();
|
|
108
|
+
this.chars.splice(this._cursor - 1, 1);
|
|
109
|
+
this._cursor--;
|
|
110
|
+
this.lastKill = "none";
|
|
111
|
+
}
|
|
112
|
+
/** Delete the code point to the right of cursor. */
|
|
113
|
+
deleteRight() {
|
|
114
|
+
if (this._cursor === this.chars.length) return;
|
|
115
|
+
this.pushUndo();
|
|
116
|
+
this.chars.splice(this._cursor, 1);
|
|
117
|
+
this.lastKill = "none";
|
|
118
|
+
}
|
|
119
|
+
/** ^K: kill from cursor to end-of-line. Appends if previous kill was forward. */
|
|
120
|
+
killToEnd() {
|
|
121
|
+
if (this._cursor === this.chars.length) return;
|
|
122
|
+
this.pushUndo();
|
|
123
|
+
const killed = this.chars.slice(this._cursor).join("");
|
|
124
|
+
this.chars.length = this._cursor;
|
|
125
|
+
this.recordKill(killed, "forward");
|
|
126
|
+
}
|
|
127
|
+
/** ^U: kill from start-of-line to cursor. */
|
|
128
|
+
killToStart() {
|
|
129
|
+
if (this._cursor === 0) return;
|
|
130
|
+
this.pushUndo();
|
|
131
|
+
const killed = this.chars.slice(0, this._cursor).join("");
|
|
132
|
+
this.chars.splice(0, this._cursor);
|
|
133
|
+
this._cursor = 0;
|
|
134
|
+
this.recordKill(killed, "backward");
|
|
135
|
+
}
|
|
136
|
+
/** ^W: kill the word (backward) to the left of cursor. */
|
|
137
|
+
killWordLeft() {
|
|
138
|
+
if (this._cursor === 0) return;
|
|
139
|
+
let i = this._cursor;
|
|
140
|
+
while (i > 0 && !isWordChar(this.chars[i - 1])) i--;
|
|
141
|
+
while (i > 0 && isWordChar(this.chars[i - 1])) i--;
|
|
142
|
+
if (i === this._cursor) return;
|
|
143
|
+
this.pushUndo();
|
|
144
|
+
const killed = this.chars.slice(i, this._cursor).join("");
|
|
145
|
+
this.chars.splice(i, this._cursor - i);
|
|
146
|
+
this._cursor = i;
|
|
147
|
+
this.recordKill(killed, "backward");
|
|
148
|
+
}
|
|
149
|
+
/** M-d: kill the word (forward) starting at cursor. */
|
|
150
|
+
killWordRight() {
|
|
151
|
+
if (this._cursor === this.chars.length) return;
|
|
152
|
+
let i = this._cursor;
|
|
153
|
+
while (i < this.chars.length && !isWordChar(this.chars[i])) i++;
|
|
154
|
+
while (i < this.chars.length && isWordChar(this.chars[i])) i++;
|
|
155
|
+
if (i === this._cursor) return;
|
|
156
|
+
this.pushUndo();
|
|
157
|
+
const killed = this.chars.slice(this._cursor, i).join("");
|
|
158
|
+
this.chars.splice(this._cursor, i - this._cursor);
|
|
159
|
+
this.recordKill(killed, "forward");
|
|
160
|
+
}
|
|
161
|
+
/** ^Y: yank most recent kill at cursor. No-op if ring is empty. */
|
|
162
|
+
yank() {
|
|
163
|
+
if (this.killRing.length === 0) return void 0;
|
|
164
|
+
const top = this.killRing[0];
|
|
165
|
+
this.insert(top);
|
|
166
|
+
this.yankIndex = 0;
|
|
167
|
+
return top;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* M-y: rotate yank ring. Caller must have just yanked. Removes the
|
|
171
|
+
* previously yanked text and inserts the next entry from the ring.
|
|
172
|
+
*/
|
|
173
|
+
yankPop(prevYank) {
|
|
174
|
+
if (this.killRing.length === 0) return void 0;
|
|
175
|
+
this.yankIndex = (this.yankIndex + 1) % this.killRing.length;
|
|
176
|
+
if (this._cursor < prevYank.length) return void 0;
|
|
177
|
+
const start = this._cursor - toCodePoints(prevYank).length;
|
|
178
|
+
this.pushUndo();
|
|
179
|
+
this.chars.splice(start, toCodePoints(prevYank).length);
|
|
180
|
+
this._cursor = start;
|
|
181
|
+
const next = this.killRing[this.yankIndex];
|
|
182
|
+
const cps = toCodePoints(next);
|
|
183
|
+
this.chars.splice(this._cursor, 0, ...cps);
|
|
184
|
+
this._cursor += cps.length;
|
|
185
|
+
return next;
|
|
186
|
+
}
|
|
187
|
+
/** Reset the kill-merge tracker. Called when a non-kill action runs. */
|
|
188
|
+
resetKillTracking() {
|
|
189
|
+
this.lastKill = "none";
|
|
190
|
+
}
|
|
191
|
+
/** Test helper / introspection. */
|
|
192
|
+
getKillRing() {
|
|
193
|
+
return this.killRing;
|
|
194
|
+
}
|
|
195
|
+
/** Push the current state onto the undo stack. */
|
|
196
|
+
pushUndo() {
|
|
197
|
+
this.undoStack.push({
|
|
198
|
+
text: this.text,
|
|
199
|
+
cursor: this._cursor
|
|
200
|
+
});
|
|
201
|
+
if (this.undoStack.length > LineBuffer.UNDO_STACK_MAX) this.undoStack.shift();
|
|
202
|
+
}
|
|
203
|
+
/** ^_: pop the most recent snapshot. Returns true if anything happened. */
|
|
204
|
+
undo() {
|
|
205
|
+
const snap = this.undoStack.pop();
|
|
206
|
+
if (!snap) return false;
|
|
207
|
+
this.chars = toCodePoints(snap.text);
|
|
208
|
+
this._cursor = this.clampCursor(snap.cursor);
|
|
209
|
+
this.lastKill = "none";
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
clampCursor(c) {
|
|
213
|
+
if (c < 0) return 0;
|
|
214
|
+
if (c > this.chars.length) return this.chars.length;
|
|
215
|
+
return c;
|
|
216
|
+
}
|
|
217
|
+
recordKill(text, dir) {
|
|
218
|
+
if (text.length === 0) return;
|
|
219
|
+
if (this.lastKill === dir && this.killRing.length > 0) this.killRing[0] = dir === "forward" ? this.killRing[0] + text : text + this.killRing[0];
|
|
220
|
+
else {
|
|
221
|
+
this.killRing.unshift(text);
|
|
222
|
+
if (this.killRing.length > LineBuffer.KILL_RING_MAX) this.killRing.length = LineBuffer.KILL_RING_MAX;
|
|
223
|
+
}
|
|
224
|
+
this.lastKill = dir;
|
|
225
|
+
this.yankIndex = -1;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
302
228
|
/**
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
229
|
+
* Word character classifier. Matches readline's default: ASCII alphanumeric
|
|
230
|
+
* plus underscore. Non-ASCII letters are treated as word chars too so
|
|
231
|
+
* "señor" moves as one word.
|
|
232
|
+
*/
|
|
307
233
|
const isWordChar = (ch) => {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return true; // a-z
|
|
317
|
-
if (cp === 0x5f)
|
|
318
|
-
return true; // _
|
|
319
|
-
if (cp > 0x7f) {
|
|
320
|
-
// Treat any non-ASCII printable as word-ish; cheap heuristic but
|
|
321
|
-
// sufficient for editor word motion.
|
|
322
|
-
return cp >= 0xa0;
|
|
323
|
-
}
|
|
324
|
-
return false;
|
|
234
|
+
if (ch.length === 0) return false;
|
|
235
|
+
const cp = ch.codePointAt(0) ?? 0;
|
|
236
|
+
if (cp >= 48 && cp <= 57) return true;
|
|
237
|
+
if (cp >= 65 && cp <= 90) return true;
|
|
238
|
+
if (cp >= 97 && cp <= 122) return true;
|
|
239
|
+
if (cp === 95) return true;
|
|
240
|
+
if (cp > 127) return cp >= 160;
|
|
241
|
+
return false;
|
|
325
242
|
};
|
|
243
|
+
//#endregion
|
|
244
|
+
export { LineBuffer };
|