From e4f13e37c5da6a5bf7abe6d94b8ff42bf27bff0f Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 25 Aug 2019 01:39:54 +0200 Subject: [PATCH] console: use getStringWidth() for character width calculation 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: https://github.com/nodejs/node/issues/29299 --- lib/internal/cli_table.js | 14 ++++---------- test/parallel/test-console-table.js | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/internal/cli_table.js b/lib/internal/cli_table.js index 6e9a6bdbc9021a..aaa094e6a5d25f 100644 --- a/lib/internal/cli_table.js +++ b/lib/internal/cli_table.js @@ -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 @@ -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. @@ -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++) { @@ -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); } } diff --git a/test/parallel/test-console-table.js b/test/parallel/test-console-table.js index eba7ba610c7393..706cd20ad1f62a 100644 --- a/test/parallel/test-console-table.js +++ b/test/parallel/test-console-table.js @@ -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' │ +└─────────┴─────────┘ +`);