我在Node.js中有一个子进程,它生成ANSI-escape彩色输出,有时比我的终端更宽。
我想截断长行,但不打破ANSI颜色代码,也不计算不可见的字符(这样有很多转义的行也不会太短)
答案 0 :(得分:1)
首先,您需要确保处理来自stdout
的完整行,这可能会在行之间提供片段:
var acc = '';
child.stdout.setEncoding('utf8'); // get strings rather than buffers
child.stdout.on('data', function(data){ // when output is written by child
// split lines, including linebreaks:
data.split(/(\r?\n)/).forEach(function(frag) {
if (frag == '\r\n' || frag == '\n') { // if linebreak,
console.log(filterAnsi(acc, width)); // output filtered completed line
acc = ''; // clear accumulator line
} else { // if not linebreak,
acc += frag; // add fragment to accumulator
}
});
});
接下来是过滤器本身:
// Crop the length of lines, ANSI escape code aware
// Always outputs every escape char, regardless of length (so we always end up with a sane state)
// Visible characters are filtered out once length is exceeded
function filterAnsi(str, len) {
if (!len || len < 10) return str; // probably not a valid console -- send back the whole line
var count = 0, // number of visible chars on line so far
esc = false, // in an escape sequence
longesc = false; // in a multi-character escape sequence
var outp = true; // should output this character
return str.split('').filter(function(c){ // filter characters...
if (esc && !longesc && c == '[') longesc = true; // have seen an escape, now '[', start multi-char escape
if (c == '\x1b') esc = true; // start of escape sequence
outp = (count < len || esc); // if length exceeded, don't output non-escape chars
if (!esc && !longesc) count++; // if not in escape, count visible char
if (esc && !longesc && c != '\x1b') esc = false; // out of single char escape
if (longesc && c != '[' && c >= '@' && c <= '~') {esc=false; longesc=false;} // end of multi-char escape
return outp; // result for filter
}).join(''); // glue chars back into string
}
答案 1 :(得分:1)
您可能想尝试这个微小的NPM库:printable-characters
它处理包含零宽度字符和ANSI转义码的字符串的所有负担。
在不破坏ANSI代码的情况下获得前N个符号:
const { first } = require ('printable-characters')
const s = '\u001b[22mfoobar\u001b[22m'
first (s, 0) // === '\u001b[22m\u001b[22m'
first (s, 1) // === '\u001b[22mf\u001b[22m'
first (s, 3) // === '\u001b[22mfoo\u001b[22m'
first (s, 6) // === '\u001b[22mfoobar\u001b[22m'