So I want to make a layer that emulates the vi movement and editing commands.
I was thinking it would be best to use the Leader plugin to make a lookup table aliasing each vi command to a sequence of keys that does what I need it to.
For instance 2dw would get mapped to shift-control right arrow right arrow delete.
Now do I need to separately define 2dw, 3dw, 4dw, etc. or is there a way to recognize a one or two digit number typed and repeat a command that many times?
I don’t want to have to enter the leader key for each new command - is there a way to make it automatic?
One possibility might be to set up a macro where the “switch to vi layer” key automatically presses the leader key and then each defined sequence ends with the leader key - but is there a time delay to enter a sequence after pressing the leader key?
Or is there a better way to do this than using Leader?
I think the most practical thing would be to have a “vi layer”, where you have a couple of macros: numbers would be macros that do nothing, but accumulate the numbers you press. d would flip a boolean that will signal deletion, but do nothing otherwise. w would be the trigger that executes the command, by looking at the boolean that d set, and repeating the command N times.
Something along these lines:
static struct {
uint8_t repeat_number;
enum {
NOTHING,
DELETE
} command;
} vi_state;
// add the following to the macro enum:
enum {
VI_0,
VI_1,
// ...
VI_D,
VI_W,
};
void macroViNumber(uint8_t macro_index, uint8_t key_state) {
if (!keyToggledOn(key_state))
return;
vi_state.repeat_number = vi_state.repeat_number * 10 + (macro_index - VI_0);
}
void viExecute(void) {
switch (vi_state.command) {
case NOTHING:
break;
case DELETE:
// Press Shift + Control
Macro.play(MACRO(D(LeftShift), D(LeftControl)));
// Press & Release RightArrow N times
for (uint8_t i = 0; i < vi_state.repeat_number; i++) {
Macro.play(MACRO(T(RightArrow)));
}
// Release Shift + Control, then tap Delete
Macro.play(MACRO(U(LeftShift), U(LeftControl), T(Delete)));
break;
}
}
void macroViCommand(uint8_t macro_index, uint8_t key_state) {
if (!keyToggledOn(key_state))
return;
switch (macro_index) {
case VI_D:
vi_state.command = DELETE;
break;
case VI_W: {
viExecute();
vi_state.command = NOTHING;
vi_state.repeat_number = 0;
}
}
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
switch (macroIndex) {
case VI_0 ... VI_9:
macroViNumber(macroIndex, keyState);
break;
case VI_D:
case VI_W:
macroViCommand(macroIndex, keyState);
break;
}
return MACRO_NONE;
}
// On the VI layer:
M(VI_1), M(VI_2), ....
I would think the biggest hurdle would be that you can’t delete words because the keyboard has no idea where the words are on the screen. You would have to find a way to communicate back to the keyboard where the next is.