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 ANSI = require('./ansi_term.js');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
prepAnsi, isAnsi,
|
prepAnsi, isAnsi, isFormattedLine,
|
||||||
splitTextAtTerms,
|
splitTextAtTerms,
|
||||||
renderSubstr
|
renderSubstr
|
||||||
} = require('./string_util.js');
|
} = 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) {
|
if(options.isAnsi) {
|
||||||
prepAnsi(
|
prepAnsi(
|
||||||
this.message.replace(/\r?\n/g, '\r\n'), // normalized LF -> CRLF
|
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
|
// strip colors, colorize the lines, etc. If we exclude the prefixes, this seems to do
|
||||||
// the trick and allow them to leave them alone!
|
// 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 => {
|
split.forEach(l => {
|
||||||
quoteLines.push(`${lastSgr}${l}`);
|
quoteLines.push(`${lastSgr}${l}`);
|
||||||
|
|
||||||
|
@ -522,7 +537,7 @@ Message.prototype.getQuoteLines = function(options, cb) {
|
||||||
} else {
|
} else {
|
||||||
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}\> )+(?:[A-Za-z0-9]{2}\>)*) */;
|
const QUOTE_RE = /^ ((?:[A-Za-z0-9]{2}\> )+(?:[A-Za-z0-9]{2}\>)*) */;
|
||||||
const quoted = [];
|
const quoted = [];
|
||||||
const input = this.message.trim().replace(/\b/g, '');
|
const input = _.trimEnd(this.message).replace(/\b/g, '');
|
||||||
|
|
||||||
// find *last* tearline
|
// find *last* tearline
|
||||||
let tearLinePos = this.getTearLinePosition(input);
|
let tearLinePos = this.getTearLinePosition(input);
|
||||||
|
@ -535,23 +550,42 @@ Message.prototype.getQuoteLines = function(options, cb) {
|
||||||
// - New (pre)quoted line - quote_line
|
// - New (pre)quoted line - quote_line
|
||||||
// - Continuation of new/quoted line
|
// - Continuation of new/quoted line
|
||||||
//
|
//
|
||||||
// :TODO: keep lines as-is that
|
// Also:
|
||||||
// - have extended ASCII
|
// - Detect pre-formatted lines & try to keep them as-is
|
||||||
// - have tabs or " " (3+ spaces), e.g. pre-formatting
|
|
||||||
// - contain pipe codes
|
|
||||||
//
|
//
|
||||||
let state;
|
let state;
|
||||||
let buf = '';
|
let buf = '';
|
||||||
let quoteMatch;
|
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 => {
|
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);
|
quoteMatch = line.match(QUOTE_RE);
|
||||||
|
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case 'line' :
|
case 'line' :
|
||||||
if(quoteMatch) {
|
if(quoteMatch) {
|
||||||
|
if(isFormattedLine(line)) {
|
||||||
|
quoted.push(getFormattedLine(line.replace(/\s/, '')));
|
||||||
|
} else {
|
||||||
quoted.push(...getWrapped(buf, quoteMatch[1]));
|
quoted.push(...getWrapped(buf, quoteMatch[1]));
|
||||||
state = 'quote_line';
|
state = 'quote_line';
|
||||||
buf = line;
|
buf = line;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
buf += ` ${line}`;
|
buf += ` ${line}`;
|
||||||
}
|
}
|
||||||
|
@ -574,8 +608,12 @@ Message.prototype.getQuoteLines = function(options, cb) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default :
|
default :
|
||||||
|
if(isFormattedLine(line)) {
|
||||||
|
quoted.push(getFormattedLine(line));
|
||||||
|
} else {
|
||||||
state = quoteMatch ? 'quote_line' : 'line';
|
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;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,6 +27,7 @@ exports.cleanControlCodes = cleanControlCodes;
|
||||||
exports.prepAnsi = prepAnsi;
|
exports.prepAnsi = prepAnsi;
|
||||||
exports.isAnsi = isAnsi;
|
exports.isAnsi = isAnsi;
|
||||||
exports.isAnsiLine = isAnsiLine;
|
exports.isAnsiLine = isAnsiLine;
|
||||||
|
exports.isFormattedLine = isFormattedLine;
|
||||||
exports.splitTextAtTerms = splitTextAtTerms;
|
exports.splitTextAtTerms = splitTextAtTerms;
|
||||||
|
|
||||||
// :TODO: create Unicode verison of this
|
// :TODO: create Unicode verison of this
|
||||||
|
@ -582,6 +583,31 @@ function isAnsiLine(line) {
|
||||||
return isAnsi(line);// || renderStringLength(line) < line.length;
|
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) {
|
function isAnsi(input) {
|
||||||
//
|
//
|
||||||
// * ANSI found - limited, just colors
|
// * ANSI found - limited, just colors
|
||||||
|
@ -603,7 +629,7 @@ function isAnsi(input) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// :TODO: if a similar method is kept, use exec() until threshold
|
// :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) || [];
|
const m = input.match(ANSI_DET_REGEXP) || [];
|
||||||
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing
|
return m.length >= 4; // :TODO: do this reasonably, e.g. a percent or soemthing
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue