Skip to content

Commit

Permalink
console: use getStringWidth() for character width calculation
Browse files Browse the repository at this point in the history
This is more accurate for displayed full-width characters
(e.g. CJK ones) and makes the calculations match the ones we
use in the readline module.

Fixes: #29299

PR-URL: #29300
Reviewed-By: Gus Caplan <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: James M Snell <[email protected]>
  • Loading branch information
addaleax authored and antsmartian committed Sep 2, 2019
1 parent 2cc757f commit 9e23eef
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 10 deletions.
14 changes: 4 additions & 10 deletions lib/internal/cli_table.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

const { Math, ObjectPrototype } = primordials;

const { Buffer } = require('buffer');
const { removeColors } = require('internal/util');
const { getStringWidth } = require('internal/readline/utils');

// The use of Unicode characters below is the only non-comment use of non-ASCII
// Unicode characters in Node.js built-in modules. If they are ever removed or
Expand All @@ -29,16 +28,11 @@ const tableChars = {
/* eslint-enable node-core/non-ascii-character */
};

const countSymbols = (string) => {
const normalized = removeColors(string).normalize('NFC');
return Buffer.from(normalized, 'UCS-2').byteLength / 2;
};

const renderRow = (row, columnWidths) => {
let out = tableChars.left;
for (var i = 0; i < row.length; i++) {
const cell = row[i];
const len = countSymbols(cell);
const len = getStringWidth(cell);
const needed = (columnWidths[i] - len) / 2;
// round(needed) + ceil(needed) will always add up to the amount
// of spaces we need while also left justifying the output.
Expand All @@ -52,7 +46,7 @@ const renderRow = (row, columnWidths) => {

const table = (head, columns) => {
const rows = [];
const columnWidths = head.map((h) => countSymbols(h));
const columnWidths = head.map((h) => getStringWidth(h));
const longestColumn = columns.reduce((n, a) => Math.max(n, a.length), 0);

for (var i = 0; i < head.length; i++) {
Expand All @@ -63,7 +57,7 @@ const table = (head, columns) => {
const value = rows[j][i] =
ObjectPrototype.hasOwnProperty(column, j) ? column[j] : '';
const width = columnWidths[i] || 0;
const counted = countSymbols(value);
const counted = getStringWidth(value);
columnWidths[i] = Math.max(width, counted);
}
}
Expand Down
18 changes: 18 additions & 0 deletions test/parallel/test-console-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,21 @@ test([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], `
└─────────┴──${line}β”€β”€β”˜
`);
}

test({ foo: 'οΏ₯', bar: 'Β₯' }, `
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ (index) β”‚ Values β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ foo β”‚ 'οΏ₯' β”‚
β”‚ bar β”‚ 'Β₯' β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜
`);

test({ foo: 'δ½ ε₯½', bar: 'hello' }, `
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ (index) β”‚ Values β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ foo β”‚ 'δ½ ε₯½' β”‚
β”‚ bar β”‚ 'hello' β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
`);

0 comments on commit 9e23eef

Please sign in to comment.