Major improvements to quote builder for pre-formatted text/etc.
This commit is contained in:
parent
1c736debf3
commit
1bad0de5c1
|
@ -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) {
|
||||
quoted.push(...getWrapped(buf, quoteMatch[1]));
|
||||
state = 'quote_line';
|
||||
buf = line;
|
||||
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 :
|
||||
state = quoteMatch ? 'quote_line' : 'line';
|
||||
buf = 'line' === state ? line : line.replace(/\s/, '');//_.trimStart(line);
|
||||
if(isFormattedLine(line)) {
|
||||
quoted.push(getFormattedLine(line));
|
||||
} else {
|
||||
state = quoteMatch ? 'quote_line' : 'line';
|
||||
buf = 'line' === state ? line : line.replace(/\s/, ''); // trim *first* leading space, if any
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue