feat(lua): show proper verbose output for lua configuration

`:verbose` didn't work properly with lua configs (For example:
    options or keymaps are set from lua, just say that they were set
    from lua, doesn't say where they were set at.

This fixes that issue. Now `:verbose` will provide filename and line no
when option/keymap is set from lua.

Changes:
  - compiles lua/vim/keymap.lua as vim/keymap.lua
 - When souring a lua file current_sctx.sc_sid is set to SID_LUA
 - Moved finding scripts SID out of `do_source()` to `get_current_script_id()`.
   So it can be reused for lua files.
 - Added new function `nlua_get_sctx` that extracts current lua scripts
   name and line no with debug library. And creates a sctx for it.
     NOTE: This function ignores C functions and blacklist which
     currently contains only vim/_meta.lua so vim.o/opt wrappers aren't
     targeted.
 - Added function `nlua_set_sctx` that changes provided sctx to current
   lua scripts sctx if a lua file is being executed.
 - Added tests in tests/functional/lua/verbose_spec.lua
 - add primary support for additional types (:autocmd, :function, :syntax) to lua verbose
    Note: These can't yet be directly set from lua but once that's possible
    :verbose should work for them hopefully :D
 - add :verbose support for nvim_exec & nvim_command within lua
    Currently auto commands/commands/functions ... can only be defined
    by nvim_exec/nvim_command this adds support for them. Means if those
    Are defined within lua with vim.cmd/nvim_exec :verbose will show their
    location . Though note it'll show the line no on which nvim_exec call was made.
This commit is contained in:
shadmansaleh
2022-01-08 00:39:44 +06:00
parent e383543342
commit ebfe083337
22 changed files with 359 additions and 71 deletions

View File

@@ -16,6 +16,7 @@
#include "nvim/change.h"
#include "nvim/cursor.h"
#include "nvim/eval/userfunc.h"
#include "nvim/eval/typval.h"
#include "nvim/event/loop.h"
#include "nvim/event/time.h"
#include "nvim/ex_cmds2.h"
@@ -652,6 +653,15 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// [package, loaded, module]
lua_setfield(lstate, -2, "vim.filetype"); // [package, loaded]
code = (char *)&lua_keymap_module[0];
if (luaL_loadbuffer(lstate, code, sizeof(lua_keymap_module) - 1, "@vim/keymap.lua")
|| nlua_pcall(lstate, 0, 1)) {
nlua_error(lstate, _("E5106: Error while creating vim.keymap module: %.*s"));
return 1;
}
// [package, loaded, module]
lua_setfield(lstate, -2, "vim.keymap"); // [package, loaded]
lua_pop(lstate, 2); // []
}
@@ -1808,6 +1818,69 @@ void nlua_execute_on_key(int c)
#endif
}
// Checks if str is in blacklist array
static bool is_in_ignorelist(const char *str, char *ignorelist[], int ignorelist_size)
{
for (int i = 0; i < ignorelist_size; i++) {
if (strncmp(ignorelist[i], str, strlen(ignorelist[i])) == 0) {
return true;
}
}
return false;
}
// Get sctx of current file being sourced if doesn't exist generate it
static sctx_T *nlua_get_sourcing_sctx(void)
{
lua_State *const lstate = global_lstate;
sctx_T *retval = (sctx_T *)xmalloc(sizeof(sctx_T));
retval->sc_seq = -1;
retval->sc_sid = SID_LUA;
retval->sc_lnum = -1;
lua_Debug *info = (lua_Debug *)xmalloc(sizeof(lua_Debug));
// Files where internal wrappers are defined so we can ignore them
// like vim.o/opt etc are defined in _meta.lua
char *ignorelist[] = {
"vim/_meta.lua",
"vim/keymap.lua",
};
int blacklist_size = sizeof(ignorelist) / sizeof(ignorelist[0]);
for (int level = 1; true; level++) {
if (lua_getstack(lstate, level, info) != 1) {
goto cleanup;
}
if (lua_getinfo(lstate, "nSl", info) == 0) {
goto cleanup;
}
if (info->what[0] == 'C' || info->source[0] != '@'
|| is_in_ignorelist(info->source+1, ignorelist, blacklist_size)) {
continue;
}
break;
}
char *source_path = fix_fname(info->source + 1);
get_current_script_id((char_u *)source_path, retval);
xfree(source_path);
retval->sc_lnum = info->currentline;
cleanup:
xfree(info);
return retval;
}
// Sets the editor "script context" during Lua execution. Used by :verbose.
// @param[out] current
void nlua_set_sctx(sctx_T *current)
{
if (p_verbose > 0 && current->sc_sid == SID_LUA) {
sctx_T *lua_sctx = nlua_get_sourcing_sctx();
*current = *lua_sctx;
xfree(lua_sctx);
}
}
void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap)
{
lua_State *const lstate = global_lstate;