使用rlwrap与Node.js REPL,如何使节点'.break'(Ctrl-C)不被rlwrap解释为SIGINT?

9

在讨论如何保留命令行历史记录的问题上,我定义了以下别名:

(链接)

alias node='env NODE_NO_READLINE=1 rlwrap node'

它对历史数据持久性非常有效,但是现在,每次我按Ctrl-C发送节点的'.break'命令时,rlwrap也会将其视为SIGINT:它会清除所有内容并自杀(如其手册所述),因此迫使我重新启动节点会话(必须重新调用我的变量、函数和要求等),而我只是想要'.break'... 有没有办法恢复经典的节点行为呢?
  • Ctrl-C:中断
  • 再次按Ctrl-C(或在空白行上):退出
1个回答

7

避免 SIGINT 信号

node 改变了 CTRL-C 的含义,通过取消其中断字符 VINTR(通常为 CTRL-C),以避免它会收到的中断信号。

启动后,rlwrap 一直处于睡眠状态,直到您的终端或伪终端(例如 node 使用的 pty)发生了某些事情。这个“某些事情”可以是您按下的键,也可以是 node 的输出。

每次发生这种情况时,rlwrap 将复制 node 终端设置(包括 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 模式下也可以通过将这样的按键绑定到 ~/.inputrc 中的 rlwrap-direct-keypress 来实现:

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

然而,当node本身使用readline时(尝试使用NODE_NO_READLINE=1 node,然后输入CTRL-C),它只有在使用CTRL+C时才会得到特殊对待。

在这种情况下(即命令执行自己的行编辑时),必须将rlwrap强制进入readline模式:

$ rlwrap --always-readline node

这个方法有一个不幸和不可避免的缺点,就是每当一个命令要求单个按键(继续?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

总结

简而言之:

  • inputc中添加"\C-c": rlwrap-direct-keypress
  • 暂时取消终端的中断字符,或使用如上所述的rlwrap --polling --always-readline
  • 尽量接受单个按键需要额外输入Enter的情况

我尝试使用rlwrap-direct-keypress但没有成功。 - Andrew
1
rlwrap 有一些新选项可能会有所帮助 - 我已相应地编辑了我的答案。 - Hans Lub
1
有了这个配置,按下ctrl-c会在屏幕上打印^C,并需要按Enter键才能更新屏幕。但这总比没有好。我现在想知道如何在node REPL脚本中实现这一点,而不仅仅是在你在这里的答案中使用node REPL:https://dev59.com/questions/1aHia4cB1Zd3GeqPNQs5#43677273 即rlwrap --polling --always-readline -z node_complete ./myrepl.js仍然无法正常运行ctrl-c。 - Andrew
1
我无法重现那个问题。你是否已经“reset”终端?你能否使用“--enable-debug”配置选项构建“rlwrap”,运行“rlwrap --debug --polling --always-readline node”,按下几次CTRL-C,并将生成的“/tmp/rlwrap.debug”文件发送给我吗?(你可以在我的Github页面找到我的联系方式) - Hans Lub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接