Open silasdb opened 3 years ago
Well that does make sense? When :map! normal 3 j
, 23j
means move down twice, move down. I think 0 is a special case here because you're never start a count with 0. I'm not sure we'd want to add more special cases in case someone maps these numbers.
Indeed, "0" is the important case here. Maybe it makes more sense to just implement a generic solution for any digit than for zero only, but I'm not familiar to the code to claim that.
Maybe it makes more sense to just implement a generic solution for any digit @silasdb
A "count-pending" mode, perhaps? A digit in normal/visual mode would switch to count-pending mode, which would only accept digits, and would go back to normal/visual (or switch to operator-pending) mode on the first non-digit key press.
A digit that was remapped would not cause a switch to count-pending mode, because the code that makes the switch won't see it as a digit. Then 0
could be "implemented" via such a mapping, without being a special case in the lower levels of the code.
Easier said than done, though.
I agree that a sub mode is the right way to properly fix this. There are however a few peculiarities to consider:
Key binding functions can currently indicate that not enough input
is available by returning NULL
. However, there is no way to
switch to a different mode and force immediate re-evaluation of the
current mapping.
We could check whether the mode was changed by a key binding function and process it again. This would result in an endless loop if two modes have the same binding which switches between them.
Modes currently have a boolean flag (visual
), indicating whether
they support non-singleton selections. This doesn't really make sense
for something like a count pending mode which can be entered from
both normal and visual(-line) modes. As an example, selections should
not be cleared when switching from visual to count pending mode.
More generally, this begs the question whether we should always be in some form of a visual mode and only provide a way to fix/anchor a selection endpoint. This would also resolve some of the inconsistencies mentioned in #886.
Mode history. We currently keep track of the previous (regular i.e. non
operator pending) mode. This is for example used to switch back from
operator pending mode to either insert/replace (after <C-w>
) or to
normal mode (after dw
). This can also be used when encountering a
non-digit input in the pending count mode, to switch back to either
normal or visual mode.
However, if we embrace a more dynamic scenario with multiple sub modes this might no longer be enough. It might make sense to use a stack to keep track of the modes. Entering pending count would push it onto the mode stack, when leaving we pop it and yield control to the previous mode.
I hacked up a quick prototype how such a count sub mode could work with minimal changes. As you can see it still contains a few ugly corner cases.
You can use "count" parameters to many commands, like:
13dd -> delete next 13 lines
But digits get useless after you've remapped them to something else, even if they are not the first number. Try:
:map! normal 3
Now try to pass a count to a parameter that uses digit "3". E.g.: Go to 23th line: 23G . It fails.
I noticed this after trying to reverse "^" and "0".