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