【发布时间】:2014-10-07 14:35:18
【问题描述】:
我在 Node.js 中有一个子进程,它产生 ANSI-escape 彩色输出,有时比我的终端宽。
我想截断长行,但不破坏 ANSI 颜色代码,也不计算不可见字符(这样有很多转义的行不会太短)
【问题讨论】:
标签: javascript node.js ansi-escape
我在 Node.js 中有一个子进程,它产生 ANSI-escape 彩色输出,有时比我的终端宽。
我想截断长行,但不破坏 ANSI 颜色代码,也不计算不可见字符(这样有很多转义的行不会太短)
【问题讨论】:
标签: javascript node.js ansi-escape
首先,您需要确保处理来自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
}
【讨论】:
你可能想试试这个小型 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'
【讨论】: