向终端提示添加颜色会导致较大的空白区域

时间:2012-08-22 14:29:36

标签: javascript node.js command-line-interface ansi readline

我正在研究一个简单的cli脚本,并希望为以下代码添加一些颜色:

rl.question('Enter destination path: ', function(answer) {
     // ...                                                                                                                                
});                                                                                                                                  
rl.write('/home/' + user + '/bin');

终端中显示的内容:

Enter destination path: /home/jmcateer/bin_

但是我想在我做以下操作的提示中添加一些颜色:

rl.question('\u001b[1;36mEnter destination path:\u001b[0m ', function(answer) {

});                                                                                                                                  
rl.write('/home/' + user + '/bin');

命令行提示结束显示:

Enter destination path:                 /home/jmcateer/bin_

它有效,但是我不喜欢那里有大量的空白区域。有没有人对如何处理这个有任何想法?

编辑:

我无法通过退格来删除空白区域...当我尝试使用退格键时,空格会跳转到另一端,就像这样

Enter destination path:                 /home/jmcateer/bin_
Enter destination path: /home/jmcateer/bi                _
Enter destination path: /home/jmcateer/b                _
...
Enter destination path:                 _

此时退格无效。

3 个答案:

答案 0 :(得分:4)

如果您在没有第二个参数的情况下致电rl.setPrompt(prompt, length)the internal _promptLength variable is set to the length of the prompt string; ANSI X3.64转义序列解释。内部_getCursorPos方法从_promptLength]计算光标位置[3];因此,在长度中包含转义序列会导致光标定位得比它应该的位置更远。

要完全解决此问题,Node的readline库应在设置_promptLength时解析ANSI转义序列。要解决此问题,您可以手动计算不带转义序列的提示字符串的长度,并将其作为第二个参数传递给rl.setPrompt(prompt, length)

答案 1 :(得分:2)

我也遇到过类似的问题。 Basil Crow对于问题原因的出色答案是正确的,因为确实是ANSI转义序列导致长度故障;但是,Interface.setPrompt()不仅仅是问题 - 它是解决方案

似乎这种对长度的误读(我在bash中玩弄时巧妙地避免的东西)会影响整个Interface对象的写出过程,即任何以任何身份调用Interface.setPrompt()的东西都会如果未指定长度参数,则会受到影响。

为了克服这个问题,你可以做以下两件事之一:


重新定义Interface.setPrompt()以始终指定提示输出的长度,以便Interface.question()等方法再次正常运行:

// I'm using the 'color' npm library for the sake of convenience. It is not required
// and you can use normal regex to strip color codes and what not.
var colors   = require('colors'),
    readline = require('readline');

var rl = readline.createInterface(process.stdin, process.stdout);

/* Overcome some bugs in the Nodejs readline implementation */
rl._setPrompt = rl.setPrompt;
rl.setPrompt = function(prompt, length)
{
    rl._setPrompt(prompt, length ? length : prompt.split(/[\r\n]/).pop().stripColors.length);
};

var str = '[' + '?'.green + '] Blackbeard walks under the black flag with a ____? ';

rl.question(str, function(answer)
{
    var answ = 'scallywag swagger';
    console.log(
        'You answered "' + ((answer == answ) ? answer.green : answer.red)
        + '". The correct answer is', '"' + answ.green + '".');
});


重新定义Interface.write()以使用Interface.setPrompt()将写出字符串和字符串的真实长度传递给setPrompt方法:

var colors   = require('colors'),
    readline = require('readline');

var rl = readline.createInterface(process.stdin, process.stdout);

/* Overcome some bugs in the Nodejs readline implementation */
rl._write = rl.write; 
rl.write = function(d, key)
{
    // "key" functionality is lost, but if you care enough you can add it back
    rl.setPrompt(d, d.split(/[\r\n]/).pop().stripColors.length);
    rl.prompt(true);
};

var str = '[' + '?'.green + '] Blackbeard walks under the black flag with a ____? ';
rl.write(str);

rl.on('line', function(answer)
{
    var answ = 'scallywag swagger';
    console.log(
        'You answered "' + ((answer == answ) ? answer.green : answer.red)
        + '". The correct answer is', '"' + answ.green + '".');
    rl.prompt(true);
});


两者的结果相同:output of the above scripts

或者你可以做到这两点。或者,您可以直接修改readline.Interface.prototype(并全局应用修复)而不是对象实例本身。这里有很多选择。

希望这有助于某人!

编辑 - 另请参阅:https://github.com/joyent/node/issues/3860

答案 2 :(得分:0)

当然,您需要使用CSI序列rl.write修改n D字符串,其中n是将光标移回的字符数。

以下是一个试验片段:

var rl = require('readline').createInterface({input: process.stdin, output: process.stdout});

rl.question('\u001b[1;36mEnter destination path: \u001b[0m', function(answer) {

});                                                                                               
rl.write('\u001b[11 D/home/jp/bin');

请注意最后一行中的11DD代表要移回的字符数。 11显然是字符数。

查看所有有趣的终端代码:http://en.wikipedia.org/wiki/ANSI_escape_code