Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adjust Node REPL to not clobber prompt on async callback?

When working with the Node REPL console, I'm looking for a way for asynchronous calls to both not lock up the console input, and not clobber the console prompt when they return.

I've seen a few solutions dealing with asynchronous calls in the REPL, where writing your own custom eval function you can check the result of the executed code to see if it's a promise/async object, and just not return until it resolves.

However, I'd like to solve the issue of a repeating background process logging its progress. Ideally I'd like it to behave like the Chrome Javascript console, where if you have a command partially printed on the console prompt, and an async result gets logged, the line you're typing on gets moved one line down, and the log inserted above it.

So, functionally, I'd like to insert the logic that when console.log() is called, the line containing the cursor is first cleared, then the contents of the log() written, and then the REPL prompt (and whatever the user had typed so far onto it) gets re-written on the line following the new output.

Is there any way to hook into the REPL object to accomplish this? Is this some advanced manipulation of the output stream from the REPL (i.e. only possible on terminals that support an "erase to beginning of line" escape code)?

like image 634
MidnightLightning Avatar asked Feb 23 '15 21:02

MidnightLightning


1 Answers

Tapping straight into the Output Stream I managed to get something working like how I wanted:

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);
};

Though that all assumes an ANSI-compliant output stream is the output, and feels quite hack-ish, overriding the console.log() function like that. Is there a more compliant way to handle this, or is this the best way?

like image 140
MidnightLightning Avatar answered Sep 28 '22 04:09

MidnightLightning