I’ve experimented a bit with various readline implementations in Perl. There’s quite a few on the CPAN, like you’d expect.
I’ve used Term::ReadLine::Gnu for some projects; most notably the shell functionality in pimpd2 and I thought it was pretty good. The only thing missing was a sane keymap (that is, a vi-mode).
So I went looking for modules that might support this. The first hit was Term::ReadLine::Zoid with its subclass ViCommand. This was spot on.
A nice thing with the readline implementations is that they’re all compatible; you don’t have to change the codebase if you switch module. So I had a snippet like this:
This simple REPL tabcompletes to the imported symbols from the B::Keywords package, and it works like you’d expect with Term::ReadLine::Gnu. To try this out with Term::ReadLine::Zoid we execute it like so;
The vi-mode worked out of the box and I played with it for a bit. Then I noticed that using f, F, t, or T in normal mode didn’t work quite so well;
Alright. Obvious what happens here; the ‘(‘ is being treated as a pattern metacharacter by the regex compiler. Should be an easy fix.
I’ve sent the patch upstream; the module hasn’t been updated since 2004 though, so just in case a fork can be found here, and the diff here. After applying that fix, the vi-mode worked just fine. So time to find another obstacle…
Term::ReadLine::Zoid does not come with a completion function by default. The completion function I defined in the above code snippet simply returned all strings in the @Symbols array every time TAB was pressed. Not what I want. So this means I’ll have to create a new completion function from scratch and inject it into Zoid. Or does it?
I started reading the documentation one more time. I had missed a very important thing in the Zoid documentation:
It features almost all key-bindings described in the posix spec for the sh(1) utility with some extensions like multiline editing; this includes a vi-command mode with a save-buffer (for copy-pasting) and an undo-stack.
I couldn’t see why the Gnu implementation wouldn’t support this. So I turned to the mighty interweb and found a reference to RL_STATE_VIMOTION. This should mean there is support for vi-mode, even though not explicitly stated in the documentation… The ‘Selecting a Keymap’ section caught my eye.
Not that much of a description, but let’s play around a bit…
And there we have it; a nice, working tabcompletion and a sane keymap. Time to write a sane REPL, using the module I first started out with 2 hours ago…