feat(lua): vim.keycode() gets structured parse result #38636

Problems:
1. Can't get individual parts of a key-chord separately: modifiers, key.
2. Can't separate a key-combo into individual key-chords.

Solution:
Enhance `vim.keycode()` to optionally return a structured parse result
as a list of key-chords:
- `key_raw` the key-chord (problem 2)
- `mod` the modifiers of `key_raw` (problem 1)
- `key_orig` the key part of the key-chord, only here if differing from `key`
  (this doesn't solve any of the above mentioned problems, but it may provide
  useful and it's (in terms of code) free)
- `key` a normalized version of `key_orig` (solving problem 1), example(the
  first is `key_orig` and second is `key`): `lt` and `<`, `Bar` and `|` (in
  `<C-Bar>`)
This commit is contained in:
altermo
2026-07-18 18:20:41 +02:00
committed by GitHub
parent 952e59347e
commit a2dfa195b2
14 changed files with 263 additions and 35 deletions

View File

@@ -31,6 +31,7 @@
#include "nvim/ex_eval.h"
#include "nvim/fold.h"
#include "nvim/globals.h"
#include "nvim/keycodes.h"
#include "nvim/lua/base64.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/spell.h"
@@ -41,6 +42,7 @@
#include "nvim/mbyte_defs.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message_defs.h"
#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
#include "nvim/regexp_defs.h"
@@ -678,6 +680,51 @@ static int nlua_with(lua_State *L)
return rets;
}
// Parses internal representation of key into detailed dict about each key chord.
static int nlua_keyarg(lua_State *L)
{
luaL_argcheck(L, lua_isstring(L, 1), 1, "string expected");
char *escaped = vim_strsave_escape_ks((char *)lua_tostring(L, 1));
const char *p = escaped;
lua_newtable(L);
struct keycode_data data;
while (*p != NUL) {
const char *key = str2special(&p, true, true, &data);
lua_createtable(L, 0, 3);
lua_newtable(L);
for (int i = 0; mod_mask_table[i].name != 'A'; i++) {
if ((data.modifiers & mod_mask_table[i].mod_mask) == mod_mask_table[i].mod_flag) {
lua_pushlstring(L, &mod_mask_table[i].name, 1);
lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1);
}
}
lua_setfield(L, -2, "mod");
lua_pushlstring(L, data.key.data, data.key.size);
lua_setfield(L, -2, "key");
lua_pushstring(L, key);
lua_setfield(L, -2, "key_raw");
if (data.key_orig.size != 0) {
lua_pushlstring(L, data.key_orig.data, data.key_orig.size);
lua_setfield(L, -2, "key_orig");
}
lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1);
}
xfree(escaped);
return 1;
}
// Access to internal functions. For use in runtime/
static void nlua_state_add_internal(lua_State *const lstate)
{
@@ -695,6 +742,9 @@ static void nlua_state_add_internal(lua_State *const lstate)
lua_pushcfunction(lstate, &nlua_with);
lua_setfield(lstate, -2, "_with_c");
lua_pushcfunction(lstate, &nlua_keyarg);
lua_setfield(lstate, -2, "_keyarg");
}
void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)