that other guy is right: rlwrap
will work. Unfortunately, it throws away
node
s own completion. How to avoid this is a FAQ, so here follows a way to restore completion: not by feeding a TAB to the wrapped command and then
somehow parsing the resulting mess, but using a filter.
Filters are small scripts that act as
rlwrap
plugins. The can re-write user input, command output, prompts, history and completion word lists.
They can be written in perl
or python
and be combined in a pipeline.
Filters can do one more trick: interact with the wrapped command behind the user's back (the cloak_and_dagger()
method)
So if we teach node
a new command rlwrap_complete(prefix)
that prints a list of completions of prefix
we can use
cloak_and_dagger("rlwrap_complete($prefix)")
to get hold of all possibe completions, and use those for rlwrap
s own completer.
Here is the filter, written for node
, in perl
, but a python
version for a different command would look very similar:
#!/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;
Now we have to teach node
the command rlwrap_complete()
. As node
doesn't use an init file like .noderc
we have to
create a REPL instance and extend it:
#!/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)}});
}
Move the filter code to $RLWRAP_FILTERDIR/node_complete
, save the above code as myrepl.js
and make it executable. Then call:
$ rlwrap -z node_complete ./myrepl.js
... and enjoy a REPL with searchable history and TAB completion! Any time you press TAB rlwrap
will have an (invisible) chat with node
to come up with the right completions.
Other rlwrap
goodies (coloured prompts, vi
mode, additional filters) can be added if you want them.
Of course, any REPL needs to be able to do a bit of metaprogramming to access its own namespace as data before we can use the same solution as for node
rlwrap
? It lets you use readline for input in any program – Lanctotset editing-mode vi
andset keymap vi
in my .inputrcrlwrap
doesn't respect it and there's novi-mode
. I tried socat but it has some problems too. – Ensollrlwrap nc localhost 8000
but it doesn't work withnode
,nesh
norbc
– Ensoll-a --
consider adding it as an answer and I'll accept it. – Ensollset show-mode-in-prompt on
very well. – Ensollrlwrap
withset show-mode-in-prompt on
? – NutritiousNODE_NO_READLINE=1
but it works nicely withNODE_NO_READLINE=1
. – Ensoll