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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatNumericLocale } from
|
|
1
|
+
import { formatNumericLocale } from "./units.js";
|
|
2
2
|
/**
|
|
3
3
|
* Aligned tabular printer (psql's default output mode).
|
|
4
4
|
*
|
|
@@ -312,13 +312,13 @@ export const padToWidth = (text, width, alignment) => {
|
|
|
312
312
|
if (w >= width)
|
|
313
313
|
return text;
|
|
314
314
|
const pad = width - w;
|
|
315
|
-
if (alignment ===
|
|
316
|
-
return text +
|
|
317
|
-
if (alignment ===
|
|
318
|
-
return
|
|
315
|
+
if (alignment === "left")
|
|
316
|
+
return text + " ".repeat(pad);
|
|
317
|
+
if (alignment === "right")
|
|
318
|
+
return " ".repeat(pad) + text;
|
|
319
319
|
const leftPad = pad >> 1;
|
|
320
320
|
const rightPad = pad - leftPad;
|
|
321
|
-
return
|
|
321
|
+
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
|
|
322
322
|
};
|
|
323
323
|
// ---------------------------------------------------------------------------
|
|
324
324
|
// Type heuristics & cell formatting (shared with vertical mode).
|
|
@@ -357,46 +357,46 @@ const isRightAlignedField = (oid) => RIGHT_ALIGNED_OIDS.has(oid);
|
|
|
357
357
|
const renderCell = (cell, nullPrint, numericLocale) => {
|
|
358
358
|
if (cell === null || cell === undefined)
|
|
359
359
|
return nullPrint;
|
|
360
|
-
if (typeof cell ===
|
|
360
|
+
if (typeof cell === "string") {
|
|
361
361
|
return formatNumericLocale(cell, numericLocale);
|
|
362
362
|
}
|
|
363
|
-
if (typeof cell ===
|
|
363
|
+
if (typeof cell === "number" || typeof cell === "bigint") {
|
|
364
364
|
return formatNumericLocale(cell.toString(), numericLocale);
|
|
365
365
|
}
|
|
366
|
-
if (typeof cell ===
|
|
367
|
-
return cell ?
|
|
366
|
+
if (typeof cell === "boolean")
|
|
367
|
+
return cell ? "t" : "f";
|
|
368
368
|
if (cell instanceof Date)
|
|
369
369
|
return cell.toISOString();
|
|
370
370
|
if (cell instanceof Uint8Array) {
|
|
371
|
-
let hex =
|
|
371
|
+
let hex = "\\x";
|
|
372
372
|
for (const b of cell)
|
|
373
|
-
hex += b.toString(16).padStart(2,
|
|
373
|
+
hex += b.toString(16).padStart(2, "0");
|
|
374
374
|
return hex;
|
|
375
375
|
}
|
|
376
376
|
return JSON.stringify(cell);
|
|
377
377
|
};
|
|
378
378
|
const ASCII_GLYPHS = {
|
|
379
|
-
hrule:
|
|
380
|
-
vrule:
|
|
381
|
-
topLeft:
|
|
382
|
-
topMid:
|
|
383
|
-
topRight:
|
|
384
|
-
midLeft:
|
|
385
|
-
midMid:
|
|
386
|
-
midRight:
|
|
387
|
-
botLeft:
|
|
388
|
-
botMid:
|
|
389
|
-
botRight:
|
|
390
|
-
headerNlLeft:
|
|
391
|
-
headerNlRight:
|
|
392
|
-
wrapLeft:
|
|
393
|
-
wrapRight:
|
|
394
|
-
nlLeft:
|
|
395
|
-
nlRight:
|
|
379
|
+
hrule: "-",
|
|
380
|
+
vrule: "|",
|
|
381
|
+
topLeft: "+",
|
|
382
|
+
topMid: "+",
|
|
383
|
+
topRight: "+",
|
|
384
|
+
midLeft: "+",
|
|
385
|
+
midMid: "+",
|
|
386
|
+
midRight: "+",
|
|
387
|
+
botLeft: "+",
|
|
388
|
+
botMid: "+",
|
|
389
|
+
botRight: "+",
|
|
390
|
+
headerNlLeft: " ",
|
|
391
|
+
headerNlRight: "+",
|
|
392
|
+
wrapLeft: ".",
|
|
393
|
+
wrapRight: ".",
|
|
394
|
+
nlLeft: " ",
|
|
395
|
+
nlRight: "+",
|
|
396
396
|
wrapRightBorder: true,
|
|
397
|
-
midvruleNl:
|
|
398
|
-
midvruleWrap:
|
|
399
|
-
midvruleBlank:
|
|
397
|
+
midvruleNl: "|",
|
|
398
|
+
midvruleWrap: "|",
|
|
399
|
+
midvruleBlank: "|",
|
|
400
400
|
};
|
|
401
401
|
// `pg_asciiformat_old` — the legacy ASCII renderer kept around for
|
|
402
402
|
// `\pset linestyle old-ascii`. Two visible quirks vs the modern ASCII
|
|
@@ -408,27 +408,27 @@ const ASCII_GLYPHS = {
|
|
|
408
408
|
// joining cell has more `\n`-split lines below, `;` when it has more
|
|
409
409
|
// wrap-split lines, ` ` when the cell is exhausted (`midvrule_blank`).
|
|
410
410
|
const OLD_ASCII_GLYPHS = {
|
|
411
|
-
hrule:
|
|
412
|
-
vrule:
|
|
413
|
-
topLeft:
|
|
414
|
-
topMid:
|
|
415
|
-
topRight:
|
|
416
|
-
midLeft:
|
|
417
|
-
midMid:
|
|
418
|
-
midRight:
|
|
419
|
-
botLeft:
|
|
420
|
-
botMid:
|
|
421
|
-
botRight:
|
|
422
|
-
headerNlLeft:
|
|
423
|
-
headerNlRight:
|
|
424
|
-
wrapLeft:
|
|
425
|
-
wrapRight:
|
|
426
|
-
nlLeft:
|
|
427
|
-
nlRight:
|
|
411
|
+
hrule: "-",
|
|
412
|
+
vrule: "|",
|
|
413
|
+
topLeft: "+",
|
|
414
|
+
topMid: "+",
|
|
415
|
+
topRight: "+",
|
|
416
|
+
midLeft: "+",
|
|
417
|
+
midMid: "+",
|
|
418
|
+
midRight: "+",
|
|
419
|
+
botLeft: "+",
|
|
420
|
+
botMid: "+",
|
|
421
|
+
botRight: "+",
|
|
422
|
+
headerNlLeft: "+",
|
|
423
|
+
headerNlRight: " ",
|
|
424
|
+
wrapLeft: " ",
|
|
425
|
+
wrapRight: " ",
|
|
426
|
+
nlLeft: " ",
|
|
427
|
+
nlRight: " ",
|
|
428
428
|
wrapRightBorder: false,
|
|
429
|
-
midvruleNl:
|
|
430
|
-
midvruleWrap:
|
|
431
|
-
midvruleBlank:
|
|
429
|
+
midvruleNl: ":",
|
|
430
|
+
midvruleWrap: ";",
|
|
431
|
+
midvruleBlank: " ",
|
|
432
432
|
};
|
|
433
433
|
// Light box-drawing glyphs (the only Unicode variant we expose today —
|
|
434
434
|
// `unicode_border_linestyle=double` / `unicode_column_linestyle=double` /
|
|
@@ -452,35 +452,35 @@ const OLD_ASCII_GLYPHS = {
|
|
|
452
452
|
// U+2534 ┴ Box Drawings Light Up and Horizontal (botMid)
|
|
453
453
|
// U+2518 ┘ Box Drawings Light Up and Left (botRight)
|
|
454
454
|
const UNICODE_GLYPHS = {
|
|
455
|
-
hrule:
|
|
456
|
-
vrule:
|
|
457
|
-
topLeft:
|
|
458
|
-
topMid:
|
|
459
|
-
topRight:
|
|
460
|
-
midLeft:
|
|
461
|
-
midMid:
|
|
462
|
-
midRight:
|
|
463
|
-
botLeft:
|
|
464
|
-
botMid:
|
|
465
|
-
botRight:
|
|
455
|
+
hrule: "─",
|
|
456
|
+
vrule: "│",
|
|
457
|
+
topLeft: "┌",
|
|
458
|
+
topMid: "┬",
|
|
459
|
+
topRight: "┐",
|
|
460
|
+
midLeft: "├",
|
|
461
|
+
midMid: "┼",
|
|
462
|
+
midRight: "┤",
|
|
463
|
+
botLeft: "└",
|
|
464
|
+
botMid: "┴",
|
|
465
|
+
botRight: "┘",
|
|
466
466
|
// U+21B5 ↵ "Downwards Arrow with Corner Leftwards" — newline marker.
|
|
467
467
|
// U+2026 … "Horizontal Ellipsis" — in-cell wrap marker.
|
|
468
468
|
// Matches `unicode_style` in upstream `fe_utils/print.c`.
|
|
469
|
-
headerNlLeft:
|
|
470
|
-
headerNlRight:
|
|
471
|
-
wrapLeft:
|
|
472
|
-
wrapRight:
|
|
473
|
-
nlLeft:
|
|
474
|
-
nlRight:
|
|
469
|
+
headerNlLeft: " ",
|
|
470
|
+
headerNlRight: "↵",
|
|
471
|
+
wrapLeft: "…",
|
|
472
|
+
wrapRight: "…",
|
|
473
|
+
nlLeft: " ",
|
|
474
|
+
nlRight: "↵",
|
|
475
475
|
wrapRightBorder: true,
|
|
476
|
-
midvruleNl:
|
|
477
|
-
midvruleWrap:
|
|
478
|
-
midvruleBlank:
|
|
476
|
+
midvruleNl: "│",
|
|
477
|
+
midvruleWrap: "│",
|
|
478
|
+
midvruleBlank: "│",
|
|
479
479
|
};
|
|
480
480
|
const glyphsFor = (style) => {
|
|
481
|
-
if (style ===
|
|
481
|
+
if (style === "unicode")
|
|
482
482
|
return UNICODE_GLYPHS;
|
|
483
|
-
if (style ===
|
|
483
|
+
if (style === "old-ascii")
|
|
484
484
|
return OLD_ASCII_GLYPHS;
|
|
485
485
|
return ASCII_GLYPHS;
|
|
486
486
|
};
|
|
@@ -502,7 +502,7 @@ export const computeColumnWidths = (rs, topt) => {
|
|
|
502
502
|
for (const row of rs.rows) {
|
|
503
503
|
for (let i = 0; i < rs.fields.length; i++) {
|
|
504
504
|
const cellText = renderCell(row[i], nullPrint, numericLocale);
|
|
505
|
-
for (const line of cellText.split(
|
|
505
|
+
for (const line of cellText.split("\n")) {
|
|
506
506
|
const w = displayWidth(line);
|
|
507
507
|
if (w > widths[i])
|
|
508
508
|
widths[i] = w;
|
|
@@ -512,7 +512,7 @@ export const computeColumnWidths = (rs, topt) => {
|
|
|
512
512
|
return widths;
|
|
513
513
|
};
|
|
514
514
|
const formatCell = (text) => {
|
|
515
|
-
const lines = text.split(
|
|
515
|
+
const lines = text.split("\n");
|
|
516
516
|
let width = 0;
|
|
517
517
|
for (const l of lines) {
|
|
518
518
|
const w = displayWidth(l);
|
|
@@ -538,12 +538,12 @@ const buildRule = (widths, border, glyphs, position) => {
|
|
|
538
538
|
let left;
|
|
539
539
|
let mid;
|
|
540
540
|
let right;
|
|
541
|
-
if (position ===
|
|
541
|
+
if (position === "top") {
|
|
542
542
|
left = glyphs.topLeft;
|
|
543
543
|
mid = glyphs.topMid;
|
|
544
544
|
right = glyphs.topRight;
|
|
545
545
|
}
|
|
546
|
-
else if (position ===
|
|
546
|
+
else if (position === "middle") {
|
|
547
547
|
left = glyphs.midLeft;
|
|
548
548
|
mid = glyphs.midMid;
|
|
549
549
|
right = glyphs.midRight;
|
|
@@ -553,7 +553,7 @@ const buildRule = (widths, border, glyphs, position) => {
|
|
|
553
553
|
mid = glyphs.botMid;
|
|
554
554
|
right = glyphs.botRight;
|
|
555
555
|
}
|
|
556
|
-
let out =
|
|
556
|
+
let out = "";
|
|
557
557
|
if (border === 2 || border === 3) {
|
|
558
558
|
out += left;
|
|
559
559
|
}
|
|
@@ -564,7 +564,7 @@ const buildRule = (widths, border, glyphs, position) => {
|
|
|
564
564
|
out += hrule.repeat(widths[i] + pad * 2);
|
|
565
565
|
if (i < widths.length - 1) {
|
|
566
566
|
if (border === 0) {
|
|
567
|
-
out +=
|
|
567
|
+
out += " "; // single space between columns in border 0
|
|
568
568
|
}
|
|
569
569
|
else {
|
|
570
570
|
out += mid;
|
|
@@ -580,10 +580,10 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
580
580
|
const topt = opts.topt;
|
|
581
581
|
const border = topt.border;
|
|
582
582
|
const tuplesOnly = topt.tuplesOnly;
|
|
583
|
-
const nullPrint = opts.nullPrint !==
|
|
583
|
+
const nullPrint = opts.nullPrint !== "" ? opts.nullPrint : topt.nullPrint;
|
|
584
584
|
const glyphs = glyphsFor(topt.unicodeBorderLineStyle);
|
|
585
585
|
const headers = rs.fields.map((f) => f.name);
|
|
586
|
-
const aligns = rs.fields.map((f) => isRightAlignedField(f.dataTypeID) ?
|
|
586
|
+
const aligns = rs.fields.map((f) => isRightAlignedField(f.dataTypeID) ? "right" : "left");
|
|
587
587
|
// Pre-render & measure every cell.
|
|
588
588
|
const cellGrid = rs.rows.map((row) => row.map((cell) => formatCell(renderCell(cell, nullPrint, topt.numericLocale))));
|
|
589
589
|
const headerCells = headers.map((h) => formatCell(h));
|
|
@@ -664,7 +664,8 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
664
664
|
// - width_wrap[i] > width_header[i] (header is the floor;
|
|
665
665
|
// can't shrink below it without overlapping the header).
|
|
666
666
|
if (widthAverage[i] > 0 && widths[i] > headerW) {
|
|
667
|
-
const ratio = widths[i] / widthAverage[i] +
|
|
667
|
+
const ratio = widths[i] / widthAverage[i] +
|
|
668
|
+
maxWidth[i] * 0.01;
|
|
668
669
|
if (ratio > maxRatio) {
|
|
669
670
|
maxRatio = ratio;
|
|
670
671
|
worstCol = i;
|
|
@@ -679,8 +680,8 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
679
680
|
}
|
|
680
681
|
}
|
|
681
682
|
}
|
|
682
|
-
let out =
|
|
683
|
-
const newline =
|
|
683
|
+
let out = "";
|
|
684
|
+
const newline = "\n";
|
|
684
685
|
// Compute total table width once: needed for title centring (and only
|
|
685
686
|
// there at the moment). Mirrors upstream `width_total` from
|
|
686
687
|
// print.c lines 935-950: when the title is narrower than the table,
|
|
@@ -699,12 +700,12 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
699
700
|
}
|
|
700
701
|
else {
|
|
701
702
|
const pad = (widthTotal - titleW) >> 1;
|
|
702
|
-
out +=
|
|
703
|
+
out += " ".repeat(pad) + topt.title + newline;
|
|
703
704
|
}
|
|
704
705
|
}
|
|
705
706
|
// Top rule: emitted when border == 2 or 3.
|
|
706
707
|
if (!tuplesOnly && (border === 2 || border === 3)) {
|
|
707
|
-
out += buildRule(widths, border, glyphs,
|
|
708
|
+
out += buildRule(widths, border, glyphs, "top") + newline;
|
|
708
709
|
}
|
|
709
710
|
// ------- Header row(s) -------
|
|
710
711
|
if (!tuplesOnly) {
|
|
@@ -732,13 +733,13 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
732
733
|
// `nl` the cell has more `\n`-split content below
|
|
733
734
|
// (header_nl_left/header_nl_right marker)
|
|
734
735
|
// `none` the cell is done (already emitted its last line)
|
|
735
|
-
const cellWrapPrev = headerColLines.map((l) => (lineIdx > 0 && lineIdx < l.length ?
|
|
736
|
-
const cellWrapNext = headerColLines.map((l) => (lineIdx < l.length - 1 ?
|
|
737
|
-
out += renderHeaderLine(headerColLines.map((l) => l[lineIdx] ??
|
|
736
|
+
const cellWrapPrev = headerColLines.map((l) => (lineIdx > 0 && lineIdx < l.length ? "nl" : "none"));
|
|
737
|
+
const cellWrapNext = headerColLines.map((l) => (lineIdx < l.length - 1 ? "nl" : "none"));
|
|
738
|
+
out += renderHeaderLine(headerColLines.map((l) => l[lineIdx] ?? ""), widths, border, glyphs, cellWrapPrev, cellWrapNext, lineIdx === 0);
|
|
738
739
|
out += newline;
|
|
739
740
|
}
|
|
740
741
|
// Header rule.
|
|
741
|
-
out += buildRule(widths, border, glyphs,
|
|
742
|
+
out += buildRule(widths, border, glyphs, "middle") + newline;
|
|
742
743
|
}
|
|
743
744
|
// ------- Data rows -------
|
|
744
745
|
for (let r = 0; r < cellGrid.length; r++) {
|
|
@@ -771,14 +772,16 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
771
772
|
const kinds = [];
|
|
772
773
|
const lines = cell.lines;
|
|
773
774
|
for (let si = 0; si < lines.length; si++) {
|
|
774
|
-
const chunks = wrapped
|
|
775
|
+
const chunks = wrapped
|
|
776
|
+
? wrapLine(lines[si], widths[i])
|
|
777
|
+
: [lines[si]];
|
|
775
778
|
for (let ci = 0; ci < chunks.length; ci++) {
|
|
776
779
|
if (si === 0 && ci === 0)
|
|
777
|
-
kinds.push(
|
|
780
|
+
kinds.push("start");
|
|
778
781
|
else if (ci === 0)
|
|
779
|
-
kinds.push(
|
|
782
|
+
kinds.push("nl");
|
|
780
783
|
else
|
|
781
|
-
kinds.push(
|
|
784
|
+
kinds.push("wrap");
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
787
|
return kinds;
|
|
@@ -794,26 +797,26 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
794
797
|
// still emitting more content.
|
|
795
798
|
const cellWrapPrev = colLineKinds.map((kinds, j) => {
|
|
796
799
|
if (li === 0 || li >= colLines[j].length)
|
|
797
|
-
return
|
|
798
|
-
return kinds[li] ===
|
|
800
|
+
return "none";
|
|
801
|
+
return kinds[li] === "wrap" ? "wrap" : "nl";
|
|
799
802
|
});
|
|
800
803
|
const cellWrapNext = colLineKinds.map((kinds, j) => {
|
|
801
804
|
const nextIdx = li + 1;
|
|
802
805
|
if (nextIdx >= colLines[j].length)
|
|
803
|
-
return
|
|
804
|
-
return kinds[nextIdx] ===
|
|
806
|
+
return "none";
|
|
807
|
+
return kinds[nextIdx] === "wrap" ? "wrap" : "nl";
|
|
805
808
|
});
|
|
806
|
-
out += renderDataLine(colLines.map((l) => l[li] ??
|
|
809
|
+
out += renderDataLine(colLines.map((l) => l[li] ?? ""), widths, aligns, border, glyphs, cellWrapPrev, cellWrapNext, li === 0);
|
|
807
810
|
out += newline;
|
|
808
811
|
}
|
|
809
812
|
// Heavy borders (border == 3) insert a rule between rows.
|
|
810
813
|
if (border === 3 && r < cellGrid.length - 1) {
|
|
811
|
-
out += buildRule(widths, border, glyphs,
|
|
814
|
+
out += buildRule(widths, border, glyphs, "middle") + newline;
|
|
812
815
|
}
|
|
813
816
|
}
|
|
814
817
|
// Bottom rule when border 2/3.
|
|
815
818
|
if (!tuplesOnly && (border === 2 || border === 3)) {
|
|
816
|
-
out += buildRule(widths, border, glyphs,
|
|
819
|
+
out += buildRule(widths, border, glyphs, "bottom") + newline;
|
|
817
820
|
}
|
|
818
821
|
// Footer: (N rows) + trailing blank line. Upstream's
|
|
819
822
|
// `print_aligned_text` emits `printTableAddFooter()` and then
|
|
@@ -831,7 +834,7 @@ const renderHorizontal = (rs, opts, wrapped) => {
|
|
|
831
834
|
const hasUserFooters = !!opts.footers && opts.footers.length > 0;
|
|
832
835
|
if (!tuplesOnly && topt.defaultFooter && !hasUserFooters) {
|
|
833
836
|
const n = rs.rows.length;
|
|
834
|
-
out += `(${String(n)} ${n === 1 ?
|
|
837
|
+
out += `(${String(n)} ${n === 1 ? "row" : "rows"})` + newline;
|
|
835
838
|
}
|
|
836
839
|
if (!tuplesOnly && opts.footers) {
|
|
837
840
|
for (const f of opts.footers)
|
|
@@ -870,9 +873,9 @@ const pickMidvrule = (glyphs,
|
|
|
870
873
|
_left, right, firstLine) => {
|
|
871
874
|
if (firstLine)
|
|
872
875
|
return glyphs.vrule;
|
|
873
|
-
if (right ===
|
|
876
|
+
if (right === "wrap")
|
|
874
877
|
return glyphs.midvruleWrap;
|
|
875
|
-
if (right ===
|
|
878
|
+
if (right === "nl")
|
|
876
879
|
return glyphs.midvruleNl;
|
|
877
880
|
return glyphs.midvruleBlank;
|
|
878
881
|
};
|
|
@@ -885,16 +888,16 @@ _left, right, firstLine) => {
|
|
|
885
888
|
* without border)
|
|
886
889
|
*/
|
|
887
890
|
const dataRightMarker = (state, glyphs, isLast, border) => {
|
|
888
|
-
if (state ===
|
|
891
|
+
if (state === "wrap")
|
|
889
892
|
return glyphs.wrapRight;
|
|
890
|
-
if (state ===
|
|
893
|
+
if (state === "nl")
|
|
891
894
|
return glyphs.nlRight;
|
|
892
895
|
// state === 'none': trailing edge — only emit a space when there's
|
|
893
896
|
// something AFTER us (another column to follow, or the right border
|
|
894
897
|
// of a border=2/3 box). For the LAST cell on a borderless row, nothing.
|
|
895
898
|
if (isLast && border !== 2 && border !== 3)
|
|
896
|
-
return
|
|
897
|
-
return
|
|
899
|
+
return "";
|
|
900
|
+
return " ";
|
|
898
901
|
};
|
|
899
902
|
/**
|
|
900
903
|
* Left-marker glyph for a data row's cell. Mirrors `wrap[j]` at upstream
|
|
@@ -907,11 +910,11 @@ const dataRightMarker = (state, glyphs, isLast, border) => {
|
|
|
907
910
|
* upstream skips this entirely (no leading marker).
|
|
908
911
|
*/
|
|
909
912
|
const dataLeftMarker = (state, glyphs) => {
|
|
910
|
-
if (state ===
|
|
913
|
+
if (state === "wrap")
|
|
911
914
|
return glyphs.wrapLeft;
|
|
912
|
-
if (state ===
|
|
915
|
+
if (state === "nl")
|
|
913
916
|
return glyphs.nlLeft;
|
|
914
|
-
return
|
|
917
|
+
return " ";
|
|
915
918
|
};
|
|
916
919
|
/**
|
|
917
920
|
* Render one display-line of a header row. Centered cells, fixed
|
|
@@ -942,7 +945,7 @@ cellWrapNext,
|
|
|
942
945
|
// exhausted on that line — so the choice can't be made per-column.
|
|
943
946
|
firstLine) => {
|
|
944
947
|
const { vrule } = glyphs;
|
|
945
|
-
let out =
|
|
948
|
+
let out = "";
|
|
946
949
|
if (border === 2 || border === 3)
|
|
947
950
|
out += vrule;
|
|
948
951
|
for (let i = 0; i < cells.length; i++) {
|
|
@@ -955,12 +958,12 @@ firstLine) => {
|
|
|
955
958
|
// cells too at border=0 — the inter-column slot doubles as the
|
|
956
959
|
// leading-gutter slot of col[i].
|
|
957
960
|
if (border !== 0 || (!glyphs.wrapRightBorder && i > 0)) {
|
|
958
|
-
out += firstLine ?
|
|
961
|
+
out += firstLine ? " " : glyphs.headerNlLeft;
|
|
959
962
|
}
|
|
960
963
|
// Header cells are always centered and padded to full width
|
|
961
964
|
// (upstream emits `%-*s%s%-*s` regardless of position — no
|
|
962
965
|
// skip-padding-on-last-cell quirk on header rows).
|
|
963
|
-
out += padToWidth(cells[i], widths[i],
|
|
966
|
+
out += padToWidth(cells[i], widths[i], "center");
|
|
964
967
|
// Trailing marker. Upstream `print.c` line 1003-1005:
|
|
965
968
|
// if (opt_border != 0 || format->wrap_right_border)
|
|
966
969
|
// fputs(!header_done[i] ? format->header_nl_right : " ", fout);
|
|
@@ -971,7 +974,7 @@ firstLine) => {
|
|
|
971
974
|
// border=0 — the inter-column space comes from the NEXT cell's
|
|
972
975
|
// leading-gutter emit on the next loop iteration.
|
|
973
976
|
if (border !== 0 || glyphs.wrapRightBorder) {
|
|
974
|
-
out += cellWrapNext[i] !==
|
|
977
|
+
out += cellWrapNext[i] !== "none" ? glyphs.headerNlRight : " ";
|
|
975
978
|
}
|
|
976
979
|
// Column divider (not on the last column). For border 0 ASCII the
|
|
977
980
|
// trailing-marker slot above already consumes the inter-column gap.
|
|
@@ -1016,7 +1019,7 @@ cellWrapNext,
|
|
|
1016
1019
|
// emitted).
|
|
1017
1020
|
firstLine) => {
|
|
1018
1021
|
const { vrule } = glyphs;
|
|
1019
|
-
let out =
|
|
1022
|
+
let out = "";
|
|
1020
1023
|
if (border === 2 || border === 3)
|
|
1021
1024
|
out += vrule;
|
|
1022
1025
|
for (let i = 0; i < cells.length; i++) {
|
|
@@ -1036,15 +1039,15 @@ firstLine) => {
|
|
|
1036
1039
|
// right-aligned cells always pad on the left side regardless.
|
|
1037
1040
|
// `finalspaces` = (border == 2 || not last column).
|
|
1038
1041
|
const finalspaces = border === 2 || border === 3 || !isLast;
|
|
1039
|
-
const needsTrailingPad = finalspaces || cellWrapNext[i] !==
|
|
1040
|
-
if (aligns[i] ===
|
|
1042
|
+
const needsTrailingPad = finalspaces || cellWrapNext[i] !== "none";
|
|
1043
|
+
if (aligns[i] === "right") {
|
|
1041
1044
|
// Right-aligned cells always get full padding on the left so
|
|
1042
1045
|
// content right-aligns. Trailing pad only when finalspaces (or
|
|
1043
1046
|
// wrap, to keep marker aligned).
|
|
1044
|
-
out += padToWidth(cells[i], widths[i],
|
|
1047
|
+
out += padToWidth(cells[i], widths[i], "right");
|
|
1045
1048
|
}
|
|
1046
1049
|
else if (needsTrailingPad) {
|
|
1047
|
-
out += padToWidth(cells[i], widths[i],
|
|
1050
|
+
out += padToWidth(cells[i], widths[i], "left");
|
|
1048
1051
|
}
|
|
1049
1052
|
else {
|
|
1050
1053
|
// Last cell, no wrap state — emit raw content (no trailing pad).
|
|
@@ -1063,7 +1066,7 @@ firstLine) => {
|
|
|
1063
1066
|
if (border !== 0 || glyphs.wrapRightBorder) {
|
|
1064
1067
|
out += dataRightMarker(cellWrapNext[i], glyphs, isLast, border);
|
|
1065
1068
|
}
|
|
1066
|
-
else if (isLast && cellWrapNext[i] !==
|
|
1069
|
+
else if (isLast && cellWrapNext[i] !== "none") {
|
|
1067
1070
|
out += dataRightMarker(cellWrapNext[i], glyphs, isLast, border);
|
|
1068
1071
|
}
|
|
1069
1072
|
// Column divider. Upstream lines 1158-1169: in old-ascii the
|
|
@@ -1091,13 +1094,13 @@ const wrapLine = (line, width) => {
|
|
|
1091
1094
|
if (displayWidth(line) <= width)
|
|
1092
1095
|
return [line];
|
|
1093
1096
|
const chunks = [];
|
|
1094
|
-
let buf =
|
|
1097
|
+
let buf = "";
|
|
1095
1098
|
let bufW = 0;
|
|
1096
1099
|
for (const ch of line) {
|
|
1097
1100
|
const cw = codePointWidth(ch.codePointAt(0) ?? 0);
|
|
1098
1101
|
if (bufW + cw > width && buf.length > 0) {
|
|
1099
1102
|
chunks.push(buf);
|
|
1100
|
-
buf =
|
|
1103
|
+
buf = "";
|
|
1101
1104
|
bufW = 0;
|
|
1102
1105
|
}
|
|
1103
1106
|
buf += ch;
|
|
@@ -1114,25 +1117,25 @@ const renderVertical = (rs, opts) => {
|
|
|
1114
1117
|
const topt = opts.topt;
|
|
1115
1118
|
const border = topt.border;
|
|
1116
1119
|
const tuplesOnly = topt.tuplesOnly;
|
|
1117
|
-
const nullPrint = opts.nullPrint !==
|
|
1120
|
+
const nullPrint = opts.nullPrint !== "" ? opts.nullPrint : topt.nullPrint;
|
|
1118
1121
|
const glyphs = glyphsFor(topt.unicodeBorderLineStyle);
|
|
1119
1122
|
// `old-ascii` swaps several emission decisions (leading-slot at border<2,
|
|
1120
1123
|
// suppressed data trailing marker, alternate midvrule glyph on
|
|
1121
1124
|
// continuation lines). Track once at the top so the per-line code stays
|
|
1122
1125
|
// readable.
|
|
1123
|
-
const oldAscii = topt.unicodeBorderLineStyle ===
|
|
1126
|
+
const oldAscii = topt.unicodeBorderLineStyle === "old-ascii";
|
|
1124
1127
|
const headers = rs.fields.map((f) => f.name);
|
|
1125
1128
|
// Width of the name column = max header line width (multi-line headers
|
|
1126
1129
|
// count per-line; upstream `pg_wcssize` returns the widest line).
|
|
1127
1130
|
let nameWidth = 0;
|
|
1128
1131
|
let hmultiline = false;
|
|
1129
1132
|
for (const h of headers) {
|
|
1130
|
-
for (const line of h.split(
|
|
1133
|
+
for (const line of h.split("\n")) {
|
|
1131
1134
|
const w = displayWidth(line);
|
|
1132
1135
|
if (w > nameWidth)
|
|
1133
1136
|
nameWidth = w;
|
|
1134
1137
|
}
|
|
1135
|
-
if (h.includes(
|
|
1138
|
+
if (h.includes("\n"))
|
|
1136
1139
|
hmultiline = true;
|
|
1137
1140
|
}
|
|
1138
1141
|
// Width of the value column = max value width across all rows.
|
|
@@ -1141,9 +1144,9 @@ const renderVertical = (rs, opts) => {
|
|
|
1141
1144
|
const cellGrid = rs.rows.map((row) => row.map((cell) => renderCell(cell, nullPrint, topt.numericLocale)));
|
|
1142
1145
|
for (const row of cellGrid) {
|
|
1143
1146
|
for (const v of row) {
|
|
1144
|
-
if (v.includes(
|
|
1147
|
+
if (v.includes("\n"))
|
|
1145
1148
|
dmultiline = true;
|
|
1146
|
-
for (const line of v.split(
|
|
1149
|
+
for (const line of v.split("\n")) {
|
|
1147
1150
|
const w = displayWidth(line);
|
|
1148
1151
|
if (w > valueWidth)
|
|
1149
1152
|
valueWidth = w;
|
|
@@ -1168,7 +1171,7 @@ const renderVertical = (rs, opts) => {
|
|
|
1168
1171
|
// The two-pass loop turns `dmultiline` on the first iteration if a
|
|
1169
1172
|
// wrap is needed, then recomputes with the bumped swidth. We
|
|
1170
1173
|
// implement that as a single pass over the two possible swidths.
|
|
1171
|
-
const wrappedMode = topt.format ===
|
|
1174
|
+
const wrappedMode = topt.format === "wrapped";
|
|
1172
1175
|
let dwidth = valueWidth;
|
|
1173
1176
|
if (wrappedMode) {
|
|
1174
1177
|
const outputColumns = topt.columns > 0 ? topt.columns : topt.envColumns;
|
|
@@ -1190,7 +1193,9 @@ const renderVertical = (rs, opts) => {
|
|
|
1190
1193
|
const labelOverhead = border === 0 ? 9 : border === 1 ? 12 : 15;
|
|
1191
1194
|
const nrows = cellGrid.length;
|
|
1192
1195
|
const rwidth = labelOverhead +
|
|
1193
|
-
(nrows > 0
|
|
1196
|
+
(nrows > 0
|
|
1197
|
+
? 1 + Math.floor(Math.log10(Math.max(1, nrows)))
|
|
1198
|
+
: 0);
|
|
1194
1199
|
const compute = (swidth) => {
|
|
1195
1200
|
let width = nameWidth + swidth + valueWidth;
|
|
1196
1201
|
if (width < rwidth)
|
|
@@ -1218,8 +1223,8 @@ const renderVertical = (rs, opts) => {
|
|
|
1218
1223
|
dwidth = newDwidth < valueWidth ? newDwidth : valueWidth;
|
|
1219
1224
|
}
|
|
1220
1225
|
}
|
|
1221
|
-
let out =
|
|
1222
|
-
const newline =
|
|
1226
|
+
let out = "";
|
|
1227
|
+
const newline = "\n";
|
|
1223
1228
|
if (!tuplesOnly && topt.title) {
|
|
1224
1229
|
out += topt.title + newline;
|
|
1225
1230
|
}
|
|
@@ -1230,7 +1235,7 @@ const renderVertical = (rs, opts) => {
|
|
|
1230
1235
|
// against vanilla psql 18: `\\pset expanded on` then `select 1
|
|
1231
1236
|
// where false;` emits `(0 rows)\n\n`.
|
|
1232
1237
|
if (!tuplesOnly)
|
|
1233
|
-
out +=
|
|
1238
|
+
out += "(0 rows)" + newline;
|
|
1234
1239
|
if (!tuplesOnly && opts.footers) {
|
|
1235
1240
|
for (const f of opts.footers)
|
|
1236
1241
|
out += f + newline;
|
|
@@ -1276,8 +1281,8 @@ const renderVertical = (rs, opts) => {
|
|
|
1276
1281
|
out += newline;
|
|
1277
1282
|
}
|
|
1278
1283
|
for (let c = 0; c < headers.length; c++) {
|
|
1279
|
-
const headerLines = headers[c].split(
|
|
1280
|
-
const dataLines = cellGrid[r][c].split(
|
|
1284
|
+
const headerLines = headers[c].split("\n");
|
|
1285
|
+
const dataLines = cellGrid[r][c].split("\n");
|
|
1281
1286
|
out += renderVerticalCell(headerLines, dataLines, nameWidth, dwidth, border, glyphs, hmultiline, emitHeaderMarker, emitDataMarker, emitHeaderLeftSlot, oldAscii);
|
|
1282
1287
|
}
|
|
1283
1288
|
}
|
|
@@ -1364,7 +1369,7 @@ const renderRecordHeader = (record, nameWidth, valueWidth, border, glyphs, isFir
|
|
|
1364
1369
|
// blank line padded to width; at border>=1 a continuous hrule run.
|
|
1365
1370
|
if (record === 0) {
|
|
1366
1371
|
if (border === 0) {
|
|
1367
|
-
return
|
|
1372
|
+
return " ".repeat(nameWidth + valueWidth);
|
|
1368
1373
|
}
|
|
1369
1374
|
if (border === 1) {
|
|
1370
1375
|
const rowWidth = nameWidth + 3 + valueWidth;
|
|
@@ -1389,7 +1394,7 @@ const renderRecordHeader = (record, nameWidth, valueWidth, border, glyphs, isFir
|
|
|
1389
1394
|
const target = nameWidth + valueWidth;
|
|
1390
1395
|
if (label.length >= target)
|
|
1391
1396
|
return label;
|
|
1392
|
-
return label +
|
|
1397
|
+
return label + " ".repeat(target - label.length);
|
|
1393
1398
|
}
|
|
1394
1399
|
const label = `[ RECORD ${String(record)} ]`;
|
|
1395
1400
|
// border 1: `-[ RECORD N ]---+---------`
|
|
@@ -1437,7 +1442,11 @@ const renderRecordHeader = (record, nameWidth, valueWidth, border, glyphs, isFir
|
|
|
1437
1442
|
// top/mid junction, then rightSegLen hrules, then top/mid right
|
|
1438
1443
|
// corner.
|
|
1439
1444
|
const leftPadded = leftCore + hrule.repeat(leftSegLen - leftCore.length);
|
|
1440
|
-
return (outerLeft +
|
|
1445
|
+
return (outerLeft +
|
|
1446
|
+
leftPadded +
|
|
1447
|
+
outerMid +
|
|
1448
|
+
hrule.repeat(rightSegLen) +
|
|
1449
|
+
outerRight);
|
|
1441
1450
|
}
|
|
1442
1451
|
// Label overflows the left segment. Drop the mid junction and pad
|
|
1443
1452
|
// hrules between the outer corners. When the natural row inner width
|
|
@@ -1482,7 +1491,7 @@ const renderRecordHeader = (record, nameWidth, valueWidth, border, glyphs, isFir
|
|
|
1482
1491
|
*/
|
|
1483
1492
|
const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, glyphs, hmultiline, emitHeaderMarker, emitDataMarker, emitHeaderLeftSlot, oldAscii) => {
|
|
1484
1493
|
const { vrule } = glyphs;
|
|
1485
|
-
let out =
|
|
1494
|
+
let out = "";
|
|
1486
1495
|
const dataChunks = [];
|
|
1487
1496
|
for (const src of dataLines) {
|
|
1488
1497
|
if (dwidth > 0 && displayWidth(src) > dwidth) {
|
|
@@ -1528,10 +1537,10 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1528
1537
|
// `border==2 || (hmultiline && oldAscii)`. Old-ascii routes the
|
|
1529
1538
|
// continuation marker through the LEFT side via header_nl_left.
|
|
1530
1539
|
if (emitHeaderLeftSlot) {
|
|
1531
|
-
out += hLine > 0 ? glyphs.headerNlLeft :
|
|
1540
|
+
out += hLine > 0 ? glyphs.headerNlLeft : " ";
|
|
1532
1541
|
}
|
|
1533
1542
|
const text = headerLines[hLine];
|
|
1534
|
-
out += padToWidth(text, nameWidth,
|
|
1543
|
+
out += padToWidth(text, nameWidth, "left");
|
|
1535
1544
|
const hasMore = hLine + 1 < headerLines.length;
|
|
1536
1545
|
if (hasMore) {
|
|
1537
1546
|
if (emitHeaderMarker)
|
|
@@ -1540,7 +1549,7 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1540
1549
|
}
|
|
1541
1550
|
else {
|
|
1542
1551
|
if (emitHeaderMarker)
|
|
1543
|
-
out +=
|
|
1552
|
+
out += " ";
|
|
1544
1553
|
hcomplete = true;
|
|
1545
1554
|
}
|
|
1546
1555
|
}
|
|
@@ -1556,7 +1565,7 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1556
1565
|
swidth++;
|
|
1557
1566
|
if (border === 0 && hmultiline && !oldAscii)
|
|
1558
1567
|
swidth++;
|
|
1559
|
-
out +=
|
|
1568
|
+
out += " ".repeat(swidth);
|
|
1560
1569
|
}
|
|
1561
1570
|
// ---- Separator ----
|
|
1562
1571
|
// Border > 0 emits the column rule. Upstream `print.c` 1710-1719
|
|
@@ -1580,7 +1589,7 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1580
1589
|
// Leading slot: " " on the first chunk of a source line,
|
|
1581
1590
|
// wrap_left on a wrap continuation. ALWAYS emitted (upstream
|
|
1582
1591
|
// print.c line 1731 has no border guard).
|
|
1583
|
-
out += offset === 0 ?
|
|
1592
|
+
out += offset === 0 ? " " : glyphs.wrapLeft;
|
|
1584
1593
|
out += chunk.text;
|
|
1585
1594
|
// Mirror upstream's `offset += bytes_to_output`: bumped even on
|
|
1586
1595
|
// the last chunk of a cell, so the next iteration (header still
|
|
@@ -1589,7 +1598,7 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1589
1598
|
const isLastChunk = dLine === dataChunks.length - 1;
|
|
1590
1599
|
const nextChunk = !isLastChunk ? dataChunks[dLine + 1] : null;
|
|
1591
1600
|
let needsPad = false;
|
|
1592
|
-
let markerGlyph =
|
|
1601
|
+
let markerGlyph = "";
|
|
1593
1602
|
if (nextChunk && !chunk.isWrapEnd) {
|
|
1594
1603
|
// Wrap continuation: next chunk continues THIS source line.
|
|
1595
1604
|
if (emitDataMarker) {
|
|
@@ -1613,7 +1622,7 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1613
1622
|
if (border > 1) {
|
|
1614
1623
|
// Border 2/3: pad to dwidth, trailing space, then vrule.
|
|
1615
1624
|
needsPad = true;
|
|
1616
|
-
markerGlyph =
|
|
1625
|
+
markerGlyph = " ";
|
|
1617
1626
|
}
|
|
1618
1627
|
dcomplete = true;
|
|
1619
1628
|
// Offset stays bumped — header-tail iterations should see
|
|
@@ -1622,7 +1631,7 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1622
1631
|
if (needsPad) {
|
|
1623
1632
|
const pad = dwidth - chunk.width;
|
|
1624
1633
|
if (pad > 0)
|
|
1625
|
-
out +=
|
|
1634
|
+
out += " ".repeat(pad);
|
|
1626
1635
|
}
|
|
1627
1636
|
out += markerGlyph;
|
|
1628
1637
|
// ---- Right border ----
|
|
@@ -1635,10 +1644,10 @@ const renderVerticalCell = (headerLines, dataLines, nameWidth, dwidth, border, g
|
|
|
1635
1644
|
// (upstream: `fprintf(fout, "%*s %s\n", dwidth, "", rightvrule)`
|
|
1636
1645
|
// — note the TWO trailing spaces between the dwidth pad and rule).
|
|
1637
1646
|
if (border === 2 || border === 3) {
|
|
1638
|
-
out +=
|
|
1647
|
+
out += " ".repeat(dwidth) + " " + vrule;
|
|
1639
1648
|
}
|
|
1640
1649
|
}
|
|
1641
|
-
out +=
|
|
1650
|
+
out += "\n";
|
|
1642
1651
|
}
|
|
1643
1652
|
return out;
|
|
1644
1653
|
};
|
|
@@ -1661,9 +1670,9 @@ const horizontalTotalWidth = (rs, topt) => {
|
|
|
1661
1670
|
return overhead + widths.reduce((a, b) => a + b, 0);
|
|
1662
1671
|
};
|
|
1663
1672
|
const chooseExpanded = (rs, topt) => {
|
|
1664
|
-
if (topt.expanded ===
|
|
1673
|
+
if (topt.expanded === "on")
|
|
1665
1674
|
return true;
|
|
1666
|
-
if (topt.expanded ===
|
|
1675
|
+
if (topt.expanded === "auto") {
|
|
1667
1676
|
const maxColumns = topt.columns > 0 ? topt.columns : topt.envColumns;
|
|
1668
1677
|
if (maxColumns <= 0)
|
|
1669
1678
|
return false;
|
|
@@ -1675,10 +1684,10 @@ const chooseExpanded = (rs, topt) => {
|
|
|
1675
1684
|
// Public printer.
|
|
1676
1685
|
// ---------------------------------------------------------------------------
|
|
1677
1686
|
export const alignedPrinter = {
|
|
1678
|
-
format:
|
|
1687
|
+
format: "aligned",
|
|
1679
1688
|
printQuery(rs, opts, out) {
|
|
1680
1689
|
const expanded = chooseExpanded(rs, opts.topt);
|
|
1681
|
-
const wrapped = opts.topt.format ===
|
|
1690
|
+
const wrapped = opts.topt.format === "wrapped";
|
|
1682
1691
|
let text;
|
|
1683
1692
|
if (expanded) {
|
|
1684
1693
|
text = renderVertical(rs, opts);
|
|
@@ -1703,7 +1712,7 @@ const renderEmpty = (rs, opts) => {
|
|
|
1703
1712
|
const glyphs = glyphsFor(topt.unicodeBorderLineStyle);
|
|
1704
1713
|
const headerCells = rs.fields.map((f) => formatCell(f.name));
|
|
1705
1714
|
const widths = headerCells.map((c) => c.width);
|
|
1706
|
-
let out =
|
|
1715
|
+
let out = "";
|
|
1707
1716
|
if (!tuplesOnly && topt.title) {
|
|
1708
1717
|
// Centre the title above the table, matching the horizontal-path
|
|
1709
1718
|
// logic (and upstream `print_aligned_text` `width_total` formula).
|
|
@@ -1717,33 +1726,33 @@ const renderEmpty = (rs, opts) => {
|
|
|
1717
1726
|
const widthTotal = overhead + widths.reduce((a, b) => a + b, 0);
|
|
1718
1727
|
const titleW = displayWidth(topt.title);
|
|
1719
1728
|
if (titleW >= widthTotal) {
|
|
1720
|
-
out += topt.title +
|
|
1729
|
+
out += topt.title + "\n";
|
|
1721
1730
|
}
|
|
1722
1731
|
else {
|
|
1723
|
-
out +=
|
|
1732
|
+
out += " ".repeat((widthTotal - titleW) >> 1) + topt.title + "\n";
|
|
1724
1733
|
}
|
|
1725
1734
|
}
|
|
1726
1735
|
if (!tuplesOnly && (border === 2 || border === 3)) {
|
|
1727
|
-
out += buildRule(widths, border, glyphs,
|
|
1736
|
+
out += buildRule(widths, border, glyphs, "top") + "\n";
|
|
1728
1737
|
}
|
|
1729
1738
|
if (!tuplesOnly) {
|
|
1730
|
-
const noneStates = headerCells.map(() =>
|
|
1739
|
+
const noneStates = headerCells.map(() => "none");
|
|
1731
1740
|
out +=
|
|
1732
|
-
renderHeaderLine(headerCells.map((c) => c.lines[0] ??
|
|
1733
|
-
out += buildRule(widths, border, glyphs,
|
|
1741
|
+
renderHeaderLine(headerCells.map((c) => c.lines[0] ?? ""), widths, border, glyphs, noneStates, noneStates, true) + "\n";
|
|
1742
|
+
out += buildRule(widths, border, glyphs, "middle") + "\n";
|
|
1734
1743
|
}
|
|
1735
1744
|
if (!tuplesOnly && (border === 2 || border === 3)) {
|
|
1736
|
-
out += buildRule(widths, border, glyphs,
|
|
1745
|
+
out += buildRule(widths, border, glyphs, "bottom") + "\n";
|
|
1737
1746
|
}
|
|
1738
1747
|
// User footers suppress the default `(0 rows)` row counter — mirrors
|
|
1739
1748
|
// upstream `footers_with_default` (print.c lines 397-413).
|
|
1740
1749
|
const hasUserFooters = !!opts.footers && opts.footers.length > 0;
|
|
1741
1750
|
if (!tuplesOnly && topt.defaultFooter && !hasUserFooters) {
|
|
1742
|
-
out +=
|
|
1751
|
+
out += "(0 rows)\n";
|
|
1743
1752
|
}
|
|
1744
1753
|
if (!tuplesOnly && opts.footers) {
|
|
1745
1754
|
for (const f of opts.footers)
|
|
1746
|
-
out += f +
|
|
1755
|
+
out += f + "\n";
|
|
1747
1756
|
}
|
|
1748
1757
|
// Trailing blank line between query results, mirroring the horizontal /
|
|
1749
1758
|
// vertical code paths (which append `\n` via `printTableCleanup`).
|
|
@@ -1751,6 +1760,6 @@ const renderEmpty = (rs, opts) => {
|
|
|
1751
1760
|
// multiple back-to-back `\d`-family queries run together. Emitted
|
|
1752
1761
|
// unconditionally (matches `fputc('\n', fout)` on print.c line 1196 /
|
|
1753
1762
|
// 1821 — both are outside the `!opt_tuples_only` guard).
|
|
1754
|
-
out +=
|
|
1763
|
+
out += "\n";
|
|
1755
1764
|
return out;
|
|
1756
1765
|
};
|