Using rlwrap with Node.js REPL, how could node '.break' (Ctrl-C) not be interpreted as a SIGINT by rlwrap?
Asked Answered
S

1

9

Following this discussion on how to preserve command line history between sessions, I defined the following alias:

alias node='env NODE_NO_READLINE=1 rlwrap node'

It works perfectly for the history persistance but now, everytime I do a Ctrl-C to send node's '.break' command, rlwrap takes it too but as a SIGINT: it cleans everything and suicides (as described in its man page), thus forcing me to restart a node session (having to recall my var, funcs, requires etc), while I just wanted to '.break'...

Any way to get back the classic node behaviour?

  • Ctrl-C : breaks
  • Ctrl-C again (or on a blank line): exit
Shericesheridan answered 18/2, 2014 at 19:46 Comment(0)
B
7

Avoiding SIGINT

node changes the meaning of CTRL-C by unsetting its interrupt character VINTR (usually CTRL-C) to avoid the interrupt signal that it would otherwise get.

After starting up, rlwrap is sleeping all the time, until something happens on your terminal or on the pseudo-terminal (pty) used by e.g. node. This "something" can be a keypress by you, or output from node.

Every time this happens, rlwrap will copy nodess terminal settings (including VINTR) ) to its own tty.

However, if node only changes its terminal settings, this, by itself, won't wake up rlwrap, which will thus keep the old settings on its own tty. Transparency will then be broken: When you press CTRL-C rlwrap will still interpret it as a SIGINT, while node would have understood a .break command.

There ia a special, very obscure, pty mode (EXTPROC) that allows the pty master (rlwrap) to be woken up by a slave's changes in terminal settings, but this is very un-portable. This is why, since version 0.41, rlwrap has the much less elegant --polling option that makes it wake up every 40 milliseconds and copy the slave's terminal settings.

Forward CTRL-C

Starting with version 0.43, rlwrap can directly forward special keys even when in readline mode by binding such a key to rlwrap-direct-keypress in ~/.inputrc:

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

However, node only gives CTRL+C special treatment when it itself uses readline (try NODE_NO_READLINE=1 node and then type CTRL-C) to see what I mean)

In such cases (i.e. when a command does its own line editing), one has to force rlwrap into readline mode:

$ rlwrap --always-readline node

This has the unfortunate and unavoidable drawback that whanever a command asks for single keypresses (Continue? Y/N) one has to type an extra Enter.

And then there still is the problem sketched above: if the terminal's interrupt character is not changed, node will never see the CTRL-C (but get a SIGINT instead)

There are two solutions. Either:

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

or:

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

Wrapping up

To make a long story short:

  • Add "\C-c": rlwrap-direct-keypress to your inputc
  • Temporarily unset the terminal's interrupt character, or use rlwrap --polling --always-readline as above
  • Try to live with the extra Enter for single keypresses
Bach answered 23/2, 2014 at 22:25 Comment(4)
I tried to use rlwrap-direct-keypress without success.Jackass
rlwrap has a few new options that might help - I edited my answer accordingly.Bach
With this configuration, pressing ctrl-c prints ^C to the screen and it takes an Enter to update the screen. But that's better than nothing. I'm now wondering how to get this with node REPL scripts, not just the node REPL itself, as in your answer here: https://mcmap.net/q/904711/-a-node-shell-based-on-gnu-readline I.e. rlwrap --polling --always-readline -z node_complete ./myrepl.js still has ctrl-c broken.Jackass
I cannot reproduce that. Did you reset the terminal? Could you build rlwrap with the --enable-debug configure option, run rlwrap --debug --polling --always-readline node, press CTRL-C a few times, and mail me the resulting /tmp/rlwrap.debug file? (you find my address on my Github pageBach

© 2022 - 2024 — McMap. All rights reserved.