* Better isAnsi() regex

* Handle word wrap within ANSI on plain text lines
This commit is contained in:
Bryan Ashby 2017-08-20 20:40:36 -06:00
parent fa465613a1
commit bf8552e24f
1 changed files with 49 additions and 15 deletions

View File

@ -8,6 +8,7 @@ const ANSI = require('./ansi_term.js');
// deps
const iconv = require('iconv-lite');
const _ = require('lodash');
exports.stylizeString = stylizeString;
exports.pad = pad;
@ -23,6 +24,7 @@ exports.formatByteSize = formatByteSize;
exports.cleanControlCodes = cleanControlCodes;
exports.prepAnsi = prepAnsi;
exports.isAnsi = isAnsi;
exports.isAnsiLine = isAnsiLine;
exports.splitTextAtTerms = splitTextAtTerms;
// :TODO: create Unicode verison of this
@ -380,13 +382,12 @@ function prepAnsi(input, options, cb) {
return cb(null, '');
}
options.termWidth = options.termWidth || 80;
options.termHeight = options.termHeight || 25;
options.cols = options.cols || options.termWidth || 80;
options.rows = options.rows || options.termHeight || 'auto';
options.startCol = options.startCol || 1;
options.termWidth = options.termWidth || 80;
options.termHeight = options.termHeight || 25;
options.cols = options.cols || options.termWidth || 80;
options.rows = options.rows || options.termHeight || 'auto';
options.startCol = options.startCol || 1;
options.preserveTextLines = options.preserveTextLines || false;
const canvas = Array.from( { length : 'auto' === options.rows ? 25 : options.rows }, () => Array.from( { length : options.cols}, () => new Object() ) );
const parser = new ANSIEscapeParser( { termHeight : options.termHeight, termWidth : options.termWidth } );
@ -463,24 +464,52 @@ function prepAnsi(input, options, cb) {
parser.on('complete', () => {
let output = '';
let lastSgr = '';
let line;
let textState = 'new';
canvas.slice(0, lastRow + 1).forEach(row => {
const lastCol = getLastPopulatedColumn(row) + 1;
let i;
line = '';
for(i = 0; i < lastCol; ++i) {
const col = row[i];
if(col.sgr) {
lastSgr = col.sgr;
}
output += `${col.sgr || ''}${col.char || ' '}`;
line += `${col.sgr || ''}${col.char || ' '}`;
}
if(i < row.length) {
output += `${ANSI.blackBG()}${row.slice(i).map( () => ' ').join('')}${lastSgr}`;
}
if(options.preserveTextLines && !isAnsiLine(line)) {
switch(textState) {
case 'new' :
line = _.trimStart(line);
if(line) {
textState = 'cont';
}
break;
if(options.startCol + options.cols < options.termWidth || options.forceLineTerm) {
output += '\r\n';
case 'cont' :
line = ' ' + line;
break;
}
output += line;
} else {
if('cont' === textState) {
output += '\r\n';
}
textState = 'new';
output += line;
if(i < row.length) {
output += `${ANSI.blackBG()}${row.slice(i).map( () => ' ').join('')}${lastSgr}`;
}
if(options.startCol + options.cols < options.termWidth || options.forceLineTerm) {
output += '\r\n';
}
}
});
@ -490,6 +519,10 @@ function prepAnsi(input, options, cb) {
parser.parse(input);
}
function isAnsiLine(line) {
return isAnsi(line);// || renderStringLength(line) < line.length;
}
function isAnsi(input) {
//
// * ANSI found - limited, just colors
@ -510,8 +543,9 @@ function isAnsi(input) {
});
*/
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[0-9]{1,3}[ABCDEFGJKLMSTrsuHfhlm]/g;
return ( input.match(ANSI_DET_REGEXP) || [] ).length > 4; // :TODO: do this reasonably, e.g. a percent or soemthing
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[\?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g;
const m = input.match(ANSI_DET_REGEXP) || [];
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing
}
function splitTextAtTerms(s) {