【问题标题】:A node shell based on gnu readline基于gnu readline的node shell
【发布时间】:2017-04-19 20:11:40
【问题描述】:

有没有内部使用 gnu readline 的节点外壳?

如您所知,node shell 有两种方式(除其他外): 它没有搜索历史,它没有使用 gnu readline。使用 gnu readline 的 shell(如 psql、ipython、python、bash 等)具有许多开箱即用的功能,并且都共享您在 ~/.inputrc 中设置的单个配置文件。例如,我在上面列出的所有 shell 中都有很好的 vim 模式,因为它们都在内部使用 gnu readline。如果 js 的 shell 内部也使用 gnu readline,那么它将与我的其他 shell 保持一致。

【问题讨论】:

  • 你试过rlwrap吗?它允许您在任何程序中使用 readline 进行输入
  • 谢谢,它为我打开了一扇全新的大门。但不幸的是,即使我的.inputrc 中有set editing-mode viset keymap vi rlwrap 也不尊重它,也没有vi-mode。我试过socat,但它也有一些问题。
  • vi-mode 在rlwrap nc localhost 8000 下工作,但不适用于nodeneshbc
  • 好的,我需要 -a -- 考虑添加它作为答案,我会接受它。
  • 不太支持set show-mode-in-prompt on

标签: node.js shell


【解决方案1】:

that other guy 是对的:rlwrap 会起作用。不幸的是,它扔掉了 nodes 自己完成。如何避免这种情况是FAQ,所以这里遵循一种恢复完成的方法:not 通过将 TAB 提供给包装的命令,然后 以某种方式解析产生的混乱,但使用过滤器。

Filters 是小脚本,充当 rlwrap 插件。可以重写用户输入、命令输出、提示、历史和完成单词列表。 它们可以写成perlpython 并组合成一个管道。

过滤器还可以做一件事:与用户背后的包装命令进行交互(cloak_and_dagger() 方法)

因此,如果我们教 node 一个新命令 rlwrap_complete(prefix) 打印 prefix 的完成列表,我们可以使用 cloak_and_dagger("rlwrap_complete($prefix)") 获取所有可能的完成,并将其用于 rlwraps 自己的完成。

这是为perl 编写的node 的过滤器,但不同命令的python 版本看起来非常相似:

#!/usr/bin/env perl

use lib ($ENV{RLWRAP_FILTERDIR} or ".");
use RlwrapFilter;
use strict;

my $filter = new RlwrapFilter;

$filter -> completion_handler( sub {
  my($line, $prefix, @completions) = @_;
  my $command = "rlwrap_complete('$prefix')";
  my $completion_list = $filter -> cloak_and_dagger($command, "> ", 0.1); # read until we see a new prompt "> "
  my @new_completions =  grep /^$prefix/, split /\r\n/, $completion_list; # split on CRNL and weed out rubbish
  return (@completions, @new_completions);                                                  
 });

$filter -> run;

现在我们必须教node 命令rlwrap_complete()。作为nodedoesn't use an init file like .noderc,我们必须 创建一个 REPL 实例并扩展它:

#!/usr/bin/env node

// terminal:false disables readline (just like env NODE_NO_READLINE=1): 
var myrepl = require("repl").start({terminal:false}); 

// add REPL command rlwrap_complete(prefix) that prints a simple list of completions of prefix
myrepl.context['rlwrap_complete'] =  function(prefix) {
  myrepl.complete(prefix, function(err,data) { for (x of data[0]) {console.log(x)}});
}    

将过滤器代码移动到$RLWRAP_FILTERDIR/node_complete,将上述代码另存为myrepl.js并使其可执行。然后调用:

$ rlwrap -z node_complete ./myrepl.js

...享受具有可搜索历史的 REPL TAB 完成!任何时候您按 TAB rlwrap 都会与 node 进行(不可见的)聊天以提出正确的完成。

如果需要,可以添加其他 rlwrap 好东西(彩色提示、vi 模式、其他过滤器)。

当然,在我们可以使用与node 相同的解决方案之前,任何 REPL 都需要能够进行一些元编程来访问其自己的命名空间作为数据。

【讨论】:

  • 感谢您的详细回答。我想我们应该在 rlwrap 命令中添加-c,以便fs.<TAB> 的完成也可以工作,否则在fs.<TAB> 的情况下前缀将是空字符串。
  • @Sassan:从断字字符列表中删除点 . 只是 -c 又名 --complete-filenames 选项的副作用(一般方法是使用--break-chars) 但你是对的:对于Javascript,你想完成像fs. 这样的前缀你的评论让我意识到完成处理程序需要添加原始@completions到@ 987654362@ - 如果不是,rlwrap -c 将不会在文件名上完成。我相应地编辑了我的答案。
  • 感谢您的详细信息,我也使用-e ''以避免完成后多余的空间。
【解决方案2】:

rlwrap 将允许您将 readline 用于任意程序。

如果程序不(或可以说服不)使用自己的行编辑,则效果最好。特别是对于node,您可以使用:

NODE_NO_READLINE=1 rlwrap node

【讨论】:

  • NODE_NO_READLINE=1 让它变得更好。我知道rlwrap 通过-f 接受自动补全,但是否可以使用底层动态repl 的自动补全?例如,当我输入 fs. 并按 Tab 时,它是否会带来自动完成节点的提示?
  • @Sassan:不,唉。查看Is there a way to run rlwrap with tab completion disabled?的答案
  • @HansLub 是的,我在那里读到了你的答案。感谢您在此提及。关于此评论:stackoverflow.com/questions/9210931/… 我想知道是否可以编写特定代码来处理特定的 REPL。我说的是至少对于流行的 REPL 来说逐个处理选项卡完成。问题是节点周围的社区完全没有希望使用 readline 或任何标准的东西。
  • 因为某些未知的原因,他们只是喜欢新事物,而无论如何讨厌 readline 之类的旧事物。因此,与在节点中使用 readline 相比,我更有希望在 rlwrap 中处理它。 Node 将所有完成建议打印为纯文本,没有分页或魔法。对于许多其他 REPL,它应该是相同的,所以如果我们处理这种情况,也许我们可以在许多由 rlwrap 包装的 REPL 中实现自动完成。
  • 为底层命令提供一个 TAB 并不困难,但解释返回的内容是一个问题(这需要my comment 中提到的“虚拟终端模拟器”)一个更优雅的解决方案是编写一个 node.js 函数 complete(text) 打印完成列表,然后是例如"END_OF_COMPLETIONS" 并在过滤器中使用它,使用 cloak_and_dagger() 方法与底层命令交互而不会打扰用户。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 2010-11-06
  • 2023-04-06
  • 2015-03-10
  • 1970-01-01
  • 2020-07-17
  • 2023-03-24
相关资源
最近更新 更多