Используя rlwrap с Node.js REPL, как узел '.break' (Ctrl-C) не может быть интерпретирован rlwrap как SIGINT?

После этого обсуждения о том, как сохранить историю командной строки между сессиями, я определил следующий псевдоним:

alias node='env NODE_NO_READLINE=1 rlwrap node'

Он отлично работает для сохранения истории, но теперь, каждый раз, когда я делаю Ctrl-C, чтобы отправить команду узла.break, rlwrap принимает ее тоже, но как SIGINT: он очищает все и самоубийства (как описано на его man-странице), таким образом вынуждая меня перезапустить сессию узла (вызывая мои var, funcs, require и т. д.), в то время как я просто хотел ".break"...

Есть ли способ вернуть классическое поведение узла?

  • Ctrl-C: разрывы
  • Ctrl-C снова (или на пустой строке): выход

1 ответ

Решение

Избегая SIGINT

node изменяет значение CTRL-C, сбрасывая его символ прерывания VINTR (обычно CTRL-C), чтобы избежать сигнала прерывания, который он получил бы в противном случае.

После запуска rlwrap спит все время, пока что-то не происходит на вашем терминале или на псевдотерминале (pty) используется, например, node, Это "что-то" может быть нажатием клавиши вами или выводом из node,

Каждый раз, когда это происходит, rlwrap будет копировать nodes Настройки терминала (включая VINTR)) на свой tty.

Однако если node только меняет настройки терминала, это само по себе не проснется rlwrap, что, таким образом, сохранит старые настройки на собственном tty. Прозрачность будет нарушена: при нажатии CTRL-C rlwrap все равно будет интерпретировать это как SIGINT, в то время как node понял бы .break команда.

Там особенный, очень непонятный, pty режим ( EXTPROC), который позволяет мастеру pty (rlwrap) быть разбуженным изменениями в настройках терминала ведомого, но это очень непереносимо. Вот почему, начиная с версии 0.41, rlwrap имеет гораздо менее элегантный --polling опция, которая заставляет его просыпаться каждые 40 миллисекунд и копировать настройки терминала ведомого.

Нападающий CTRL-C

Начиная с версии 0.43, rlwrap может напрямую переадресовывать специальные ключи даже в режиме readline, связывая такой ключ с rlwrap-direct-keypress в ~/.inputrc:

$if node
   "\C-c": rlwrap-direct-keypress
$endif

Тем не мение, node CTRL+C предоставляет специальную обработку только тогда, когда он сам использует readline (попробуйте NODE_NO_READLINE=1 node а затем наберите CTRL-C), чтобы увидеть, что я имею в виду)

В таких случаях (т. Е. Когда команда выполняет собственное редактирование строки), необходимо rlwrap в режиме readline:

$ rlwrap --always-readline node

Это имеет неприятный и неизбежный недостаток, когда команда запрашивает одиночные нажатия клавиш (Continue? Y/N) нужно ввести дополнительный Enter.

И еще есть проблема, набросанная выше: если символ прерывания терминала не изменился, node никогда не увидит CTRL-C (но получить SIGINT вместо)

Есть два решения. Или:

stty intr undef # disable interrupt character
rlwrap --always-readline node
stty intr '^c'  # re-enable CTRL-C

или же:

 rlwrap --polling --always-readline node # --polling means: continually wake up and wacth  node's interrupt character

Завершение

Короче говоря:

  • добавлять "\C-c": rlwrap-direct-keypress на ваш inputc
  • Временно сбросьте символ прерывания терминала или используйте rlwrap --polling --always-readline как указано выше
  • Попробуйте жить с дополнительным Enter для одиночных нажатий клавиш
Другие вопросы по тегам