Отрегулировать Node REPL, чтобы не вызывать всплывающее окно при асинхронном обратном вызове
При работе с консолью Node REPL я ищу способ асинхронных вызовов, чтобы не блокировать ввод с консоли и не загромождать приглашение консоли при их возврате.
Я видел несколько решений, связанных с асинхронными вызовами в REPL, где пишу свой собственный eval
Функция позволяет проверить результат выполненного кода, чтобы увидеть, является ли он объектом обещания / асинхронности, и просто не возвращать, пока он не разрешится.
Тем не менее, я хотел бы решить проблему повторяющегося фонового процесса, регистрирующего его ход. В идеале я бы хотел, чтобы он вел себя как консоль Chrome Javascript, где, если у вас есть команда, частично напечатанная в командной строке, и в результате записывается асинхронный результат, строка, на которой вы печатаете, перемещается на одну строку вниз, а журнал вставлен над ним.
Итак, функционально, я хотел бы вставить логику, что когда console.log()
вызывается, строка, содержащая курсор, сначала очищается, затем содержимое log()
записывается, а затем приглашение REPL (и все, что пользователь уже набрал на нем) переписывается в строке после нового вывода.
Есть ли способ подключиться к объекту REPL для достижения этой цели? Является ли это каким-то продвинутым манипулированием выходным потоком из REPL (т. Е. Возможно только на терминалах, которые поддерживают escape-код "стирание в начало строки")?
3 ответа
Прямо в поток вывода мне удалось получить что-то вроде того, что я хотел:
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()
функционировать так. Есть ли более гибкий способ справиться с этим или это лучший способ?
Тем не менее, сейчас я не могу найти современного удовлетворительного ответа на 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's padEnd, можно заменить любой библиотекой
На основе более старого ответа @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
};