From 862031c57f3077ea041c118f0e9b451a2dd01712 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 2 Jan 2021 15:04:16 -0700 Subject: [PATCH] Bug fix: Word wrap when dealing with pipe codes Bug fix: Assumed FES styleizers --- core/fse.js | 2 +- core/string_util.js | 39 +++++++++++++++++++++++++++++++++++++-- core/word_wrap.js | 10 ++++++---- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/core/fse.js b/core/fse.js index c085ef2c..9fa0e97b 100644 --- a/core/fse.js +++ b/core/fse.js @@ -442,7 +442,7 @@ exports.FullScreenEditorModule = exports.getModule = class FullScreenEditorModul style = [ style ]; } while (style.length < len) { - style.push(style); + style.push(style[0]); } return style; }; diff --git a/core/string_util.js b/core/string_util.js index 6887275e..407c06c5 100644 --- a/core/string_util.js +++ b/core/string_util.js @@ -20,6 +20,7 @@ exports.stringFromNullTermBuffer = stringFromNullTermBuffer; exports.stringToNullTermBuffer = stringToNullTermBuffer; exports.renderSubstr = renderSubstr; exports.renderStringLength = renderStringLength; +exports.ansiRenderStringLength = ansiRenderStringLength; exports.formatByteSizeAbbr = formatByteSizeAbbr; exports.formatByteSize = formatByteSize; exports.formatCountAbbr = formatCountAbbr; @@ -297,7 +298,7 @@ function renderStringLength(s) { let len = 0; const re = ANSI_OR_PIPE_REGEXP; - re.lastIndex = 0; // we recycle the rege; reset + re.lastIndex = 0; // we recycle the regex; reset // // Loop counting only literal (non-control) sequences @@ -312,7 +313,41 @@ function renderStringLength(s) { len += s.slice(pos, m.index).length; } - if('C' === m[3]) { // ESC[C is foward/right + if('C' === m[3]) { // ESC[C is forward/right + len += parseInt(m[2], 10) || 0; + } + } + } while(0 !== re.lastIndex); + + if(pos < s.length) { + len += s.slice(pos).length; + } + + return len; +} + +// Like renderStringLength() but ANSI only (no pipe codes accounted for) +function ansiRenderStringLength(s) { + let m; + let pos; + let len = 0; + + const re = ANSI.getFullMatchRegExp(); + + // + // Loop counting only literal (non-control) sequences + // paying special attention to ESC[C which means forward + // + do { + pos = re.lastIndex; + m = re.exec(s); + + if(m) { + if(m.index > pos) { + len += s.slice(pos, m.index).length; + } + + if('C' === m[3]) { // ESC[C is forward/right len += parseInt(m[2], 10) || 0; } } diff --git a/core/word_wrap.js b/core/word_wrap.js index 94773283..afeca1f8 100644 --- a/core/word_wrap.js +++ b/core/word_wrap.js @@ -1,7 +1,9 @@ /* jslint node: true */ 'use strict'; -const renderStringLength = require('./string_util.js').renderStringLength; +const { + ansiRenderStringLength, +} = require('./string_util'); // deps const assert = require('assert'); @@ -28,7 +30,7 @@ function wordWrapText(text, options) { //const REGEXP_GOBBLE = new RegExp(`.{0,${options.width}}`, 'g'); // - // For a given word, match 0->options.width chars -- alwasy include a full trailing ESC + // For a given word, match 0->options.width chars -- always include a full trailing ESC // sequence if present! // // :TODO: Need to create ansi.getMatchRegex or something - this is used all over @@ -49,7 +51,7 @@ function wordWrapText(text, options) { function appendWord() { word.match(REGEXP_GOBBLE).forEach( w => { - renderLen = renderStringLength(w); + renderLen = ansiRenderStringLength(w); if(result.renderLen[i] + renderLen > options.width) { if(0 === i) { @@ -70,7 +72,7 @@ function wordWrapText(text, options) { // // * Sublime Text 3 for example considers spaces after a word // part of said word. For example, "word " would be wraped - // in it's entirity. + // in it's entirety. // // * Tabs in Sublime Text 3 are also treated as a word, so, e.g. // "\t" may resolve to " " and must fit within the space.