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.
- package/README.md +35 -3
- package/dist/analytics.js +52 -34
- package/dist/api.js +643 -13
- package/dist/auth.js +50 -44
- package/dist/cli.js +8 -1
- package/dist/commands/auth.js +64 -51
- package/dist/commands/bootstrap.js +115 -157
- package/dist/commands/branches.js +160 -150
- package/dist/commands/bucket.js +183 -146
- package/dist/commands/checkout.js +51 -51
- package/dist/commands/config.js +228 -82
- package/dist/commands/connection_string.js +62 -62
- package/dist/commands/data_api.js +100 -101
- package/dist/commands/databases.js +29 -26
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/dev.js +114 -114
- package/dist/commands/env.js +43 -43
- package/dist/commands/functions.js +101 -104
- package/dist/commands/index.js +27 -25
- package/dist/commands/init.js +23 -22
- package/dist/commands/ip_allow.js +29 -29
- package/dist/commands/link.js +232 -182
- package/dist/commands/neon_auth.js +385 -370
- package/dist/commands/operations.js +11 -11
- package/dist/commands/orgs.js +8 -8
- package/dist/commands/projects.js +103 -101
- package/dist/commands/psql.js +31 -31
- package/dist/commands/roles.js +27 -24
- package/dist/commands/schema_diff.js +25 -26
- package/dist/commands/set_context.js +17 -17
- package/dist/commands/status.js +40 -0
- package/dist/commands/user.js +5 -5
- package/dist/commands/vpc_endpoints.js +50 -50
- package/dist/config.js +7 -7
- package/dist/config_format.js +5 -5
- package/dist/context.js +37 -14
- package/dist/current_branch_fast_path.js +55 -0
- package/dist/dev/env.js +33 -33
- package/dist/dev/functions.js +4 -4
- package/dist/dev/inputs.js +6 -6
- package/dist/dev/runtime.js +25 -25
- package/dist/env.js +14 -14
- package/dist/env_file.js +13 -13
- package/dist/errors.js +68 -5
- package/dist/functions_api.js +10 -10
- package/dist/help.js +15 -15
- package/dist/index.js +110 -107
- package/dist/log.js +2 -2
- package/dist/parameters.gen.js +14 -14
- package/dist/pkg.js +5 -5
- package/dist/psql/cli.js +4 -2
- package/dist/psql/command/cmd_cond.js +61 -61
- package/dist/psql/command/cmd_connect.js +159 -154
- package/dist/psql/command/cmd_copy.js +107 -97
- package/dist/psql/command/cmd_describe.js +368 -363
- package/dist/psql/command/cmd_format.js +276 -263
- package/dist/psql/command/cmd_io.js +269 -263
- package/dist/psql/command/cmd_lo.js +74 -66
- package/dist/psql/command/cmd_meta.js +148 -148
- package/dist/psql/command/cmd_misc.js +17 -17
- package/dist/psql/command/cmd_pipeline.js +142 -135
- package/dist/psql/command/cmd_restrict.js +25 -25
- package/dist/psql/command/cmd_show.js +183 -168
- package/dist/psql/command/dispatch.js +26 -26
- package/dist/psql/command/shared.js +14 -14
- package/dist/psql/complete/filenames.js +16 -16
- package/dist/psql/complete/index.js +4 -4
- package/dist/psql/complete/matcher.js +33 -32
- package/dist/psql/complete/psqlVars.js +173 -173
- package/dist/psql/complete/queries.js +5 -3
- package/dist/psql/complete/rules.js +900 -863
- package/dist/psql/core/common.js +136 -133
- package/dist/psql/core/help.js +343 -343
- package/dist/psql/core/mainloop.js +160 -153
- package/dist/psql/core/prompt.js +126 -123
- package/dist/psql/core/settings.js +111 -111
- package/dist/psql/core/sqlHelp.js +150 -150
- package/dist/psql/core/startup.js +211 -205
- package/dist/psql/core/syncVars.js +14 -14
- package/dist/psql/core/variables.js +24 -24
- package/dist/psql/describe/formatters.js +302 -289
- package/dist/psql/describe/processNamePattern.js +28 -28
- package/dist/psql/describe/queries.js +656 -651
- package/dist/psql/index.js +436 -411
- package/dist/psql/io/history.js +36 -36
- package/dist/psql/io/input.js +15 -15
- package/dist/psql/io/lineEditor/buffer.js +27 -25
- package/dist/psql/io/lineEditor/complete.js +15 -15
- package/dist/psql/io/lineEditor/filename.js +22 -22
- package/dist/psql/io/lineEditor/index.js +65 -62
- package/dist/psql/io/lineEditor/keymap.js +325 -318
- package/dist/psql/io/lineEditor/vt100.js +60 -60
- package/dist/psql/io/pgpass.js +18 -18
- package/dist/psql/io/pgservice.js +14 -14
- package/dist/psql/io/psqlrc.js +46 -46
- package/dist/psql/print/aligned.js +175 -166
- package/dist/psql/print/asciidoc.js +51 -51
- package/dist/psql/print/crosstab.js +34 -31
- package/dist/psql/print/csv.js +25 -22
- package/dist/psql/print/html.js +54 -54
- package/dist/psql/print/json.js +12 -12
- package/dist/psql/print/latex.js +118 -118
- package/dist/psql/print/pager.js +28 -26
- package/dist/psql/print/troff.js +48 -48
- package/dist/psql/print/unaligned.js +15 -14
- package/dist/psql/print/units.js +17 -17
- package/dist/psql/scanner/slash.js +48 -46
- package/dist/psql/scanner/sql.js +88 -84
- package/dist/psql/scanner/stringutils.js +21 -17
- package/dist/psql/types/index.js +7 -7
- package/dist/psql/types/scanner.js +8 -8
- package/dist/psql/wire/connection.js +341 -327
- package/dist/psql/wire/copy.js +7 -7
- package/dist/psql/wire/pipeline.js +26 -24
- package/dist/psql/wire/protocol.js +102 -102
- package/dist/psql/wire/sasl.js +62 -62
- package/dist/psql/wire/tls.js +79 -73
- package/dist/storage_api.js +22 -23
- package/dist/test_utils/fixtures.js +74 -41
- package/dist/test_utils/oauth_server.js +5 -5
- package/dist/utils/api_enums.js +33 -0
- package/dist/utils/branch_notice.js +5 -5
- package/dist/utils/branch_picker.js +26 -26
- package/dist/utils/compute_units.js +4 -4
- package/dist/utils/enrichers.js +28 -16
- package/dist/utils/esbuild.js +28 -28
- package/dist/utils/formats.js +1 -1
- package/dist/utils/middlewares.js +3 -3
- package/dist/utils/package_manager.js +68 -0
- package/dist/utils/point_in_time.js +12 -12
- package/dist/utils/psql.js +30 -30
- package/dist/utils/string.js +2 -2
- package/dist/utils/ui.js +9 -9
- package/dist/utils/zip.js +1 -1
- package/dist/writer.js +17 -17
- package/package.json +10 -12
|
@@ -22,20 +22,20 @@
|
|
|
22
22
|
* mirror that exactly, writing to stderr and returning
|
|
23
23
|
* `{ status: 'error' }`.
|
|
24
24
|
*/
|
|
25
|
-
import { scanSlashArgs } from
|
|
26
|
-
import {
|
|
25
|
+
import { scanSlashArgs } from "../scanner/slash.js";
|
|
26
|
+
import { parseBool, parseTriple, writeErr, writeOut } from "./shared.js";
|
|
27
27
|
/** Recognised output-format names accepted by `\pset format`. */
|
|
28
28
|
const OUTPUT_FORMATS = [
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
"aligned",
|
|
30
|
+
"unaligned",
|
|
31
|
+
"wrapped",
|
|
32
|
+
"html",
|
|
33
|
+
"asciidoc",
|
|
34
|
+
"latex",
|
|
35
|
+
"latex-longtable",
|
|
36
|
+
"troff-ms",
|
|
37
|
+
"csv",
|
|
38
|
+
"json",
|
|
39
39
|
];
|
|
40
40
|
/** Convert OutputFormat to its human-readable display string. */
|
|
41
41
|
const formatName = (f) => f;
|
|
@@ -46,7 +46,7 @@ const formatName = (f) => f;
|
|
|
46
46
|
* off → "Expanded display is off."
|
|
47
47
|
* auto → "Expanded display is used automatically."
|
|
48
48
|
*/
|
|
49
|
-
const tripleLabel = (value) => value ===
|
|
49
|
+
const tripleLabel = (value) => value === "auto" ? "used automatically" : value;
|
|
50
50
|
/**
|
|
51
51
|
* `\a` — toggle aligned/unaligned.
|
|
52
52
|
*
|
|
@@ -56,15 +56,15 @@ const tripleLabel = (value) => value === 'auto' ? 'used automatically' : value;
|
|
|
56
56
|
* that here, gating the status write on QUIET like the sibling toggles.
|
|
57
57
|
*/
|
|
58
58
|
export const cmdA = {
|
|
59
|
-
name:
|
|
60
|
-
helpKey:
|
|
59
|
+
name: "a",
|
|
60
|
+
helpKey: "a",
|
|
61
61
|
run: (ctx) => {
|
|
62
62
|
const topt = ctx.settings.popt.topt;
|
|
63
|
-
topt.format = topt.format ===
|
|
63
|
+
topt.format = topt.format === "aligned" ? "unaligned" : "aligned";
|
|
64
64
|
if (!ctx.settings.quiet) {
|
|
65
65
|
writeOut(`Output format is ${formatName(topt.format)}.\n`);
|
|
66
66
|
}
|
|
67
|
-
return Promise.resolve({ status:
|
|
67
|
+
return Promise.resolve({ status: "ok" });
|
|
68
68
|
},
|
|
69
69
|
};
|
|
70
70
|
/**
|
|
@@ -75,11 +75,11 @@ export const cmdA = {
|
|
|
75
75
|
* `printPsetInfo`.
|
|
76
76
|
*/
|
|
77
77
|
export const cmdC = {
|
|
78
|
-
name:
|
|
79
|
-
helpKey:
|
|
78
|
+
name: "C",
|
|
79
|
+
helpKey: "C",
|
|
80
80
|
run: (ctx) => {
|
|
81
|
-
const arg = ctx.nextArg(
|
|
82
|
-
return Promise.resolve(applyPset(ctx.settings.popt.topt,
|
|
81
|
+
const arg = ctx.nextArg("normal");
|
|
82
|
+
return Promise.resolve(applyPset(ctx.settings.popt.topt, "title", arg, ctx.cmdName, ctx.settings.quiet));
|
|
83
83
|
},
|
|
84
84
|
};
|
|
85
85
|
/**
|
|
@@ -87,13 +87,13 @@ export const cmdC = {
|
|
|
87
87
|
* print the current value (upstream prints `Field separator is "%s".`).
|
|
88
88
|
*/
|
|
89
89
|
export const cmdF = {
|
|
90
|
-
name:
|
|
91
|
-
helpKey:
|
|
90
|
+
name: "f",
|
|
91
|
+
helpKey: "f",
|
|
92
92
|
run: (ctx) => {
|
|
93
|
-
const arg = ctx.nextArg(
|
|
93
|
+
const arg = ctx.nextArg("normal");
|
|
94
94
|
if (arg === null) {
|
|
95
95
|
writeOut(`Field separator is "${ctx.settings.popt.topt.fieldSep}".\n`);
|
|
96
|
-
return Promise.resolve({ status:
|
|
96
|
+
return Promise.resolve({ status: "ok" });
|
|
97
97
|
}
|
|
98
98
|
ctx.settings.popt.topt.fieldSep = arg;
|
|
99
99
|
// Upstream confirms the change (quiet-gated), like the other \pset-style
|
|
@@ -101,7 +101,7 @@ export const cmdF = {
|
|
|
101
101
|
if (!ctx.settings.quiet) {
|
|
102
102
|
writeOut(`Field separator is "${arg}".\n`);
|
|
103
103
|
}
|
|
104
|
-
return Promise.resolve({ status:
|
|
104
|
+
return Promise.resolve({ status: "ok" });
|
|
105
105
|
},
|
|
106
106
|
};
|
|
107
107
|
/**
|
|
@@ -110,12 +110,12 @@ export const cmdF = {
|
|
|
110
110
|
* loosely — we always restore `aligned` to match the documented behaviour).
|
|
111
111
|
*/
|
|
112
112
|
export const cmdH = {
|
|
113
|
-
name:
|
|
114
|
-
helpKey:
|
|
113
|
+
name: "H",
|
|
114
|
+
helpKey: "H",
|
|
115
115
|
run: (ctx) => {
|
|
116
116
|
const topt = ctx.settings.popt.topt;
|
|
117
|
-
topt.format = topt.format ===
|
|
118
|
-
return Promise.resolve({ status:
|
|
117
|
+
topt.format = topt.format === "html" ? "aligned" : "html";
|
|
118
|
+
return Promise.resolve({ status: "ok" });
|
|
119
119
|
},
|
|
120
120
|
};
|
|
121
121
|
/**
|
|
@@ -129,11 +129,11 @@ export const cmdH = {
|
|
|
129
129
|
* `printPsetInfo`, so the status line is suppressed.
|
|
130
130
|
*/
|
|
131
131
|
export const cmdT = {
|
|
132
|
-
name:
|
|
133
|
-
helpKey:
|
|
132
|
+
name: "t",
|
|
133
|
+
helpKey: "t",
|
|
134
134
|
run: (ctx) => {
|
|
135
|
-
const arg = ctx.nextArg(
|
|
136
|
-
return Promise.resolve(applyPset(ctx.settings.popt.topt,
|
|
135
|
+
const arg = ctx.nextArg("normal");
|
|
136
|
+
return Promise.resolve(applyPset(ctx.settings.popt.topt, "tuples_only", arg, ctx.cmdName, ctx.settings.quiet));
|
|
137
137
|
},
|
|
138
138
|
};
|
|
139
139
|
/**
|
|
@@ -144,32 +144,32 @@ export const cmdT = {
|
|
|
144
144
|
* by `printPsetInfo`.
|
|
145
145
|
*/
|
|
146
146
|
export const cmdTitleAttr = {
|
|
147
|
-
name:
|
|
148
|
-
helpKey:
|
|
147
|
+
name: "T",
|
|
148
|
+
helpKey: "T",
|
|
149
149
|
run: (ctx) => {
|
|
150
|
-
const arg = ctx.nextArg(
|
|
151
|
-
return Promise.resolve(applyPset(ctx.settings.popt.topt,
|
|
150
|
+
const arg = ctx.nextArg("normal");
|
|
151
|
+
return Promise.resolve(applyPset(ctx.settings.popt.topt, "tableattr", arg, ctx.cmdName, ctx.settings.quiet));
|
|
152
152
|
},
|
|
153
153
|
};
|
|
154
154
|
/** `\x [on|off|auto|toggle]` — expanded output. No arg → toggle. */
|
|
155
155
|
export const cmdX = {
|
|
156
|
-
name:
|
|
157
|
-
helpKey:
|
|
156
|
+
name: "x",
|
|
157
|
+
helpKey: "x",
|
|
158
158
|
run: (ctx) => {
|
|
159
|
-
const arg = ctx.nextArg(
|
|
159
|
+
const arg = ctx.nextArg("normal");
|
|
160
160
|
const topt = ctx.settings.popt.topt;
|
|
161
161
|
let next;
|
|
162
162
|
if (arg === null) {
|
|
163
|
-
next = topt.expanded ===
|
|
163
|
+
next = topt.expanded === "on" ? "off" : "on";
|
|
164
164
|
}
|
|
165
165
|
else {
|
|
166
166
|
const parsed = parseTriple(arg);
|
|
167
167
|
if (parsed === null) {
|
|
168
168
|
writeErr(`\\${ctx.cmdName}: unrecognized value "${arg}": Boolean expected\n`);
|
|
169
|
-
return Promise.resolve({ status:
|
|
169
|
+
return Promise.resolve({ status: "error", errorWritten: true });
|
|
170
170
|
}
|
|
171
|
-
if (parsed ===
|
|
172
|
-
next = topt.expanded ===
|
|
171
|
+
if (parsed === "toggle") {
|
|
172
|
+
next = topt.expanded === "on" ? "off" : "on";
|
|
173
173
|
}
|
|
174
174
|
else {
|
|
175
175
|
next = parsed;
|
|
@@ -177,7 +177,7 @@ export const cmdX = {
|
|
|
177
177
|
}
|
|
178
178
|
topt.expanded = next;
|
|
179
179
|
writeOut(`Expanded display is ${tripleLabel(next)}.\n`);
|
|
180
|
-
return Promise.resolve({ status:
|
|
180
|
+
return Promise.resolve({ status: "ok" });
|
|
181
181
|
},
|
|
182
182
|
};
|
|
183
183
|
/**
|
|
@@ -190,62 +190,62 @@ export const cmdX = {
|
|
|
190
190
|
* server reject genuinely unusable ones.
|
|
191
191
|
*/
|
|
192
192
|
const NORMALISED_ENCODINGS = new Set([
|
|
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
|
-
|
|
193
|
+
"sqlascii",
|
|
194
|
+
"eucjp",
|
|
195
|
+
"euccn",
|
|
196
|
+
"euckr",
|
|
197
|
+
"euctw",
|
|
198
|
+
"eucjis2004",
|
|
199
|
+
"utf8",
|
|
200
|
+
"muleinternal",
|
|
201
|
+
"latin1",
|
|
202
|
+
"latin2",
|
|
203
|
+
"latin3",
|
|
204
|
+
"latin4",
|
|
205
|
+
"latin5",
|
|
206
|
+
"latin6",
|
|
207
|
+
"latin7",
|
|
208
|
+
"latin8",
|
|
209
|
+
"latin9",
|
|
210
|
+
"latin10",
|
|
211
|
+
"win1256",
|
|
212
|
+
"win1258",
|
|
213
|
+
"win866",
|
|
214
|
+
"win874",
|
|
215
|
+
"koi8r",
|
|
216
|
+
"win1251",
|
|
217
|
+
"win1252",
|
|
218
|
+
"iso88595",
|
|
219
|
+
"iso88596",
|
|
220
|
+
"iso88597",
|
|
221
|
+
"iso88598",
|
|
222
|
+
"win1250",
|
|
223
|
+
"win1253",
|
|
224
|
+
"win1254",
|
|
225
|
+
"win1255",
|
|
226
|
+
"win1257",
|
|
227
|
+
"koi8u",
|
|
228
|
+
"sjis",
|
|
229
|
+
"big5",
|
|
230
|
+
"gbk",
|
|
231
|
+
"uhc",
|
|
232
|
+
"gb18030",
|
|
233
|
+
"johab",
|
|
234
|
+
"shiftjis2004",
|
|
235
235
|
// Aliases upstream's encoding_match_list accepts as recognised names.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
236
|
+
"unicode", // → UTF8
|
|
237
|
+
"mskanji", // → SJIS
|
|
238
|
+
"shiftjis", // → SJIS
|
|
239
|
+
"windows949", // → UHC
|
|
240
|
+
"windows950", // → BIG5
|
|
241
|
+
"windows936", // → GBK
|
|
242
|
+
"tcvn", // → WIN1258
|
|
243
|
+
"tcvn5712", // → WIN1258
|
|
244
|
+
"vscii", // → WIN1258
|
|
245
|
+
"alt", // → WIN866
|
|
246
|
+
"win", // → WIN1251
|
|
247
|
+
"koi8", // → KOI8R
|
|
248
|
+
"abc", // → WIN1258
|
|
249
249
|
]);
|
|
250
250
|
/**
|
|
251
251
|
* Mirror upstream `pg_char_to_encoding`'s name normalisation: drop every
|
|
@@ -253,7 +253,7 @@ const NORMALISED_ENCODINGS = new Set([
|
|
|
253
253
|
* Used to reproduce `\encoding`'s `invalid encoding name` guard without a
|
|
254
254
|
* server round-trip.
|
|
255
255
|
*/
|
|
256
|
-
const isValidEncodingName = (name) => NORMALISED_ENCODINGS.has(name.replace(/[-_]/g,
|
|
256
|
+
const isValidEncodingName = (name) => NORMALISED_ENCODINGS.has(name.replace(/[-_]/g, "").toLowerCase());
|
|
257
257
|
/**
|
|
258
258
|
* `\encoding [name]` — show or set the client encoding.
|
|
259
259
|
*
|
|
@@ -266,19 +266,19 @@ const isValidEncodingName = (name) => NORMALISED_ENCODINGS.has(name.replace(/[-_
|
|
|
266
266
|
* mirror it into `topt.encoding` so prompts/printer see the new value.
|
|
267
267
|
*/
|
|
268
268
|
export const cmdEncoding = {
|
|
269
|
-
name:
|
|
270
|
-
helpKey:
|
|
269
|
+
name: "encoding",
|
|
270
|
+
helpKey: "encoding",
|
|
271
271
|
run: async (ctx) => {
|
|
272
|
-
const arg = ctx.nextArg(
|
|
272
|
+
const arg = ctx.nextArg("normal");
|
|
273
273
|
if (arg === null) {
|
|
274
274
|
writeOut(`${ctx.settings.popt.topt.encoding}\n`);
|
|
275
|
-
return { status:
|
|
275
|
+
return { status: "ok" };
|
|
276
276
|
}
|
|
277
277
|
if (!isValidEncodingName(arg)) {
|
|
278
278
|
// Upstream `do_encoding` reports the rejected name verbatim and leaves
|
|
279
279
|
// the current encoding in place.
|
|
280
280
|
writeErr(`\\${ctx.cmdName}: invalid encoding name "${arg}"\n`);
|
|
281
|
-
return { status:
|
|
281
|
+
return { status: "error", errorWritten: true };
|
|
282
282
|
}
|
|
283
283
|
const { db } = ctx.settings;
|
|
284
284
|
// `PgConnection` always implements setClientEncoding; the optional call
|
|
@@ -294,11 +294,11 @@ export const cmdEncoding = {
|
|
|
294
294
|
// upstream's "leave the encoding as it was on failure" behaviour.
|
|
295
295
|
const msg = err instanceof Error ? err.message : String(err);
|
|
296
296
|
writeErr(`\\${ctx.cmdName}: ${msg}\n`);
|
|
297
|
-
return { status:
|
|
297
|
+
return { status: "error", errorWritten: true };
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
ctx.settings.popt.topt.encoding = arg;
|
|
301
|
-
return { status:
|
|
301
|
+
return { status: "ok" };
|
|
302
302
|
},
|
|
303
303
|
};
|
|
304
304
|
/**
|
|
@@ -335,10 +335,10 @@ silent = false) => {
|
|
|
335
335
|
const writeOutMaybe = silent ? () => undefined : writeOut;
|
|
336
336
|
const opt = option.toLowerCase();
|
|
337
337
|
switch (opt) {
|
|
338
|
-
case
|
|
338
|
+
case "format": {
|
|
339
339
|
if (value === null) {
|
|
340
340
|
writeOutMaybe(`Output format is ${formatName(topt.format)}.\n`);
|
|
341
|
-
return { status:
|
|
341
|
+
return { status: "ok" };
|
|
342
342
|
}
|
|
343
343
|
const v = value.toLowerCase();
|
|
344
344
|
// Upstream `do_pset` accepts unambiguous prefix matches for the
|
|
@@ -352,69 +352,73 @@ silent = false) => {
|
|
|
352
352
|
// with `v` (the order in OUTPUT_FORMATS — `latex` before
|
|
353
353
|
// `latex-longtable` etc. — encodes which canonical name wins
|
|
354
354
|
// when one is a prefix of another).
|
|
355
|
-
const startsWithBoth =
|
|
355
|
+
const startsWithBoth = "aligned".startsWith(v) && "asciidoc".startsWith(v);
|
|
356
356
|
if (startsWithBoth) {
|
|
357
357
|
writeErr(`\\pset: ambiguous abbreviation "${value}" matches both "aligned" and "asciidoc"\n`);
|
|
358
|
-
return { status:
|
|
358
|
+
return { status: "error", errorWritten: true };
|
|
359
359
|
}
|
|
360
360
|
const match = OUTPUT_FORMATS.find((f) => f.startsWith(v));
|
|
361
361
|
if (!match) {
|
|
362
362
|
writeErr(`\\pset: allowed formats are aligned, asciidoc, csv, html, json, latex, latex-longtable, troff-ms, unaligned, wrapped\n`);
|
|
363
|
-
return { status:
|
|
363
|
+
return { status: "error", errorWritten: true };
|
|
364
364
|
}
|
|
365
365
|
topt.format = match;
|
|
366
366
|
writeOutMaybe(`Output format is ${formatName(match)}.\n`);
|
|
367
|
-
return { status:
|
|
367
|
+
return { status: "ok" };
|
|
368
368
|
}
|
|
369
|
-
case
|
|
369
|
+
case "border": {
|
|
370
370
|
if (value === null) {
|
|
371
371
|
writeOutMaybe(`Border style is ${topt.border}.\n`);
|
|
372
|
-
return { status:
|
|
372
|
+
return { status: "ok" };
|
|
373
373
|
}
|
|
374
374
|
const n = parseInt(value, 10);
|
|
375
375
|
if (!Number.isFinite(n) || n < 0 || n > 3) {
|
|
376
376
|
writeErr(`\\pset: invalid border "${value}"\n`);
|
|
377
|
-
return { status:
|
|
377
|
+
return { status: "error", errorWritten: true };
|
|
378
378
|
}
|
|
379
379
|
topt.border = n;
|
|
380
380
|
writeOutMaybe(`Border style is ${topt.border}.\n`);
|
|
381
|
-
return { status:
|
|
381
|
+
return { status: "ok" };
|
|
382
382
|
}
|
|
383
|
-
case
|
|
384
|
-
case
|
|
383
|
+
case "expanded":
|
|
384
|
+
case "x": {
|
|
385
385
|
if (value === null) {
|
|
386
|
-
topt.expanded = topt.expanded ===
|
|
386
|
+
topt.expanded = topt.expanded === "on" ? "off" : "on";
|
|
387
387
|
}
|
|
388
388
|
else {
|
|
389
389
|
const p = parseTriple(value);
|
|
390
390
|
if (p === null) {
|
|
391
391
|
writeErr(`\\pset: unrecognized value "${value}" for "expanded": Boolean expected\n`);
|
|
392
|
-
return { status:
|
|
392
|
+
return { status: "error", errorWritten: true };
|
|
393
393
|
}
|
|
394
394
|
topt.expanded =
|
|
395
|
-
p ===
|
|
395
|
+
p === "toggle"
|
|
396
|
+
? topt.expanded === "on"
|
|
397
|
+
? "off"
|
|
398
|
+
: "on"
|
|
399
|
+
: p;
|
|
396
400
|
}
|
|
397
401
|
writeOutMaybe(`Expanded display is ${tripleLabel(topt.expanded)}.\n`);
|
|
398
|
-
return { status:
|
|
402
|
+
return { status: "ok" };
|
|
399
403
|
}
|
|
400
|
-
case
|
|
404
|
+
case "fieldsep": {
|
|
401
405
|
if (value === null) {
|
|
402
406
|
writeOutMaybe(`Field separator is "${topt.fieldSep}".\n`);
|
|
403
|
-
return { status:
|
|
407
|
+
return { status: "ok" };
|
|
404
408
|
}
|
|
405
409
|
topt.fieldSep = value;
|
|
406
410
|
writeOutMaybe(`Field separator is "${topt.fieldSep}".\n`);
|
|
407
|
-
return { status:
|
|
411
|
+
return { status: "ok" };
|
|
408
412
|
}
|
|
409
|
-
case
|
|
413
|
+
case "fieldsep_zero": {
|
|
410
414
|
// Upstream: any value (or none) forces fieldSep to the NUL byte.
|
|
411
415
|
// The bulk-view's `fieldsep_zero` line is derived from fieldSep
|
|
412
416
|
// (on iff fieldSep === '\0').
|
|
413
|
-
topt.fieldSep =
|
|
414
|
-
writeOutMaybe(
|
|
415
|
-
return { status:
|
|
417
|
+
topt.fieldSep = "\0";
|
|
418
|
+
writeOutMaybe("Field separator is zero byte.\n");
|
|
419
|
+
return { status: "ok" };
|
|
416
420
|
}
|
|
417
|
-
case
|
|
421
|
+
case "footer": {
|
|
418
422
|
if (value !== null) {
|
|
419
423
|
// Upstream `do_pset` returns directly from `ParseVariableBool`
|
|
420
424
|
// for `footer`, bypassing the `printPsetInfo` call entirely
|
|
@@ -423,18 +427,18 @@ silent = false) => {
|
|
|
423
427
|
const b = parseBool(value);
|
|
424
428
|
if (b === null) {
|
|
425
429
|
writeErr(`\\pset: unrecognized value "${value}" for "footer": Boolean expected\n`);
|
|
426
|
-
return { status:
|
|
430
|
+
return { status: "error", errorWritten: true };
|
|
427
431
|
}
|
|
428
432
|
topt.defaultFooter = b;
|
|
429
|
-
return { status:
|
|
433
|
+
return { status: "ok" };
|
|
430
434
|
}
|
|
431
435
|
topt.defaultFooter = !topt.defaultFooter;
|
|
432
436
|
writeOutMaybe(topt.defaultFooter
|
|
433
|
-
?
|
|
434
|
-
:
|
|
435
|
-
return { status:
|
|
437
|
+
? "Default footer is on.\n"
|
|
438
|
+
: "Default footer is off.\n");
|
|
439
|
+
return { status: "ok" };
|
|
436
440
|
}
|
|
437
|
-
case
|
|
441
|
+
case "recordsep": {
|
|
438
442
|
if (value !== null) {
|
|
439
443
|
topt.recordSep = value;
|
|
440
444
|
}
|
|
@@ -442,21 +446,21 @@ silent = false) => {
|
|
|
442
446
|
// path (handled by the dedicated `recordsep_zero` case), the
|
|
443
447
|
// "<newline>" sentinel for the literal `\n` byte, and the quoted
|
|
444
448
|
// verbatim form for everything else.
|
|
445
|
-
if (topt.recordSep ===
|
|
446
|
-
writeOutMaybe(
|
|
449
|
+
if (topt.recordSep === "\n") {
|
|
450
|
+
writeOutMaybe("Record separator is <newline>.\n");
|
|
447
451
|
}
|
|
448
452
|
else {
|
|
449
453
|
writeOutMaybe(`Record separator is "${topt.recordSep}".\n`);
|
|
450
454
|
}
|
|
451
|
-
return { status:
|
|
455
|
+
return { status: "ok" };
|
|
452
456
|
}
|
|
453
|
-
case
|
|
454
|
-
topt.recordSep =
|
|
455
|
-
writeOutMaybe(
|
|
456
|
-
return { status:
|
|
457
|
+
case "recordsep_zero": {
|
|
458
|
+
topt.recordSep = "\0";
|
|
459
|
+
writeOutMaybe("Record separator is zero byte.\n");
|
|
460
|
+
return { status: "ok" };
|
|
457
461
|
}
|
|
458
|
-
case
|
|
459
|
-
case
|
|
462
|
+
case "tuples_only":
|
|
463
|
+
case "t": {
|
|
460
464
|
if (value !== null) {
|
|
461
465
|
// Upstream `do_pset` returns directly from `ParseVariableBool`
|
|
462
466
|
// for `tuples_only`, bypassing `printPsetInfo` — so
|
|
@@ -465,86 +469,88 @@ silent = false) => {
|
|
|
465
469
|
const b = parseBool(value);
|
|
466
470
|
if (b === null) {
|
|
467
471
|
writeErr(`\\pset: unrecognized value "${value}": Boolean expected\n`);
|
|
468
|
-
return { status:
|
|
472
|
+
return { status: "error", errorWritten: true };
|
|
469
473
|
}
|
|
470
474
|
topt.tuplesOnly = b;
|
|
471
|
-
return { status:
|
|
475
|
+
return { status: "ok" };
|
|
472
476
|
}
|
|
473
477
|
topt.tuplesOnly = !topt.tuplesOnly;
|
|
474
|
-
writeOutMaybe(topt.tuplesOnly
|
|
475
|
-
|
|
478
|
+
writeOutMaybe(topt.tuplesOnly
|
|
479
|
+
? "Tuples only is on.\n"
|
|
480
|
+
: "Tuples only is off.\n");
|
|
481
|
+
return { status: "ok" };
|
|
476
482
|
}
|
|
477
|
-
case
|
|
483
|
+
case "title": {
|
|
478
484
|
topt.title = value;
|
|
479
485
|
if (value === null) {
|
|
480
|
-
writeOutMaybe(
|
|
486
|
+
writeOutMaybe("Title is unset.\n");
|
|
481
487
|
}
|
|
482
488
|
else {
|
|
483
489
|
writeOutMaybe(`Title is "${value}".\n`);
|
|
484
490
|
}
|
|
485
|
-
return { status:
|
|
491
|
+
return { status: "ok" };
|
|
486
492
|
}
|
|
487
|
-
case
|
|
488
|
-
case
|
|
493
|
+
case "tableattr":
|
|
494
|
+
case "t_a": {
|
|
489
495
|
topt.tableAttr = value;
|
|
490
496
|
if (value === null) {
|
|
491
|
-
writeOutMaybe(
|
|
497
|
+
writeOutMaybe("Table attributes unset.\n");
|
|
492
498
|
}
|
|
493
499
|
else {
|
|
494
500
|
writeOutMaybe(`Table attributes are "${value}".\n`);
|
|
495
501
|
}
|
|
496
|
-
return { status:
|
|
502
|
+
return { status: "ok" };
|
|
497
503
|
}
|
|
498
|
-
case
|
|
504
|
+
case "pager": {
|
|
499
505
|
if (value === null) {
|
|
500
|
-
topt.pager = topt.pager ===
|
|
506
|
+
topt.pager = topt.pager === "off" ? "on" : "off";
|
|
501
507
|
}
|
|
502
508
|
else {
|
|
503
509
|
const lower = value.toLowerCase();
|
|
504
|
-
if (lower ===
|
|
505
|
-
topt.pager =
|
|
510
|
+
if (lower === "always") {
|
|
511
|
+
topt.pager = "always";
|
|
506
512
|
}
|
|
507
|
-
else if (lower ===
|
|
513
|
+
else if (lower === "on" || lower === "off") {
|
|
508
514
|
topt.pager = lower;
|
|
509
515
|
}
|
|
510
516
|
else {
|
|
511
517
|
const b = parseBool(value);
|
|
512
518
|
if (b === null) {
|
|
513
519
|
writeErr(`\\pset: unrecognized value "${value}" for "pager"\n`);
|
|
514
|
-
return { status:
|
|
520
|
+
return { status: "error", errorWritten: true };
|
|
515
521
|
}
|
|
516
|
-
topt.pager = b ?
|
|
522
|
+
topt.pager = b ? "on" : "off";
|
|
517
523
|
}
|
|
518
524
|
}
|
|
519
|
-
writeOutMaybe(topt.pager ===
|
|
520
|
-
?
|
|
521
|
-
: topt.pager ===
|
|
522
|
-
?
|
|
523
|
-
:
|
|
524
|
-
return { status:
|
|
525
|
+
writeOutMaybe(topt.pager === "always"
|
|
526
|
+
? "Pager is always used.\n"
|
|
527
|
+
: topt.pager === "on"
|
|
528
|
+
? "Pager is used for long output.\n"
|
|
529
|
+
: "Pager usage is off.\n");
|
|
530
|
+
return { status: "ok" };
|
|
525
531
|
}
|
|
526
|
-
case
|
|
532
|
+
case "pager_min_lines": {
|
|
527
533
|
if (value !== null) {
|
|
528
534
|
const n = parseInt(value, 10);
|
|
529
535
|
if (!Number.isFinite(n) || n < 0) {
|
|
530
536
|
writeErr(`\\pset: invalid pager_min_lines "${value}"\n`);
|
|
531
|
-
return { status:
|
|
537
|
+
return { status: "error", errorWritten: true };
|
|
532
538
|
}
|
|
533
539
|
topt.pagerMinLines = n;
|
|
534
540
|
}
|
|
535
541
|
// Upstream uses `ngettext` so singular ("line") fires only for
|
|
536
542
|
// n == 1; 0 and 2+ render as "lines".
|
|
537
543
|
const lines = topt.pagerMinLines;
|
|
538
|
-
const unit = lines === 1 ?
|
|
544
|
+
const unit = lines === 1 ? "line" : "lines";
|
|
539
545
|
writeOutMaybe(`Pager won't be used for less than ${lines} ${unit}.\n`);
|
|
540
|
-
return { status:
|
|
546
|
+
return { status: "ok" };
|
|
541
547
|
}
|
|
542
|
-
case
|
|
543
|
-
topt.nullPrint = value ??
|
|
548
|
+
case "null": {
|
|
549
|
+
topt.nullPrint = value ?? "";
|
|
544
550
|
writeOutMaybe(`Null display is "${topt.nullPrint}".\n`);
|
|
545
|
-
return { status:
|
|
551
|
+
return { status: "ok" };
|
|
546
552
|
}
|
|
547
|
-
case
|
|
553
|
+
case "csv_fieldsep": {
|
|
548
554
|
if (value !== null) {
|
|
549
555
|
// Upstream `do_pset` splits the validation in two: length-based
|
|
550
556
|
// ("must be a single one-byte character") fires for empty / multi-
|
|
@@ -552,43 +558,44 @@ silent = false) => {
|
|
|
552
558
|
// NUL-terminated, so `'\0'` decodes to an empty C string). The
|
|
553
559
|
// "cannot be a double quote, a newline, or a carriage return"
|
|
554
560
|
// path is reserved for the three forbidden single-byte values.
|
|
555
|
-
if (value.length !== 1 || value ===
|
|
561
|
+
if (value.length !== 1 || value === "\0") {
|
|
556
562
|
writeErr(`\\pset: csv_fieldsep must be a single one-byte character\n`);
|
|
557
|
-
return { status:
|
|
563
|
+
return { status: "error", errorWritten: true };
|
|
558
564
|
}
|
|
559
|
-
if (value === '"' || value ===
|
|
565
|
+
if (value === '"' || value === "\n" || value === "\r") {
|
|
560
566
|
writeErr(`\\pset: csv_fieldsep cannot be a double quote, a newline, or a carriage return\n`);
|
|
561
|
-
return { status:
|
|
567
|
+
return { status: "error", errorWritten: true };
|
|
562
568
|
}
|
|
563
569
|
topt.csvFieldSep = value;
|
|
564
570
|
}
|
|
565
571
|
// Upstream wording: "Field separator for CSV is "%s".".
|
|
566
572
|
writeOutMaybe(`Field separator for CSV is "${topt.csvFieldSep}".\n`);
|
|
567
|
-
return { status:
|
|
573
|
+
return { status: "ok" };
|
|
568
574
|
}
|
|
569
|
-
case
|
|
575
|
+
case "numericlocale": {
|
|
570
576
|
if (value !== null) {
|
|
571
577
|
// Upstream `do_pset` returns directly from `ParseVariableBool`
|
|
572
578
|
// for `numericlocale`, bypassing `printPsetInfo`. The toggle
|
|
573
579
|
// path (no value) still prints the new state.
|
|
574
580
|
const p = parseTriple(value);
|
|
575
|
-
if (p === null || p ===
|
|
581
|
+
if (p === null || p === "auto") {
|
|
576
582
|
writeErr(`\\pset: unrecognized value "${value}" for "numericlocale": Boolean expected\n`);
|
|
577
|
-
return { status:
|
|
583
|
+
return { status: "error", errorWritten: true };
|
|
578
584
|
}
|
|
579
|
-
topt.numericLocale =
|
|
580
|
-
|
|
585
|
+
topt.numericLocale =
|
|
586
|
+
p === "toggle" ? !topt.numericLocale : p === "on";
|
|
587
|
+
return { status: "ok" };
|
|
581
588
|
}
|
|
582
589
|
topt.numericLocale = !topt.numericLocale;
|
|
583
590
|
writeOutMaybe(topt.numericLocale
|
|
584
|
-
?
|
|
585
|
-
:
|
|
586
|
-
return { status:
|
|
591
|
+
? "Locale-adjusted numeric output is on.\n"
|
|
592
|
+
: "Locale-adjusted numeric output is off.\n");
|
|
593
|
+
return { status: "ok" };
|
|
587
594
|
}
|
|
588
|
-
case
|
|
595
|
+
case "linestyle": {
|
|
589
596
|
if (value === null) {
|
|
590
597
|
writeOutMaybe(`Line style is ${topt.unicodeBorderLineStyle}.\n`);
|
|
591
|
-
return { status:
|
|
598
|
+
return { status: "ok" };
|
|
592
599
|
}
|
|
593
600
|
const lower = value.toLowerCase();
|
|
594
601
|
// Preserve 'old-ascii' verbatim so the bulk-view (`\pset` with no
|
|
@@ -596,40 +603,44 @@ silent = false) => {
|
|
|
596
603
|
// table. Upstream `do_pset("linestyle", "old-ascii", …)` flips
|
|
597
604
|
// `popt.topt.line_style = &pg_asciiformat_old`; we carry the same
|
|
598
605
|
// three-way distinction on `unicodeBorderLineStyle`.
|
|
599
|
-
if (lower ===
|
|
606
|
+
if (lower === "ascii" ||
|
|
607
|
+
lower === "old-ascii" ||
|
|
608
|
+
lower === "unicode") {
|
|
600
609
|
const ls = lower;
|
|
601
610
|
topt.unicodeBorderLineStyle = ls;
|
|
602
611
|
topt.unicodeColumnLineStyle = ls;
|
|
603
612
|
topt.unicodeHeaderLineStyle = ls;
|
|
604
613
|
writeOutMaybe(`Line style is ${ls}.\n`);
|
|
605
|
-
return { status:
|
|
614
|
+
return { status: "ok" };
|
|
606
615
|
}
|
|
607
616
|
writeErr(`\\pset: allowed line styles are ascii, old-ascii, unicode\n`);
|
|
608
|
-
return { status:
|
|
617
|
+
return { status: "error", errorWritten: true };
|
|
609
618
|
}
|
|
610
|
-
case
|
|
619
|
+
case "columns": {
|
|
611
620
|
if (value !== null) {
|
|
612
621
|
const n = parseInt(value, 10);
|
|
613
622
|
if (!Number.isFinite(n) || n < 0) {
|
|
614
623
|
writeErr(`\\pset: invalid columns "${value}"\n`);
|
|
615
|
-
return { status:
|
|
624
|
+
return { status: "error", errorWritten: true };
|
|
616
625
|
}
|
|
617
626
|
topt.columns = n;
|
|
618
627
|
}
|
|
619
628
|
// Upstream `printPsetInfo` reports `0` as the special "unset"
|
|
620
629
|
// sentinel — see `command.c:5433`.
|
|
621
630
|
if (topt.columns === 0) {
|
|
622
|
-
writeOutMaybe(
|
|
631
|
+
writeOutMaybe("Target width is unset.\n");
|
|
623
632
|
}
|
|
624
633
|
else {
|
|
625
634
|
writeOutMaybe(`Target width is ${topt.columns}.\n`);
|
|
626
635
|
}
|
|
627
|
-
return { status:
|
|
636
|
+
return { status: "ok" };
|
|
628
637
|
}
|
|
629
|
-
case
|
|
638
|
+
case "xheader_width": {
|
|
630
639
|
if (value !== null) {
|
|
631
640
|
const lower = value.toLowerCase();
|
|
632
|
-
if (lower ===
|
|
641
|
+
if (lower === "full" ||
|
|
642
|
+
lower === "column" ||
|
|
643
|
+
lower === "page") {
|
|
633
644
|
topt.xheaderWidth = lower;
|
|
634
645
|
}
|
|
635
646
|
else {
|
|
@@ -638,7 +649,7 @@ silent = false) => {
|
|
|
638
649
|
n <= 0 ||
|
|
639
650
|
!/^[+]?\d+$/.test(value.trim())) {
|
|
640
651
|
writeErr(`\\pset: allowed xheader_width values are "full" (default), "column", "page", or a number specifying the exact width\n`);
|
|
641
|
-
return { status:
|
|
652
|
+
return { status: "error", errorWritten: true };
|
|
642
653
|
}
|
|
643
654
|
topt.xheaderWidth = n;
|
|
644
655
|
}
|
|
@@ -646,55 +657,55 @@ silent = false) => {
|
|
|
646
657
|
// Upstream `printPsetInfo` quotes the three named widths
|
|
647
658
|
// ("full" / "column" / "page") but renders the numeric form
|
|
648
659
|
// unquoted as `Expanded header width is 33.`.
|
|
649
|
-
const current = topt.xheaderWidth ??
|
|
650
|
-
if (typeof current ===
|
|
660
|
+
const current = topt.xheaderWidth ?? "full";
|
|
661
|
+
if (typeof current === "number") {
|
|
651
662
|
writeOutMaybe(`Expanded header width is ${current}.\n`);
|
|
652
663
|
}
|
|
653
664
|
else {
|
|
654
665
|
writeOutMaybe(`Expanded header width is "${current}".\n`);
|
|
655
666
|
}
|
|
656
|
-
return { status:
|
|
667
|
+
return { status: "ok" };
|
|
657
668
|
}
|
|
658
|
-
case
|
|
659
|
-
case
|
|
660
|
-
case
|
|
669
|
+
case "unicode_border_linestyle":
|
|
670
|
+
case "unicode_column_linestyle":
|
|
671
|
+
case "unicode_header_linestyle": {
|
|
661
672
|
// Upstream `printPsetInfo` renders these as
|
|
662
673
|
// `Unicode border line style is "single".` etc. — note the space
|
|
663
674
|
// between "line" and "style" in the message (the option name
|
|
664
675
|
// itself is one token, `linestyle`).
|
|
665
|
-
const which = opt ===
|
|
666
|
-
?
|
|
667
|
-
: opt ===
|
|
668
|
-
?
|
|
669
|
-
:
|
|
676
|
+
const which = opt === "unicode_border_linestyle"
|
|
677
|
+
? "border"
|
|
678
|
+
: opt === "unicode_column_linestyle"
|
|
679
|
+
? "column"
|
|
680
|
+
: "header";
|
|
670
681
|
if (value !== null) {
|
|
671
682
|
const lower = value.toLowerCase();
|
|
672
|
-
if (lower !==
|
|
683
|
+
if (lower !== "single" && lower !== "double") {
|
|
673
684
|
writeErr(`\\pset: ${opt} must be single or double\n`);
|
|
674
|
-
return { status:
|
|
685
|
+
return { status: "error", errorWritten: true };
|
|
675
686
|
}
|
|
676
687
|
const style = lower;
|
|
677
|
-
if (opt ===
|
|
688
|
+
if (opt === "unicode_border_linestyle") {
|
|
678
689
|
topt.unicodeBorderStyle = style;
|
|
679
690
|
}
|
|
680
|
-
else if (opt ===
|
|
691
|
+
else if (opt === "unicode_column_linestyle") {
|
|
681
692
|
topt.unicodeColumnStyle = style;
|
|
682
693
|
}
|
|
683
694
|
else {
|
|
684
695
|
topt.unicodeHeaderStyle = style;
|
|
685
696
|
}
|
|
686
697
|
}
|
|
687
|
-
const current = opt ===
|
|
688
|
-
? (topt.unicodeBorderStyle ??
|
|
689
|
-
: opt ===
|
|
690
|
-
? (topt.unicodeColumnStyle ??
|
|
691
|
-
: (topt.unicodeHeaderStyle ??
|
|
698
|
+
const current = opt === "unicode_border_linestyle"
|
|
699
|
+
? (topt.unicodeBorderStyle ?? "single")
|
|
700
|
+
: opt === "unicode_column_linestyle"
|
|
701
|
+
? (topt.unicodeColumnStyle ?? "single")
|
|
702
|
+
: (topt.unicodeHeaderStyle ?? "single");
|
|
692
703
|
writeOutMaybe(`Unicode ${which} line style is "${current}".\n`);
|
|
693
|
-
return { status:
|
|
704
|
+
return { status: "ok" };
|
|
694
705
|
}
|
|
695
706
|
default: {
|
|
696
707
|
writeErr(`\\pset: unknown option "${option}"\n`);
|
|
697
|
-
return { status:
|
|
708
|
+
return { status: "error", errorWritten: true };
|
|
698
709
|
}
|
|
699
710
|
}
|
|
700
711
|
};
|
|
@@ -707,8 +718,8 @@ silent = false) => {
|
|
|
707
718
|
const psetQuotedString = (str) => {
|
|
708
719
|
let out = "'";
|
|
709
720
|
for (const ch of str) {
|
|
710
|
-
if (ch ===
|
|
711
|
-
out +=
|
|
721
|
+
if (ch === "\n")
|
|
722
|
+
out += "\\n";
|
|
712
723
|
else if (ch === "'")
|
|
713
724
|
out += "\\'";
|
|
714
725
|
else
|
|
@@ -723,12 +734,12 @@ const psetQuotedString = (str) => {
|
|
|
723
734
|
* `topt.pager` as the upstream-style triple ('off'|'on'|'always') for
|
|
724
735
|
* `applyPset`'s state machine; this is only the bulk-view conversion.
|
|
725
736
|
*/
|
|
726
|
-
const pagerNumeric = (pager) => pager ===
|
|
737
|
+
const pagerNumeric = (pager) => pager === "off" ? 0 : pager === "on" ? 1 : 2;
|
|
727
738
|
/**
|
|
728
739
|
* Render `xheader_width` for the bulk view. Enum values print verbatim;
|
|
729
740
|
* numeric values print as the integer.
|
|
730
741
|
*/
|
|
731
|
-
const xheaderWidthDisplay = (w) => (typeof w ===
|
|
742
|
+
const xheaderWidthDisplay = (w) => (typeof w === "number" ? String(w) : w);
|
|
732
743
|
/**
|
|
733
744
|
* Print the full current `\pset` state, one option per line, to stdout.
|
|
734
745
|
* Used when `\pset` is invoked with no arguments. String-valued settings
|
|
@@ -744,51 +755,51 @@ const printAllPset = (topt) => {
|
|
|
744
755
|
writeOut(`fieldsep ${psetQuotedString(topt.fieldSep)}\n`);
|
|
745
756
|
// fieldsep_zero / recordsep_zero are derived: upstream emits "on" iff
|
|
746
757
|
// the corresponding separator is the NUL byte.
|
|
747
|
-
writeOut(`fieldsep_zero ${topt.fieldSep ===
|
|
748
|
-
writeOut(`footer ${topt.defaultFooter ?
|
|
758
|
+
writeOut(`fieldsep_zero ${topt.fieldSep === "\0" ? "on" : "off"}\n`);
|
|
759
|
+
writeOut(`footer ${topt.defaultFooter ? "on" : "off"}\n`);
|
|
749
760
|
writeOut(`format ${topt.format}\n`);
|
|
750
761
|
writeOut(`linestyle ${topt.unicodeBorderLineStyle}\n`);
|
|
751
762
|
writeOut(`null ${psetQuotedString(topt.nullPrint)}\n`);
|
|
752
|
-
writeOut(`numericlocale ${topt.numericLocale ?
|
|
763
|
+
writeOut(`numericlocale ${topt.numericLocale ? "on" : "off"}\n`);
|
|
753
764
|
// pager is emitted numerically (0/1/2) — upstream uses %d in printPsetInfo.
|
|
754
765
|
writeOut(`pager ${pagerNumeric(topt.pager)}\n`);
|
|
755
766
|
writeOut(`pager_min_lines ${topt.pagerMinLines}\n`);
|
|
756
767
|
writeOut(`recordsep ${psetQuotedString(topt.recordSep)}\n`);
|
|
757
|
-
writeOut(`recordsep_zero ${topt.recordSep ===
|
|
758
|
-
writeOut(`tableattr ${topt.tableAttr === null ?
|
|
759
|
-
writeOut(`title ${topt.title === null ?
|
|
760
|
-
writeOut(`tuples_only ${topt.tuplesOnly ?
|
|
761
|
-
writeOut(`unicode_border_linestyle ${topt.unicodeBorderStyle ??
|
|
762
|
-
writeOut(`unicode_column_linestyle ${topt.unicodeColumnStyle ??
|
|
763
|
-
writeOut(`unicode_header_linestyle ${topt.unicodeHeaderStyle ??
|
|
764
|
-
writeOut(`xheader_width ${xheaderWidthDisplay(topt.xheaderWidth ??
|
|
768
|
+
writeOut(`recordsep_zero ${topt.recordSep === "\0" ? "on" : "off"}\n`);
|
|
769
|
+
writeOut(`tableattr ${topt.tableAttr === null ? "" : psetQuotedString(topt.tableAttr)}\n`);
|
|
770
|
+
writeOut(`title ${topt.title === null ? "" : psetQuotedString(topt.title)}\n`);
|
|
771
|
+
writeOut(`tuples_only ${topt.tuplesOnly ? "on" : "off"}\n`);
|
|
772
|
+
writeOut(`unicode_border_linestyle ${topt.unicodeBorderStyle ?? "single"}\n`);
|
|
773
|
+
writeOut(`unicode_column_linestyle ${topt.unicodeColumnStyle ?? "single"}\n`);
|
|
774
|
+
writeOut(`unicode_header_linestyle ${topt.unicodeHeaderStyle ?? "single"}\n`);
|
|
775
|
+
writeOut(`xheader_width ${xheaderWidthDisplay(topt.xheaderWidth ?? "full")}\n`);
|
|
765
776
|
};
|
|
766
777
|
const lexRawArgs = (tail) => {
|
|
767
778
|
const out = [];
|
|
768
779
|
let i = 0;
|
|
769
|
-
const isSpace = (c) => c ===
|
|
770
|
-
c ===
|
|
771
|
-
c ===
|
|
772
|
-
c ===
|
|
773
|
-
c ===
|
|
774
|
-
c ===
|
|
780
|
+
const isSpace = (c) => c === " " ||
|
|
781
|
+
c === "\t" ||
|
|
782
|
+
c === "\n" ||
|
|
783
|
+
c === "\r" ||
|
|
784
|
+
c === "\f" ||
|
|
785
|
+
c === "\v";
|
|
775
786
|
while (i < tail.length) {
|
|
776
787
|
while (i < tail.length && isSpace(tail[i]))
|
|
777
788
|
i++;
|
|
778
789
|
if (i >= tail.length)
|
|
779
790
|
break;
|
|
780
|
-
if (tail[i] ===
|
|
791
|
+
if (tail[i] === "\\")
|
|
781
792
|
break;
|
|
782
|
-
let arg =
|
|
783
|
-
while (i < tail.length && !isSpace(tail[i]) && tail[i] !==
|
|
793
|
+
let arg = "";
|
|
794
|
+
while (i < tail.length && !isSpace(tail[i]) && tail[i] !== "\\") {
|
|
784
795
|
const c = tail[i];
|
|
785
796
|
if (c === "'") {
|
|
786
797
|
// Single-quoted: keep delimiters in the warning text so the user
|
|
787
798
|
// sees the literal token.
|
|
788
799
|
let j = i + 1;
|
|
789
|
-
let inner =
|
|
800
|
+
let inner = "";
|
|
790
801
|
while (j < tail.length && tail[j] !== "'") {
|
|
791
|
-
if (tail[j] ===
|
|
802
|
+
if (tail[j] === "\\" && j + 1 < tail.length) {
|
|
792
803
|
inner += tail[j] + tail[j + 1];
|
|
793
804
|
j += 2;
|
|
794
805
|
continue;
|
|
@@ -802,7 +813,7 @@ const lexRawArgs = (tail) => {
|
|
|
802
813
|
}
|
|
803
814
|
if (c === '"') {
|
|
804
815
|
let j = i + 1;
|
|
805
|
-
let inner =
|
|
816
|
+
let inner = "";
|
|
806
817
|
while (j < tail.length && tail[j] !== '"') {
|
|
807
818
|
inner += tail[j];
|
|
808
819
|
j++;
|
|
@@ -811,11 +822,11 @@ const lexRawArgs = (tail) => {
|
|
|
811
822
|
i = j < tail.length ? j + 1 : j;
|
|
812
823
|
continue;
|
|
813
824
|
}
|
|
814
|
-
if (c ===
|
|
825
|
+
if (c === "`") {
|
|
815
826
|
// Drop the backtick delimiters; don't run the command (OT_NO_EVAL).
|
|
816
827
|
let j = i + 1;
|
|
817
|
-
let inner =
|
|
818
|
-
while (j < tail.length && tail[j] !==
|
|
828
|
+
let inner = "";
|
|
829
|
+
while (j < tail.length && tail[j] !== "`") {
|
|
819
830
|
inner += tail[j];
|
|
820
831
|
j++;
|
|
821
832
|
}
|
|
@@ -853,8 +864,8 @@ const lexRawArgs = (tail) => {
|
|
|
853
864
|
* collapses to `cmd` without running.
|
|
854
865
|
*/
|
|
855
866
|
export const cmdPset = {
|
|
856
|
-
name:
|
|
857
|
-
helpKey:
|
|
867
|
+
name: "pset",
|
|
868
|
+
helpKey: "pset",
|
|
858
869
|
run: (ctx) => {
|
|
859
870
|
// Upstream `exec_command_pset` calls `psql_scan_slash_option` twice
|
|
860
871
|
// (with `OT_NORMAL`, `evaluate=true`) for option + value, then loops
|
|
@@ -878,19 +889,21 @@ export const cmdPset = {
|
|
|
878
889
|
const rawEntries = lexRawArgs(ctx.rawArgs);
|
|
879
890
|
if (rawEntries.length === 0) {
|
|
880
891
|
printAllPset(ctx.settings.popt.topt);
|
|
881
|
-
return Promise.resolve({ status:
|
|
892
|
+
return Promise.resolve({ status: "ok" });
|
|
882
893
|
}
|
|
883
894
|
// Slice rawArgs up to the end of arg #2 (or arg #1 if only one was
|
|
884
895
|
// provided) and feed THAT to the eval-mode scanner. Anything past
|
|
885
896
|
// that boundary lives in the no-eval extras zone.
|
|
886
|
-
const headEndIdx = rawEntries.length >= 2
|
|
897
|
+
const headEndIdx = rawEntries.length >= 2
|
|
898
|
+
? rawEntries[1].endIdx
|
|
899
|
+
: rawEntries[0].endIdx;
|
|
887
900
|
const headSlice = ctx.rawArgs.slice(0, headEndIdx);
|
|
888
901
|
const varLookup = (name) => ctx.settings.vars.get(name);
|
|
889
|
-
const headArgs = scanSlashArgs(headSlice,
|
|
902
|
+
const headArgs = scanSlashArgs(headSlice, "normal", varLookup);
|
|
890
903
|
const option = headArgs[0] ?? null;
|
|
891
904
|
if (option === null) {
|
|
892
905
|
printAllPset(ctx.settings.popt.topt);
|
|
893
|
-
return Promise.resolve({ status:
|
|
906
|
+
return Promise.resolve({ status: "ok" });
|
|
894
907
|
}
|
|
895
908
|
const value = headArgs[1] ?? null;
|
|
896
909
|
// Under `--quiet` / `\set QUIET on`, upstream `exec_command_pset`
|