From ef98177e5831f6aae320c6ceb7bfb7f4b6019fac Mon Sep 17 00:00:00 2001 From: luxick Date: Fri, 25 Sep 2026 09:38:34 +0200 Subject: [PATCH] Improve special char and emoji handling in tables --- assets/editor/tables.js | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/assets/editor/tables.js b/assets/editor/tables.js index 785eb44..49c54e6 100644 --- a/assets/editor/tables.js +++ b/assets/editor/tables.js @@ -6,22 +6,34 @@ window.EditorTables = (function () { return s; } + var segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' }); + + // Graphemes rendered two columns wide: emoji-presentation characters, anything + // forced to emoji presentation via VS16, and East Asian wide/fullwidth ranges. + var WIDE = /\p{Emoji_Presentation}|️|[ᄀ-ᅟ⺀-〾ぁ-㏿㐀-䶿一-鿿ꀀ-꓏가-힣豈-﫿︰-﹏＀-⦆¢-₩]/u; + var ZERO = /^[\p{Mn}\p{Me}\p{Cf}]+$/u; + + function displayWidth(s) { + var w = 0; + Array.from(segmenter.segment(s), function (seg) { + var g = seg.segment; + if (!ZERO.test(g)) w += WIDE.test(g) ? 2 : 1; + }); + return w; + } + function padLeft(s, w) { - while (s.length < w) s = ' ' + s; - return s; + return repeat(' ', w - displayWidth(s)) + s; } function padRight(s, w) { - while (s.length < w) s += ' '; - return s; + return s + repeat(' ', w - displayWidth(s)); } function padCenter(s, w) { - while (s.length < w) { - s = s + ' '; - if (s.length < w) s = ' ' + s; - } - return s; + var total = w - displayWidth(s); + var left = Math.floor(total / 2); + return repeat(' ', left) + s + repeat(' ', total - left); } function parseTableRow(line) { @@ -101,7 +113,8 @@ window.EditorTables = (function () { var max = 3; for (var r = 0; r < rows.length; r++) { if (r === sepIndex) continue; - if (rows[r][c].length > max) max = rows[r][c].length; + var len = displayWidth(rows[r][c]); + if (len > max) max = len; } widths.push(max); }