From 2c7d36939551c1c230496d8f7d41b78fc2f70a20 Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Mon, 4 Mar 2019 22:03:46 +0300 Subject: [PATCH 1/4] improvement on handling of invisisble sequences in trim mode --- index.js | 27 +++++++++++++++++++++++++-- test.js | 3 +++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 9bf954d..33d4fca 100755 --- a/index.js +++ b/index.js @@ -60,6 +60,26 @@ const wrapWord = (rows, word, columns) => { } }; +// Trims spaces from a string ignoring invisible sequences +const stringVisibleTrimSpaces = str => { + const words = str.split(' '); + let first = 0; + let last = words.length; + while (first < last) { + if (stringWidth(words[first]) > 0) { + break; + } + first++; + } + while (last > first) { + if (stringWidth(words[last - 1]) > 0) { + break; + } + last--; + } + return words.slice(0, first).join('') + words.slice(first, last).join(' ') + words.slice(last, words.length).join(''); +}; + // The wrap-ansi module can be invoked // in either 'hard' or 'soft' wrap mode // @@ -77,7 +97,7 @@ const exec = (string, columns, options = {}) => { let escapeCode; const lengths = wordLengths(string); - const rows = ['']; + let rows = ['']; for (const [index, word] of string.split(' ').entries()) { if (options.trim !== false) { @@ -128,7 +148,10 @@ const exec = (string, columns, options = {}) => { rows[rows.length - 1] += word; } - pre = rows.map(row => options.trim === false ? row : row.trim()).join('\n'); + if (options.trim !== false) { + rows = rows.map(stringVisibleTrimSpaces); + } + pre = rows.join('\n'); for (const [index, character] of [...pre].entries()) { ret += character; diff --git a/test.js b/test.js index bdca69f..ea5fe42 100755 --- a/test.js +++ b/test.js @@ -121,6 +121,9 @@ test('#24, trims leading and trailing whitespace only on actual wrapped lines an t.is(wrapAnsi(' foo bar ', 6), 'foo\nbar'); t.is(wrapAnsi(' foo bar ', 42), 'foo bar'); t.is(wrapAnsi(' foo bar ', 42, {trim: false}), ' foo bar '); + t.is(wrapAnsi(chalk.blue(' foo bar '), 42, {trim: false}), chalk.blue(' foo bar ')); + t.is(wrapAnsi(chalk.blue(' foo bar '), 6), chalk.blue('foo\nbar')); + t.is(wrapAnsi(chalk.blue(' foo bar '), 42), chalk.blue('foo bar')); }); test.failing('#24, trims leading and trailing whitespace inside a color block only on actual wrapped lines and only with trimming', t => { From 1964c902acad6c14915aac0375f1a763c05e6bb7 Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Mon, 4 Mar 2019 22:16:19 +0300 Subject: [PATCH 2/4] updated for new linter --- index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/index.js b/index.js index 33d4fca..0665b29 100755 --- a/index.js +++ b/index.js @@ -69,14 +69,18 @@ const stringVisibleTrimSpaces = str => { if (stringWidth(words[first]) > 0) { break; } + first++; } + while (last > first) { if (stringWidth(words[last - 1]) > 0) { break; } + last--; } + return words.slice(0, first).join('') + words.slice(first, last).join(' ') + words.slice(last, words.length).join(''); }; @@ -151,6 +155,7 @@ const exec = (string, columns, options = {}) => { if (options.trim !== false) { rows = rows.map(stringVisibleTrimSpaces); } + pre = rows.join('\n'); for (const [index, character] of [...pre].entries()) { From 480780303c669099d386474acd658ab3192434a4 Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Mon, 4 Mar 2019 22:26:27 +0300 Subject: [PATCH 3/4] dirty rebase --- test.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test.js b/test.js index ea5fe42..4e489ae 100755 --- a/test.js +++ b/test.js @@ -121,12 +121,9 @@ test('#24, trims leading and trailing whitespace only on actual wrapped lines an t.is(wrapAnsi(' foo bar ', 6), 'foo\nbar'); t.is(wrapAnsi(' foo bar ', 42), 'foo bar'); t.is(wrapAnsi(' foo bar ', 42, {trim: false}), ' foo bar '); - t.is(wrapAnsi(chalk.blue(' foo bar '), 42, {trim: false}), chalk.blue(' foo bar ')); - t.is(wrapAnsi(chalk.blue(' foo bar '), 6), chalk.blue('foo\nbar')); - t.is(wrapAnsi(chalk.blue(' foo bar '), 42), chalk.blue('foo bar')); }); -test.failing('#24, trims leading and trailing whitespace inside a color block only on actual wrapped lines and only with trimming', t => { +test('#24, trims leading and trailing whitespace inside a color block only on actual wrapped lines and only with trimming', t => { t.is(wrapAnsi(chalk.blue(' foo bar '), 6), chalk.blue('foo\nbar')); t.is(wrapAnsi(chalk.blue(' foo bar '), 42), chalk.blue('foo bar')); t.is(wrapAnsi(chalk.blue(' foo bar '), 42, {trim: false}), chalk.blue(' foo bar ')); From 1f10a82d614451e6fa2f86311a671900999a9897 Mon Sep 17 00:00:00 2001 From: Yanis Benson Date: Tue, 5 Mar 2019 11:41:26 +0300 Subject: [PATCH 4/4] better handling of whitespace at the end of line --- index.js | 10 ++++++---- test.js | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 0665b29..efc8ac0 100755 --- a/index.js +++ b/index.js @@ -111,14 +111,16 @@ const exec = (string, columns, options = {}) => { let rowLength = stringWidth(rows[rows.length - 1]); if (index !== 0) { - if (rowLength === columns && (options.wordWrap === false || options.trim === false)) { + if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) { // If we start with a new word but the current row length equals the length of the columns, add a new row rows.push(''); rowLength = 0; } - rows[rows.length - 1] += ' '; - rowLength++; + if (rowLength > 0 || options.trim === false) { + rows[rows.length - 1] += ' '; + rowLength++; + } } // In 'hard' wrap mode, the length of a line is @@ -135,7 +137,7 @@ const exec = (string, columns, options = {}) => { continue; } - if (rowLength + lengths[index] > columns && rowLength > 0) { + if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) { if (options.wordWrap === false && rowLength < columns) { wrapWord(rows, word, columns); continue; diff --git a/test.js b/test.js index 4e489ae..a2f34b1 100755 --- a/test.js +++ b/test.js @@ -118,6 +118,7 @@ test('#23, properly wraps whitespace with no trimming', t => { }); test('#24, trims leading and trailing whitespace only on actual wrapped lines and only with trimming', t => { + t.is(wrapAnsi(' foo bar ', 3), 'foo\nbar'); t.is(wrapAnsi(' foo bar ', 6), 'foo\nbar'); t.is(wrapAnsi(' foo bar ', 42), 'foo bar'); t.is(wrapAnsi(' foo bar ', 42, {trim: false}), ' foo bar ');