Behind the scenes, vim mode's code is cleaner and more flexible than I dared hoped. The connections between the code in leoVim.py and the rest of Leo are trivial. This present code is far simpler than that implied by previous designs.
But the actual code is the least impressive part of the project. There are at least three other dimensions in which vim mode is *far* better than I ever dared to expect.
1. vim-mode bindings coexist with existing Leo bindings, *whatever* they are. Folks, this is a completely unexpected state of affairs.
I never dreamed that *all* of my Alt and Ctrl bindings would play perfectly well with vim mode. This includes Alt-X, Ctrl-G, Escape, all arrow keys, of whatever kind, and *all* of the key bindings to Leo's commands. *Everything* in Leo's existing key bindings stays just as they are, with the *addition* of plain key binding for any and all text widgets: the body pane, the log pane, and all headlines being edited. Furthermore, some vim-mode plain-key bindings have natural extensions to the outline pane. For example, the h key works just like LtArrow (or Alt-LtArrow) in the outline pane.
It's hard to overstate how important this is. Previously, I imagined that substantial changes would have to be made to accommodate Leo's more complex environment. The reverse is true: Leo's complex environment provides ways of *extending* the operation of vim bindings. For example, y and p yank and paste *outlines* when focus is in the outline pane. So, rather than having to *sacrifice* vim's standard plain-key bindings, Leo provides *more* space for plain-key vim bindings. This is an absolute revolution in my thinking.
2. vim-mode commands coexist with exiting commands
The implications of this just started to become apparent last night as I was creating the :r command. The format of this command is :r <filename> The :r command loads the contents of the given file at the insertion point.
I wouldn't call this command a must-have, but it has lead my thoughts in new and happy directions. As so often happens, design Aha's arose from mundane considerations, in this case, questions of how to best emulate vim's treatment of the :r command, and especially the thorny questions about how to emulate vim's almost endless forms of :% (text substitution) commands. I'll discuss these details in the P.P.S. It is basically an ENB
(Engineering Note Book) entry. Feel free to ignore it.
3. Vim commands suggest further improvements, even when vim mode is not in effect.
Ok. Let's assume that Leo will soon be able to parse minibuffer text that contains both a command name and one or more arguments. As I was testing the :r command, it quickly became obvious that I needed help in typing the file name argument. Yes, I could use :!ls to print the contents of the cwd, but that would suck: the listing appears in the console window, and provides no typing completion.
This morning I saw that the solution would be something like emacs dired:
https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html That is, it would be a Leo tab that would offer filename browsing and typing completion, much like Leo's 'Completion' and 'Autocomplete' tabs do for minibuffer and code completion.
The code for every kind of completion tab is hairy, but a filename completion/browsing tab would be useful not just for vim commands. Imo, Leo must have this.
===== Summary
The :!, :r commands, etc. are *always* available, even if vim-mode is not enabled.
Regardless of one's thoughts about vim's key bindings, more flexible minibuffer parsing and filename completion will be important new features for all of Leo.
Edward
P.S. Apparently nobody has used Leo's shell-command command in ages. Or maybe they tried it and gave up on Leo. Boo hoo.
I tried this command while preparing to do the :! command. It crashed. Furthermore, the code was so old it did not use the log pane for messages.
A recent rev now makes shell-command usable, and also adds the :! command.
P.P.S. An Engineering Notebook entry:
At present, typing ':' in vim normal mode puts you into the minibuffer. You can then type <tab> to get the list of all vim-related commands, that is, all commands starting with ":". Among them, you will see :r. So it must be true that typing ':r<return>' will execute this command. And indeed it does.
But in vim itself, you just type :r <filename><return>.
More importantly, in vim, you would type::
:% s/text/replaced text/g<return>
not::
:%<RETURN>s/text/replaced text/g<return>
Here is how Leo's Alt-X code (in k.fullCommand) will be extended to handle colon commands. The present code assumes that the entire contents of the minibuffer contains a command name. It computes the command name with this line of code::
commandName = s[len(helpPrompt):].strip()
This won't work for the :r command or any other command that takes arguments. k.fullCommand will use different command dispatching scheme if the minibuffer starts with ':'. In that case, k.fullCommand will look only at the prefix of the command, everything before a blank, or, for commands that end in a non-letter (like :!), everything until a blank or letter. k.fullCommand may need to call a vc callback to make this work, but it is clearly doable.
So this is good. We now have a way of emulating exactly how colon commands work, *without* having to do lots of parsing.
EKR