* renderStringLength(): Account for ESC[<N>C "forward" ESC seq
* Use string util renderStringLength() in word wrap * Hopefully resolve all issues with renderSubstr() * Fix width issue in message list
This commit is contained in:
parent
f7c21baa52
commit
d621fa9566
|
@ -291,6 +291,7 @@ function getValue(obj, path) {
|
||||||
module.exports = function format(fmt, obj) {
|
module.exports = function format(fmt, obj) {
|
||||||
|
|
||||||
const re = REGEXP_BASIC_FORMAT;
|
const re = REGEXP_BASIC_FORMAT;
|
||||||
|
re.lastIndex = 0; // reset from prev
|
||||||
|
|
||||||
let match;
|
let match;
|
||||||
let pos;
|
let pos;
|
||||||
|
|
|
@ -195,30 +195,37 @@ function stringFromNullTermBuffer(buf, encoding) {
|
||||||
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8');
|
return iconv.decode(buf.slice(0, nullPos), encoding || 'utf-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
// :TODO: Add other codes from ansi_escape_parser
|
const PIPE_REGEXP = /(\|[A-Z\d]{2})/g;
|
||||||
const ANSI_REGEXP = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
const ANSI_REGEXP = /[\u001b\u009b][[()#;?]*([0-9]{1,4}(?:;[0-9]{0,4})*)?([0-9A-ORZcf-npqrsuy=><])/g;
|
||||||
const PIPE_REGEXP = /\|[A-Z\d]{2}/g;
|
const ANSI_OR_PIPE_REGEXP = new RegExp(PIPE_REGEXP.source + '|' + ANSI_REGEXP.source, 'g');
|
||||||
const ANSI_OR_PIPE_REGEXP = new RegExp(ANSI_REGEXP.source + '|' + PIPE_REGEXP.source, 'g');
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Similar to substr() but works with ANSI/Pipe code strings
|
// Similar to substr() but works with ANSI/Pipe code strings
|
||||||
//
|
//
|
||||||
function renderSubstr(str, start, length) {
|
function renderSubstr(str, start, length) {
|
||||||
start = start || 0;
|
// shortcut for empty strings
|
||||||
length = Math.max(0, (length || str.length - start) - 1);
|
if(0 === str.length) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
const re = ANSI_REGEXP;
|
start = start || 0;
|
||||||
let pos;
|
length = length || str.length - start;
|
||||||
|
|
||||||
|
const re = ANSI_OR_PIPE_REGEXP;
|
||||||
|
re.lastIndex = 0; // we recycle the obj; must reset!
|
||||||
|
|
||||||
|
let pos = 0;
|
||||||
let match;
|
let match;
|
||||||
let out = '';
|
let out = '';
|
||||||
let renderLen = 0;
|
let renderLen = 0;
|
||||||
|
let s;
|
||||||
do {
|
do {
|
||||||
pos = re.lastIndex;
|
pos = re.lastIndex;
|
||||||
match = re.exec(str);
|
match = re.exec(str);
|
||||||
|
|
||||||
if(match) {
|
if(match) {
|
||||||
if(match.index > pos) {
|
if(match.index > pos) {
|
||||||
const s = str.slice(pos + start, match.index - (Math.min(0, length - renderLen)));
|
s = str.slice(pos + start, Math.min(match.index, pos + (length - renderLen)));
|
||||||
start = 0; // start offset applies only once
|
start = 0; // start offset applies only once
|
||||||
out += s;
|
out += s;
|
||||||
renderLen += s.length;
|
renderLen += s.length;
|
||||||
|
@ -230,19 +237,53 @@ function renderSubstr(str, start, length) {
|
||||||
|
|
||||||
// remainder
|
// remainder
|
||||||
if(pos + start < str.length && renderLen < length) {
|
if(pos + start < str.length && renderLen < length) {
|
||||||
out += str.slice(pos + start, pos + Math.max(0, length - renderLen));
|
out += str.slice(pos + start, (pos + start + (length - renderLen)));
|
||||||
|
//out += str.slice(pos + start, Math.max(1, pos + (length - renderLen - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Method to return the "rendered" length taking into account
|
// Method to return the "rendered" length taking into account Pipe and ANSI color codes.
|
||||||
// Pipe and ANSI color codes. Note that currently ANSI *movement*
|
|
||||||
// codes are not considred!
|
|
||||||
//
|
//
|
||||||
function renderStringLength(str) {
|
// We additionally account for ANSI *forward* movement ESC sequences
|
||||||
return str.replace(ANSI_OR_PIPE_REGEXP, '').length;
|
// in the form of ESC[<N>C where <N> is the "go forward" character count.
|
||||||
|
//
|
||||||
|
// See also https://github.com/chalk/ansi-regex/blob/master/index.js
|
||||||
|
//
|
||||||
|
function renderStringLength(s) {
|
||||||
|
let m;
|
||||||
|
let pos;
|
||||||
|
let len = 0;
|
||||||
|
|
||||||
|
const re = ANSI_OR_PIPE_REGEXP;
|
||||||
|
re.lastIndex = 0; // we recycle the rege; reset
|
||||||
|
|
||||||
|
//
|
||||||
|
// Loop counting only literal (non-control) sequences
|
||||||
|
// paying special attention to ESC[<N>C which means forward <N>
|
||||||
|
//
|
||||||
|
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[<N>C is foward/right
|
||||||
|
len += parseInt(m[2], 10) || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(0 !== re.lastIndex);
|
||||||
|
|
||||||
|
if(pos < s.length) {
|
||||||
|
len += s.slice(pos).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,7 +308,7 @@ function cleanControlCodes(input) {
|
||||||
pos = REGEXP_ANSI_CONTROL_CODES.lastIndex;
|
pos = REGEXP_ANSI_CONTROL_CODES.lastIndex;
|
||||||
m = REGEXP_ANSI_CONTROL_CODES.exec(input);
|
m = REGEXP_ANSI_CONTROL_CODES.exec(input);
|
||||||
|
|
||||||
if(null !== m) {
|
if(m) {
|
||||||
if(m.index > pos) {
|
if(m.index > pos) {
|
||||||
cleaned += input.slice(pos, m.index);
|
cleaned += input.slice(pos, m.index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
/* jslint node: true */
|
/* jslint node: true */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
const renderStringLength = require('./string_util.js').renderStringLength;
|
||||||
|
|
||||||
exports.wordWrapText = wordWrapText2;
|
exports.wordWrapText = wordWrapText2;
|
||||||
|
|
||||||
|
@ -15,12 +16,14 @@ const SPACE_CHARS = [
|
||||||
|
|
||||||
const REGEXP_WORD_WRAP = new RegExp(`\t|[${SPACE_CHARS.join('')}]`, 'g');
|
const REGEXP_WORD_WRAP = new RegExp(`\t|[${SPACE_CHARS.join('')}]`, 'g');
|
||||||
|
|
||||||
|
/*
|
||||||
//
|
//
|
||||||
// ANSI & pipe codes we indend to strip
|
// ANSI & pipe codes we indend to strip
|
||||||
//
|
//
|
||||||
// See also https://github.com/chalk/ansi-regex/blob/master/index.js
|
// See also https://github.com/chalk/ansi-regex/blob/master/index.js
|
||||||
//
|
//
|
||||||
// :TODO: Consolidate this, regexp's in ansi_escape_parser, and strutil. Need more complete set that includes common standads, bansi, and cterm.txt
|
// :TODO: Consolidate this, regexp's in ansi_escape_parser, and strutil. Need more complete set that includes common standads, bansi, and cterm.txt
|
||||||
|
// renderStringLength() from strUtil does not account for ESC[<N>C (e.g. go forward)
|
||||||
const REGEXP_CONTROL_CODES = /(\|[\d]{2})|(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g;
|
const REGEXP_CONTROL_CODES = /(\|[\d]{2})|(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g;
|
||||||
|
|
||||||
function getRenderLength(s) {
|
function getRenderLength(s) {
|
||||||
|
@ -28,9 +31,11 @@ function getRenderLength(s) {
|
||||||
let pos;
|
let pos;
|
||||||
let len = 0;
|
let len = 0;
|
||||||
|
|
||||||
|
REGEXP_CONTROL_CODES.lastIndex = 0; // reset
|
||||||
|
|
||||||
//
|
//
|
||||||
// Loop counting only literal (non-control) sequences
|
// Loop counting only literal (non-control) sequences
|
||||||
// paying special attention to ESC[<N>C which means foward <N>
|
// paying special attention to ESC[<N>C which means forward <N>
|
||||||
//
|
//
|
||||||
do {
|
do {
|
||||||
pos = REGEXP_CONTROL_CODES.lastIndex;
|
pos = REGEXP_CONTROL_CODES.lastIndex;
|
||||||
|
@ -53,6 +58,7 @@ function getRenderLength(s) {
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
function wordWrapText2(text, options) {
|
function wordWrapText2(text, options) {
|
||||||
assert(_.isObject(options));
|
assert(_.isObject(options));
|
||||||
|
@ -79,7 +85,7 @@ function wordWrapText2(text, options) {
|
||||||
|
|
||||||
function appendWord() {
|
function appendWord() {
|
||||||
word.match(REGEXP_GOBBLE).forEach( w => {
|
word.match(REGEXP_GOBBLE).forEach( w => {
|
||||||
renderLen = getRenderLength(w);
|
renderLen = renderStringLength(w);
|
||||||
|
|
||||||
if(result.renderLen[i] + renderLen > options.width) {
|
if(result.renderLen[i] + renderLen > options.width) {
|
||||||
if(0 === i) {
|
if(0 === i) {
|
||||||
|
|
|
@ -206,8 +206,8 @@
|
||||||
|
|
||||||
messageAreaMessageList: {
|
messageAreaMessageList: {
|
||||||
config: {
|
config: {
|
||||||
listFormat: "|00|15{msgNum:>4} |03{subject:<29.29} |11{fromUserName:<20.20} |03{ts} |01|31{newIndicator}"
|
listFormat: "|00|15{msgNum:>4} |03{subject:<28.27} |11{fromUserName:<20.20} |03{ts} |01|31{newIndicator}"
|
||||||
focusListFormat: "|00|19|15{msgNum:>4} {subject:<29.29} {fromUserName:<20.20} {ts} {newIndicator}"
|
focusListFormat: "|00|19|15{msgNum:>4} {subject:<28.27} {fromUserName:<20.20} {ts} {newIndicator}"
|
||||||
dateTimeFormat: ddd MMM Do
|
dateTimeFormat: ddd MMM Do
|
||||||
}
|
}
|
||||||
mci: {
|
mci: {
|
||||||
|
@ -260,8 +260,8 @@
|
||||||
|
|
||||||
mailMenuInbox: {
|
mailMenuInbox: {
|
||||||
config: {
|
config: {
|
||||||
listFormat: "|00|15{msgNum:>4} |03{subject:<29.29} |11{fromUserName:<20.20} |03{ts} |01|31{newIndicator}"
|
listFormat: "|00|15{msgNum:>4} |03{subject:<28.27} |11{fromUserName:<20.20} |03{ts} |01|31{newIndicator}"
|
||||||
focusListFormat: "|00|19|15{msgNum:>4} {subject:<29.29} {fromUserName:<20.20} {ts} {newIndicator}"
|
focusListFormat: "|00|19|15{msgNum:>4} {subject:<28.27} {fromUserName:<20.20} {ts} {newIndicator}"
|
||||||
dateTimeFormat: ddd MMM Do
|
dateTimeFormat: ddd MMM Do
|
||||||
}
|
}
|
||||||
mci: {
|
mci: {
|
||||||
|
@ -467,8 +467,8 @@
|
||||||
|
|
||||||
newScanMessageList: {
|
newScanMessageList: {
|
||||||
config: {
|
config: {
|
||||||
listFormat: "|00|15 {msgNum:<5.5}|03{subject:<29.29} |15{fromUserName:<20.20} {ts}"
|
listFormat: "|00|15 {msgNum:<5.5}|03{subject:<28.27} |15{fromUserName:<20.20} {ts}"
|
||||||
focusListFormat: "|00|19> |15{msgNum:<5.5}{subject:<29.29} {fromUserName:<20.20} {ts}"
|
focusListFormat: "|00|19> |15{msgNum:<5.5}{subject:<28.27} {fromUserName:<20.20} {ts}"
|
||||||
dateTimeFormat: ddd MMM Do
|
dateTimeFormat: ddd MMM Do
|
||||||
}
|
}
|
||||||
mci: {
|
mci: {
|
||||||
|
|
Loading…
Reference in New Issue