Major improvements to quote builder for pre-formatted text/etc.

This commit is contained in:
Bryan Ashby 2017-08-27 20:08:13 -06:00
parent 1c736debf3
commit 1bad0de5c1
2 changed files with 77 additions and 13 deletions

View File

@ -10,7 +10,7 @@ const Errors = require('./enig_error.js').Errors;
const ANSI = require('./ansi_term.js');
const {
prepAnsi, isAnsi,
prepAnsi, isAnsi, isFormattedLine,
splitTextAtTerms,
renderSubstr
} = require('./string_util.js');
@ -481,6 +481,20 @@ Message.prototype.getQuoteLines = function(options, cb) {
});
}
function getFormattedLine(line) {
// for pre-formatted text, we just append a line truncated to fit
let newLen;
const total = line.length + quotePrefix.length;
if(total > options.cols) {
newLen = options.cols - total;
} else {
newLen = total;
}
return `${quotePrefix}${line.slice(0, newLen)}`;
}
if(options.isAnsi) {
prepAnsi(
this.message.replace(/\r?\n/g, '\r\n'), // normalized LF -> CRLF
@ -507,6 +521,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
// strip colors, colorize the lines, etc. If we exclude the prefixes, this seems to do
// the trick and allow them to leave them alone!
//
// :TODO: The way this bumps to the right is super annoying -- it would be nice to just invert the entire line
split.forEach(l => {
quoteLines.push(`${lastSgr}${l}`);
@ -522,7 +537,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
} else {
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}\> )+(?:[A-Za-z0-9]{2}\>)*) */;
const quoted = [];
const input = this.message.trim().replace(/\b/g, '');
const input = _.trimEnd(this.message).replace(/\b/g, '');
// find *last* tearline
let tearLinePos = this.getTearLinePosition(input);
@ -535,23 +550,42 @@ Message.prototype.getQuoteLines = function(options, cb) {
// - New (pre)quoted line - quote_line
// - Continuation of new/quoted line
//
// :TODO: keep lines as-is that
// - have extended ASCII
// - have tabs or " " (3+ spaces), e.g. pre-formatting
// - contain pipe codes
// Also:
// - Detect pre-formatted lines & try to keep them as-is
//
let state;
let buf = '';
let quoteMatch;
if(quoted.length > 0) {
//
// Preserve paragraph seperation.
//
// FSC-0032 states something about leaving blank lines fully blank
// (without a prefix) but it seems nicer (and more consistent with other systems)
// to put 'em in.
//
quoted.push(quotePrefix);
}
paragraph.split(/\r?\n/).forEach(line => {
if(0 === line.trim().length) {
// see blank line notes above
return quoted.push(quotePrefix);
}
quoteMatch = line.match(QUOTE_RE);
switch(state) {
case 'line' :
if(quoteMatch) {
if(isFormattedLine(line)) {
quoted.push(getFormattedLine(line.replace(/\s/, '')));
} else {
quoted.push(...getWrapped(buf, quoteMatch[1]));
state = 'quote_line';
buf = line;
}
} else {
buf += ` ${line}`;
}
@ -574,8 +608,12 @@ Message.prototype.getQuoteLines = function(options, cb) {
break;
default :
if(isFormattedLine(line)) {
quoted.push(getFormattedLine(line));
} else {
state = quoteMatch ? 'quote_line' : 'line';
buf = 'line' === state ? line : line.replace(/\s/, '');//_.trimStart(line);
buf = 'line' === state ? line : line.replace(/\s/, ''); // trim *first* leading space, if any
}
break;
}
});

View File

@ -27,6 +27,7 @@ exports.cleanControlCodes = cleanControlCodes;
exports.prepAnsi = prepAnsi;
exports.isAnsi = isAnsi;
exports.isAnsiLine = isAnsiLine;
exports.isFormattedLine = isFormattedLine;
exports.splitTextAtTerms = splitTextAtTerms;
// :TODO: create Unicode verison of this
@ -582,6 +583,31 @@ function isAnsiLine(line) {
return isAnsi(line);// || renderStringLength(line) < line.length;
}
//
// Returns true if the line is considered "formatted". A line is
// considered formatted if it contains:
// * ANSI
// * Pipe codes
// * Extended (CP437) ASCII - https://www.ascii-codes.com/
// * Tabs
// * Contigous 3+ spaces before the end of the line
//
function isFormattedLine(line) {
if(renderStringLength(line) < line.length) {
return true; // ANSI or Pipe Codes
}
if(line.match(/[\t\x00-\x1f\x80-\xff]/)) { // eslint-disable-line no-control-regex
return true;
}
if(_.trimEnd(line).match(/[ ]{3,}/)) {
return true;
}
return false;
}
function isAnsi(input) {
//
// * ANSI found - limited, just colors
@ -603,7 +629,7 @@ function isAnsi(input) {
*/
// :TODO: if a similar method is kept, use exec() until threshold
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[\?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g;
const ANSI_DET_REGEXP = /(?:\x1b\x5b)[\?=;0-9]*?[ABCDEFGHJKLMSTfhlmnprsu]/g; // eslint-disable-line no-control-regex
const m = input.match(ANSI_DET_REGEXP) || [];
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing
}