简体   繁体   中英

NodeJS get color in readline

I have a NodeJS app that needs to execute some commands using spawn , I'm reading the output for later processing using readline which works flawlessly.

But I also need to get the color of the text, For example: when executing another Node.js script that uses chalk module.

How can this be accomplished ?

This is my code so far:

const spawn = require('child_process').spawn;
const readline = require('readline');

let myCommand = spawn(<command>, [<args...>], { cwd: dirPath });

readline.createInterface({
  input    : myCommand.stdout,
  terminal : true
}).on('line', (line) => handleOutput(myCommand.pid, line));

readline.createInterface({
  input    : myCommand.stderr,
  terminal : true
}).on('line', (line) => handleErrorOutput(myCommand.pid, line));

myCommand.on('exit', (code) => {
  // Do more stuff ..
});

UPDATE

Amr K. Aly's answer does work but when executing an external NodeJS script it return null color.

My code (index.js) :

const spawn = require('child_process').spawn;
const readline = require('readline');

let myCommand = spawn('node', ['cmd.js']);

readline.createInterface({
  input: myCommand.stdout,
  terminal: true
}).on('line', (line) => handleOutput(myCommand.pid, line));

readline.createInterface({
  input: myCommand.stderr,
  terminal: true
}).on('line', (line) => handleErrorOutput(myCommand.pid, line));

myCommand.on('exit', (code) => {
  // Do more stuff ..
});

function handleErrorOutput(obj, obj2) {}

function handleOutput(obj, line, a, b, c) {
  //PRINT TEXT WITH ANSI FORMATING
  console.log(line);

  //REGEX PATTERN TO EXTRACT COLOR
  var options = Object.assign({
    onlyFirst: false
  });

  const pattern = [
    '[\\u001B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
    '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
  ].join('|');

  var regex = new RegExp(pattern, options.onlyFirst ? undefined : 'g');
  var ansiColor = (line.match(regex));

  //PRINT EXTRACTED ANSI
  console.log("ANSI COLOR CODE :");
  console.log(ansiColor);
}

cmd.js :

const chalk = require('chalk');

console.log(chalk.blue('Blue Hello world!'));
console.log(chalk.green('green Hello world!'));
console.log(chalk.red('red Hello world!'));

my results :

Index.js 结果

Issue:

You can not see the colors when printing back the text stream you read because you have set the terminal option in createInterface to true . This causes createInterface() not to return ANSI/VT100 encoding.

Solution:

The terminal option needs to be set to false so the text would be encoded with ANSI/VT100 From Nodejs Docs: terminal <boolean> true if the input and output streams should be treated like a TTY, and have ANSI/VT100 escape codes written to it. Default: checking isTTY on the output stream upon instantiation. terminal <boolean> true if the input and output streams should be treated like a TTY, and have ANSI/VT100 escape codes written to it. Default: checking isTTY on the output stream upon instantiation. See readline.createInterface(options) documentation

readline.createInterface({
input: myCommand.stdout,
terminal: true//<== NEEDS TO BE SET TO FALSE 
}).on('line', (line) => handleOutput(myCommand.pid, line));

After setting terminal to false , the returned text will be ANSI/VT100 encoded. You'll then need to extract the ANSI/VT100 encoding related to colors and change it to whatever color format you need.

See modified code and output below with added regex to extract ANSI color codes. You need to add your own logic to process the ANSI escaped colors.

const spawn = require('child_process').spawn;
const readline = require('readline');
const chalk = require('chalk');

 //Testing on windows 10
let myCommand = spawn(process.env.comspec, ['/c', 'echo ' + chalk.red('Hello world!'), ], {
    // cwd: dirPath
});

readline.createInterface({
    input: myCommand.stdout,
    terminal: false
}).on('line', (line) => handleOutput(myCommand.pid, line));

readline.createInterface({
    input: myCommand.stderr,
    terminal: false
}).on('line', (line) => handleErrorOutput(myCommand.pid, line));

myCommand.on('exit', (code) => {
    // Do more stuff ..
});

function handleErrorOutput(obj, obj2) {}

function handleOutput(obj, line) {

    //PRINT TEXT WITH ANSI FORMATING
    console.log(line);

    //REGEX PATTERN TO EXTRACT COLOR
    var options = Object.assign({
        onlyFirst: false
    });

    const pattern = [
        '[\\u001B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
        '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'
    ].join('|');

    var regex = new RegExp(pattern, options.onlyFirst ? undefined : 'g');
    var ansiColor = (line.match(regex));

    //PRINT EXTRACTED ANSI
    console.log("ANSI COLOR CODE :");
    console.log(ansiColor);
}

Output for code above:

上面代码的输出:

EDIT:

Chalk detects automatically if you're writing to a TTY or the terminal doesn't support colors and disables the coloring. You can force it by setting an environment variable FORCE_COLOR=1 or by passing a --color as an argument.

If you change your code to the line from the snippet below, Chalk should add the styling correctly.

let myCommand = spawn('node', ['test.js', '--color', ], {


}); 

Output:

代码输出

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM