调整节点REPL以不在异步回调上提示clobber?

时间:2015-02-23 21:25:36

标签: javascript node.js read-eval-print-loop

使用Node REPL控制台时,我正在寻找一种异步调用的方法,既不会锁定控制台输入,也不会在返回时破坏控制台提示符。

我在REPL中看到了一些处理异步调用的解决方案,在这里编写自己的自定义eval函数,你可以检查执行代码的结果,看看它是否是一个promise / async对象,只是在结算之前不会返回。

但是,我想解决重复后台进程记录其进度的问题。理想情况下,我希望它的行为类似于Chrome Javascript控制台,如果您在控制台提示符上部分打印了一个命令,并且记录了异步结果,那么您输入的行将被移动一行,并且日志插在它上面。

所以,在功能上,我想插入一个逻辑,当调用console.log()时,首先清除包含游标的行,然后写入log()的内容,然后是REPL提示(以及用户到目前为止输入的内容)将在新输出后的行上重写。

有没有办法挂钩到REPL对象来实现这个目的?这是对REPL输出流的一些高级操作(即只能在支持“擦除到行首”转义码的终端上进行)?

3 个答案:

答案 0 :(得分:1)

直接进入输出流我设法得到了一些像我想要的东西:

var server = repl.start({
    prompt: '> '
});
server.context.console.log = function(msg) {
    var rli = server.rli;
    server.outputStream.write('\033[2K\033[1G'); // Erase to beginning of line, and reposition cursor at beginning of line
    server.outputStream.write(msg+"\n");
    server.outputStream.write(''+rli._prompt+rli.line); // Redraw existing line
    server.outputStream.write('\033['+(rli.cursor+rli._promptLength+1)+'G'); // Move the cursor to where it was
}

server.context.doTimeout = function() {
    setTimeout(function() {
        server.context.console.log('Timeout done!');
    }, 2000);
};

尽管所有这些都假定符合ANSI标准的输出流是输出,并且感觉很糟糕,所以会覆盖console.log()函数。是否有更合规的方法来处理这个问题,或者这是最好的方法吗?

答案 1 :(得分:1)

仍然,现在我无法在 StackOverflow 上找到满意的现代答案。 在互联网上花了几个小时后,我为最新的 Node (v15.*) 想出了这个解决方案

const log = (msg) => {
  rl.output.write('\r')
  rl.output.write(msg + '\n')
  rl.displayPrompt(true)
}

基本上,清除行,写入日志,然后再次显示提示。非常适合我的情况。

改进的解决方案。 如果缓冲行不长于日志,则上述方法效果很好。所以这是另一个版本,用空格字符填充日志的其余部分

const log = (msg) => {
  rl.output.write('\r');
  rl.output.write(_.padEnd(msg, process.stdout.columns - 2, ' ') + '\n');
  rl.displayPrompt(true);
};
  • _.padEnd:lodash 的padEnd,可以用任意lib替换

答案 2 :(得分:0)

基于@MidnightLightning的较早答案。

从节点v12.15.0之前的某个时候开始,console.log覆盖看起来像:

activeRepl.context.console.log = (msg) => {
  const promptOffset = Server._prompt.length + Server.line.length;
  Server.outputStream.write('\033[2K\033[1G'); // Erase to beginning of line, and reposition cursor at beginning of line
  Server.outputStream.write(msg + "\n");
  Server.outputStream.write('' + Server._prompt + Server.line); // Redraw existing line
  Server.outputStream.write('\033[' + (promptOffset + 1) + 'G'); // Move the cursor to where it was
};