diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 17:57:01 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 17:57:01 +0000 |
| commit | 9837de570c5972f98e74848edc97c297a13136ea (patch) | |
| tree | cc948611912d116a3f98a744e690d3d7b6e2f59a /src/nvim/lua | |
| parent | c367400b73d207833d51e09d663f969ffab37531 (diff) | |
| parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
| download | rneovim-9837de570c5972f98e74848edc97c297a13136ea.tar.gz rneovim-9837de570c5972f98e74848edc97c297a13136ea.tar.bz2 rneovim-9837de570c5972f98e74848edc97c297a13136ea.zip | |
Merge remote-tracking branch 'upstream/master' into colorcolchar
Diffstat (limited to 'src/nvim/lua')
| -rw-r--r-- | src/nvim/lua/converter.c | 18 | ||||
| -rw-r--r-- | src/nvim/lua/executor.c | 253 | ||||
| -rw-r--r-- | src/nvim/lua/executor.h | 4 | ||||
| -rw-r--r-- | src/nvim/lua/spell.c | 18 | ||||
| -rw-r--r-- | src/nvim/lua/stdlib.c | 93 | ||||
| -rw-r--r-- | src/nvim/lua/treesitter.c | 25 | ||||
| -rw-r--r-- | src/nvim/lua/xdiff.c | 147 |
7 files changed, 392 insertions, 166 deletions
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index bdb0719809..6160b84485 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -4,14 +4,14 @@ #include <assert.h> #include <lauxlib.h> #include <lua.h> -#include <lualib.h> #include <stdbool.h> +#include <stddef.h> #include <stdint.h> +#include <stdlib.h> +#include <string.h> #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/assert.h" -#include "nvim/func_attr.h" #include "nvim/memory.h" // FIXME: vim.h is not actually needed, but otherwise it states MAXPATHL is // redefined @@ -19,12 +19,16 @@ #include "nvim/ascii.h" #include "nvim/eval/decode.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" +#include "nvim/eval/typval_encode.h" #include "nvim/eval/userfunc.h" -#include "nvim/globals.h" +#include "nvim/garray.h" +#include "nvim/gettext.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/macros.h" #include "nvim/message.h" +#include "nvim/types.h" #include "nvim/vim.h" /// Determine, which keys lua table contains @@ -387,7 +391,7 @@ nlua_pop_typval_table_processing_end: case LUA_TFUNCTION: { LuaRef func = nlua_ref_global(lstate, -1); - char *name = (char *)register_luafunc(func); + char *name = register_luafunc(func); cur.tv->v_type = VAR_FUNC; cur.tv->vval.v_string = xstrdup(name); @@ -565,6 +569,7 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_FIRST_ARG_TYPE lua_State *const #define TYPVAL_ENCODE_FIRST_ARG_NAME lstate #include "nvim/eval/typval_encode.c.h" + #undef TYPVAL_ENCODE_SCOPE #undef TYPVAL_ENCODE_NAME #undef TYPVAL_ENCODE_FIRST_ARG_TYPE @@ -906,9 +911,8 @@ Float nlua_pop_Float(lua_State *lstate, Error *err) lua_pop(lstate, 1); if (table_props.type != kObjectTypeFloat) { return 0; - } else { - return (Float)table_props.val; } + return (Float)table_props.val; } /// Convert lua table to array without determining whether it is array diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index f3821f149a..5ffd90fddd 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1,18 +1,22 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include <assert.h> +#include <inttypes.h> #include <lauxlib.h> #include <lua.h> #include <lualib.h> +#include <stddef.h> +#include <string.h> #include <tree_sitter/api.h> +#include <uv.h> +#include "klib/kvec.h" #include "luv/luv.h" #include "nvim/api/extmark.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" #include "nvim/ascii.h" -#include "nvim/assert.h" #include "nvim/buffer_defs.h" #include "nvim/change.h" #include "nvim/cursor.h" @@ -20,30 +24,39 @@ #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" +#include "nvim/event/defs.h" #include "nvim/event/loop.h" +#include "nvim/event/multiqueue.h" #include "nvim/event/time.h" #include "nvim/ex_cmds.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_getln.h" -#include "nvim/extmark.h" -#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/keycodes.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/lua/stdlib.h" #include "nvim/lua/treesitter.h" #include "nvim/macros.h" -#include "nvim/map.h" +#include "nvim/main.h" #include "nvim/memline.h" +#include "nvim/memory.h" #include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/option_defs.h" +#include "nvim/os/fileio.h" #include "nvim/os/os.h" +#include "nvim/path.h" +#include "nvim/pos.h" #include "nvim/profile.h" #include "nvim/runtime.h" -#include "nvim/screen.h" +#include "nvim/strings.h" #include "nvim/ui.h" -#include "nvim/ui_compositor.h" #include "nvim/undo.h" #include "nvim/usercmd.h" #include "nvim/version.h" @@ -192,8 +205,8 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags if (status) { if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) { // consider out of memory errors unrecoverable, just like xmalloc() - mch_errmsg(e_outofmem); - mch_errmsg("\n"); + os_errmsg(e_outofmem); + os_errmsg("\n"); preserve_exit(); } const char *error = lua_tostring(lstate, -1); @@ -245,8 +258,8 @@ static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nres if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) { // Terminate this thread, as the main thread may be able to continue // execution. - mch_errmsg(e_outofmem); - mch_errmsg("\n"); + os_errmsg(e_outofmem); + os_errmsg("\n"); lua_close(lstate); #ifdef MSWIN ExitThread(0); @@ -310,6 +323,36 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate) return 1; } +/// Copies args starting at `lua_arg0` to Lua `_G.arg`, and sets `_G.arg[0]` to the scriptname. +/// +/// Example (arg[0] => "foo.lua", arg[1] => "--arg1", …): +/// nvim -l foo.lua --arg1 --arg2 +/// +/// @note Lua CLI sets args before "-e" as _negative_ `_G.arg` indices, but we currently don't. +/// +/// @see https://www.lua.org/pil/1.4.html +/// @see https://github.com/premake/premake-core/blob/1c1304637f4f5e50ba8c57aae8d1d80ec3b7aaf2/src/host/premake.c#L563-L594 +/// +/// @returns number of args +static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg0) +{ + int i = 0; + lua_newtable(L); // _G.arg + + if (lua_arg0 > 0) { + lua_pushstring(L, argv[lua_arg0 - 1]); + lua_rawseti(L, -2, 0); // _G.arg[0] = "foo.lua" + + for (; lua_arg0 >= 0 && i + lua_arg0 < argc; i++) { + lua_pushstring(L, argv[i + lua_arg0]); + lua_rawseti(L, -2, i + 1); // _G.arg[i+1] = "--foo" + } + } + + lua_setglobal(L, "arg"); + return i; +} + static void nlua_schedule_event(void **argv) { LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; @@ -400,7 +443,7 @@ static int nlua_wait(lua_State *lstate) bool fast_only = false; if (lua_top >= 4) { - fast_only = lua_toboolean(lstate, 4); + fast_only = lua_toboolean(lstate, 4); } MultiQueue *loop_events = fast_only || in_fast_callback > 0 @@ -585,8 +628,8 @@ static bool nlua_init_packages(lua_State *lstate) lua_getglobal(lstate, "require"); lua_pushstring(lstate, "vim._init_packages"); if (nlua_pcall(lstate, 1, 0)) { - mch_errmsg(lua_tostring(lstate, -1)); - mch_errmsg("\n"); + os_errmsg((char *)lua_tostring(lstate, -1)); + os_errmsg("\n"); return false; } @@ -640,7 +683,7 @@ ok: } LuaRef ui_event_cb = nlua_ref_global(lstate, 3); - ui_comp_add_cb(ns_id, ui_event_cb, ext_widgets); + ui_add_cb(ns_id, ui_event_cb, ext_widgets); return 0; } @@ -654,7 +697,7 @@ static int nlua_ui_detach(lua_State *lstate) return luaL_error(lstate, "invalid ns_id"); } - ui_comp_remove_cb(ns_id); + ui_remove_cb(ns_id); return 0; } @@ -752,10 +795,8 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return true; } -/// Initialize global lua interpreter -/// -/// Crashes Nvim if initialization fails. -void nlua_init(void) +/// Initializes global Lua interpreter, or exits Nvim on failure. +void nlua_init(char **argv, int argc, int lua_arg0) { #ifdef NLUA_TRACK_REFS const char *env = os_getenv("NVIM_LUA_NOTRACK"); @@ -766,20 +807,19 @@ void nlua_init(void) lua_State *lstate = luaL_newstate(); if (lstate == NULL) { - mch_errmsg(_("E970: Failed to initialize lua interpreter\n")); + os_errmsg(_("E970: Failed to initialize lua interpreter\n")); os_exit(1); } luaL_openlibs(lstate); if (!nlua_state_init(lstate)) { - mch_errmsg(_("E970: Failed to initialize builtin lua modules\n")); + os_errmsg(_("E970: Failed to initialize builtin lua modules\n")); os_exit(1); } luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem); - global_lstate = lstate; - main_thread = uv_thread_self(); + nlua_init_argv(lstate, argv, argc, lua_arg0); } static lua_State *nlua_thread_acquire_vm(void) @@ -1012,8 +1052,8 @@ static int nlua_require(lua_State *const lstate) time_push(&rel_time, &start_time); int status = lua_pcall(lstate, 1, 1, 0); if (status == 0) { - vim_snprintf((char *)IObuff, IOSIZE, "require('%s')", name); - time_msg((char *)IObuff, &start_time); + vim_snprintf(IObuff, IOSIZE, "require('%s')", name); + time_msg(IObuff, &start_time); } time_pop(rel_time); @@ -1177,6 +1217,7 @@ static int nlua_rpc(lua_State *lstate, bool request) api_set_error(&err, kErrorTypeValidation, "Invalid channel: %" PRIu64, chan_id); } + api_free_array(args); // TODO(bfredl): no } check_err: @@ -1301,7 +1342,7 @@ void nlua_typval_eval(const String str, typval_T *const arg, typval_T *const ret const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str.size + 1; char *lcmd; if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; + lcmd = IObuff; } else { lcmd = xmalloc(lcmd_len); } @@ -1311,7 +1352,7 @@ void nlua_typval_eval(const String str, typval_T *const arg, typval_T *const ret #undef EVALHEADER nlua_typval_exec(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv); - if (lcmd != (char *)IObuff) { + if (lcmd != IObuff) { xfree(lcmd); } } @@ -1325,7 +1366,7 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg const size_t lcmd_len = sizeof(CALLHEADER) - 1 + len + sizeof(CALLSUFFIX) - 1; char *lcmd; if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; + lcmd = IObuff; } else { lcmd = xmalloc(lcmd_len); } @@ -1338,7 +1379,7 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg nlua_typval_exec(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv); - if (lcmd != (char *)IObuff) { + if (lcmd != IObuff) { xfree(lcmd); } } @@ -1399,11 +1440,11 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) estack_push(ETYPE_SCRIPT, name, 0); garray_T ga; - char_u *line = NULL; + char *line = NULL; - ga_init(&ga, (int)sizeof(char_u *), 10); - while ((line = (char_u *)fgetline(0, cookie, 0, false)) != NULL) { - GA_APPEND(char_u *, &ga, line); + ga_init(&ga, (int)sizeof(char *), 10); + while ((line = fgetline(0, cookie, 0, false)) != NULL) { + GA_APPEND(char *, &ga, line); } char *code = ga_concat_strings_sep(&ga, "\n"); size_t len = strlen(code); @@ -1604,7 +1645,7 @@ void ex_luado(exarg_T *const eap) + (sizeof(DOEND) - 1)); char *lcmd; if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; + lcmd = IObuff; } else { lcmd = xmalloc(lcmd_len + 1); } @@ -1672,21 +1713,51 @@ void ex_luafile(exarg_T *const eap) nlua_exec_file((const char *)eap->arg); } -/// execute lua code from a file. +/// Executes Lua code from a file or "-" (stdin). /// -/// Note: we call the lua global loadfile as opposed to calling luaL_loadfile -/// in case loadfile has been overridden in the users environment. +/// Calls the Lua `loadfile` global as opposed to `luaL_loadfile` in case `loadfile` was overridden +/// in the user environment. /// -/// @param path path of the file +/// @param path Path to the file, may be "-" (stdin) during startup. /// -/// @return true if everything ok, false if there was an error (echoed) +/// @return true on success, false on error (echoed) or user canceled (CTRL-c) while reading "-" +/// (stdin). bool nlua_exec_file(const char *path) FUNC_ATTR_NONNULL_ALL { lua_State *const lstate = global_lstate; + if (!strequal(path, "-")) { + lua_getglobal(lstate, "loadfile"); + lua_pushstring(lstate, path); + } else { + FileDescriptor *stdin_dup = file_open_stdin(); + + StringBuilder sb = KV_INITIAL_VALUE; + kv_resize(sb, 64); + ptrdiff_t read_size = -1; + // Read all input from stdin, unless interrupted (ctrl-c). + while (true) { + if (got_int) { // User canceled. + return false; + } + read_size = file_read(stdin_dup, IObuff, 64); + if (read_size < 0) { // Error. + return false; + } + if (read_size > 0) { + kv_concat_len(sb, IObuff, (size_t)read_size); + } + if (read_size < 64) { // EOF. + break; + } + } + kv_push(sb, NUL); + file_free(stdin_dup, false); - lua_getglobal(lstate, "loadfile"); - lua_pushstring(lstate, path); + lua_getglobal(lstate, "loadstring"); + lua_pushstring(lstate, sb.items); + kv_destroy(sb); + } if (nlua_pcall(lstate, 1, 2)) { nlua_error(lstate, _("E5111: Error calling lua: %.*s")); @@ -1758,7 +1829,7 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_setfield(lstate, -2, "_ts_get_minimum_language_version"); } -int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results) +int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results) { lua_State *const lstate = global_lstate; int ret = OK; @@ -1771,7 +1842,7 @@ int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results luaL_checktype(lstate, -1, LUA_TFUNCTION); // [ vim, vim._expand_pat, buf ] - lua_pushlstring(lstate, (const char *)pat, STRLEN(pat)); + lua_pushlstring(lstate, (const char *)pat, strlen(pat)); if (nlua_pcall(lstate, 1, 2) != 0) { nlua_error(lstate, @@ -1806,7 +1877,7 @@ int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results goto cleanup_array; } - GA_APPEND(char_u *, &result_array, (char_u *)string_to_cstr(v.data.string)); + GA_APPEND(char *, &result_array, string_to_cstr(v.data.string)); } xp->xp_pattern += prefix_len; @@ -1832,7 +1903,7 @@ static int nlua_is_thread(lua_State *lstate) return 1; } -bool nlua_is_table_from_lua(typval_T *const arg) +bool nlua_is_table_from_lua(const typval_T *const arg) { if (arg->v_type == VAR_DICT) { return arg->vval.v_dict->lua_table_ref != LUA_NOREF; @@ -1843,7 +1914,7 @@ bool nlua_is_table_from_lua(typval_T *const arg) } } -char_u *nlua_register_table_as_callable(typval_T *const arg) +char *nlua_register_table_as_callable(const typval_T *const arg) { LuaRef table_ref = LUA_NOREF; if (arg->v_type == VAR_DICT) { @@ -1879,7 +1950,7 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) LuaRef func = nlua_ref_global(lstate, -1); - char_u *name = register_luafunc(func); + char *name = register_luafunc(func); lua_pop(lstate, 1); // [] assert(top == lua_gettop(lstate)); @@ -1889,8 +1960,8 @@ char_u *nlua_register_table_as_callable(typval_T *const arg) void nlua_execute_on_key(int c) { - char_u buf[NUMBUFLEN]; - size_t buf_len = special_to_buf(c, mod_mask, false, buf); + char buf[NUMBUFLEN]; + size_t buf_len = special_to_buf(c, mod_mask, false, (char_u *)buf); lua_State *const lstate = global_lstate; @@ -1906,7 +1977,7 @@ void nlua_execute_on_key(int c) luaL_checktype(lstate, -1, LUA_TFUNCTION); // [ vim, vim._on_key, buf ] - lua_pushlstring(lstate, (const char *)buf, buf_len); + lua_pushlstring(lstate, buf, buf_len); int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C @@ -1985,6 +2056,9 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) nlua_pushref(lstate, preview ? cmd->uc_preview_luaref : cmd->uc_luaref); lua_newtable(lstate); + lua_pushstring(lstate, cmd->uc_name); + lua_setfield(lstate, -2, "name"); + lua_pushboolean(lstate, eap->forceit == 1); lua_setfield(lstate, -2, "bang"); @@ -2177,3 +2251,80 @@ plain: kv_printf(str, "<Lua %d>", ref); return str.items; } + +char *nlua_read_secure(const char *path) +{ + lua_State *const lstate = global_lstate; + const int top = lua_gettop(lstate); + + lua_getglobal(lstate, "vim"); + lua_getfield(lstate, -1, "secure"); + lua_getfield(lstate, -1, "read"); + lua_pushstring(lstate, path); + if (nlua_pcall(lstate, 1, 1)) { + nlua_error(lstate, _("Error executing vim.secure.read: %.*s")); + lua_settop(lstate, top); + return NULL; + } + + size_t len = 0; + const char *contents = lua_tolstring(lstate, -1, &len); + char *buf = NULL; + if (contents != NULL) { + // Add one to include trailing null byte + buf = xcalloc(len + 1, sizeof(char)); + memcpy(buf, contents, len + 1); + } + + lua_settop(lstate, top); + return buf; +} + +bool nlua_trust(const char *action, const char *path) +{ + lua_State *const lstate = global_lstate; + const int top = lua_gettop(lstate); + + lua_getglobal(lstate, "vim"); + lua_getfield(lstate, -1, "secure"); + lua_getfield(lstate, -1, "trust"); + + lua_newtable(lstate); + lua_pushstring(lstate, "action"); + lua_pushstring(lstate, action); + lua_settable(lstate, -3); + if (path == NULL) { + lua_pushstring(lstate, "bufnr"); + lua_pushnumber(lstate, 0); + lua_settable(lstate, -3); + } else { + lua_pushstring(lstate, "path"); + lua_pushstring(lstate, path); + lua_settable(lstate, -3); + } + + if (nlua_pcall(lstate, 1, 2)) { + nlua_error(lstate, _("Error executing vim.secure.trust: %.*s")); + lua_settop(lstate, top); + return false; + } + + bool success = lua_toboolean(lstate, -2); + const char *msg = lua_tostring(lstate, -1); + if (msg != NULL) { + if (success) { + if (strcmp(action, "allow") == 0) { + smsg("Allowed \"%s\" in trust database.", msg); + } else if (strcmp(action, "deny") == 0) { + smsg("Denied \"%s\" in trust database.", msg); + } else if (strcmp(action, "remove") == 0) { + smsg("Removed \"%s\" from trust database.", msg); + } + } else { + semsg(e_trustfile, msg); + } + } + + lua_settop(lstate, top); + return success; +} diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index 78346fd81f..c6747833e5 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -3,13 +3,17 @@ #include <lauxlib.h> #include <lua.h> +#include <stdbool.h> #include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" #include "nvim/assert.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" #include "nvim/func_attr.h" #include "nvim/lua/converter.h" +#include "nvim/macros.h" +#include "nvim/types.h" #include "nvim/usercmd.h" // Generated by msgpack-gen.lua diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index 31a2b2d19f..d510d25e90 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -1,15 +1,25 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include <assert.h> #include <lauxlib.h> +#include <limits.h> #include <lua.h> - +#include <stdbool.h> +#include <stddef.h> + +#include "nvim/ascii.h" +#include "nvim/buffer_defs.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/highlight_defs.h" #include "nvim/lua/spell.h" +#include "nvim/message.h" #include "nvim/spell.h" -#include "nvim/vim.h" +#include "nvim/types.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "lua/spell.c.generated.h" +# include "lua/spell.c.generated.h" // IWYU pragma: export #endif int nlua_spell_check(lua_State *lstate) @@ -51,7 +61,7 @@ int nlua_spell_check(lua_State *lstate) while (*str != NUL) { attr = HLF_COUNT; - len = spell_check(curwin, (char_u *)str, &attr, &capcol, false); + len = spell_check(curwin, (char *)str, &attr, &capcol, false); assert(len <= INT_MAX); if (attr != HLF_COUNT) { diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 2f46f6ff65..6ebca6d97e 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -1,67 +1,56 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include <assert.h> #include <lauxlib.h> #include <lua.h> -#include <lualib.h> - +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> + +#include "auto/config.h" #include "cjson/lua_cjson.h" -#include "luv/luv.h" #include "mpack/lmpack.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" #include "nvim/ascii.h" -#include "nvim/assert.h" #include "nvim/buffer_defs.h" -#include "nvim/change.h" -#include "nvim/cursor.h" #include "nvim/eval.h" -#include "nvim/eval/userfunc.h" -#include "nvim/event/loop.h" -#include "nvim/event/time.h" +#include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/ex_eval.h" -#include "nvim/ex_getln.h" -#include "nvim/extmark.h" -#include "nvim/func_attr.h" -#include "nvim/garray.h" -#include "nvim/getchar.h" #include "nvim/globals.h" #include "nvim/lua/converter.h" -#include "nvim/lua/executor.h" #include "nvim/lua/spell.h" #include "nvim/lua/stdlib.h" -#include "nvim/lua/treesitter.h" #include "nvim/lua/xdiff.h" -#include "nvim/macros.h" #include "nvim/map.h" +#include "nvim/mbyte.h" #include "nvim/memline.h" -#include "nvim/message.h" -#include "nvim/msgpack_rpc/channel.h" -#include "nvim/os/os.h" +#include "nvim/memory.h" +#include "nvim/pos.h" #include "nvim/regexp.h" -#include "nvim/regexp_defs.h" -#include "nvim/screen.h" #include "nvim/types.h" -#include "nvim/undo.h" -#include "nvim/version.h" #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/stdlib.c.generated.h" #endif -static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str) +static int regex_match(lua_State *lstate, regprog_T **prog, char *str) { regmatch_T rm; rm.regprog = *prog; rm.rm_ic = false; - bool match = vim_regexec(&rm, (char *)str, 0); + bool match = vim_regexec(&rm, str, 0); *prog = rm.regprog; if (match) { - lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - (char *)str)); - lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - (char *)str)); + lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - str)); + lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - str)); return 2; } return 0; @@ -71,7 +60,7 @@ static int regex_match_str(lua_State *lstate) { regprog_T **prog = regex_check(lstate); const char *str = luaL_checkstring(lstate, 2); - int nret = regex_match(lstate, prog, (char_u *)str); + int nret = regex_match(lstate, prog, (char *)str); if (!*prog) { return luaL_error(lstate, "regex: internal error"); @@ -111,14 +100,14 @@ static int regex_match_line(lua_State *lstate) return luaL_error(lstate, "invalid row"); } - char_u *line = (char_u *)ml_get_buf(buf, rownr + 1, false); - size_t len = STRLEN(line); + char *line = ml_get_buf(buf, rownr + 1, false); + size_t len = strlen(line); if (start < 0 || (size_t)start > len) { return luaL_error(lstate, "invalid start"); } - char_u save = NUL; + char save = NUL; if (end >= 0) { if ((size_t)end > len || end < start) { return luaL_error(lstate, "invalid end"); @@ -187,7 +176,7 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL } size_t codepoints = 0, codeunits = 0; - mb_utflen((const char_u *)s1, (size_t)idx, &codepoints, &codeunits); + mb_utflen(s1, (size_t)idx, &codepoints, &codeunits); lua_pushinteger(lstate, (long)codepoints); lua_pushinteger(lstate, (long)codeunits); @@ -209,7 +198,7 @@ static int nlua_str_utf_pos(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL size_t idx = 1; size_t clen; for (size_t i = 0; i < s1_len && s1[i] != NUL; i += clen) { - clen = (size_t)utf_ptr2len_len((const char_u *)(s1) + i, (int)(s1_len - i)); + clen = (size_t)utf_ptr2len_len(s1 + i, (int)(s1_len - i)); lua_pushinteger(lstate, (long)i + 1); lua_rawseti(lstate, -2, (int)idx); idx++; @@ -277,8 +266,7 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL use_utf16 = lua_toboolean(lstate, 3); } - ssize_t byteidx = mb_utf_index_to_bytes((const char_u *)s1, s1_len, - (size_t)idx, use_utf16); + ssize_t byteidx = mb_utf_index_to_bytes(s1, s1_len, (size_t)idx, use_utf16); if (byteidx == -1) { return luaL_error(lstate, "index out of range"); } @@ -378,15 +366,14 @@ int nlua_setvar(lua_State *lstate) if (di == NULL) { // Doesn't exist, nothing to do return 0; - } else { - // Notify watchers - if (watched) { - tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv); - } - - // Delete the entry - tv_dict_item_remove(dict, di); } + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv); + } + + // Delete the entry + tv_dict_item_remove(dict, di); } else { // Update the key typval_T tv; @@ -495,8 +482,6 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL return 1; } -#if defined(HAVE_ICONV) - /// Convert string from one encoding to another static int nlua_iconv(lua_State *lstate) { @@ -515,14 +500,14 @@ static int nlua_iconv(lua_State *lstate) size_t str_len = 0; const char *str = lua_tolstring(lstate, 1, &str_len); - char_u *from = (char_u *)enc_canonize(enc_skip((char *)lua_tolstring(lstate, 2, NULL))); - char_u *to = (char_u *)enc_canonize(enc_skip((char *)lua_tolstring(lstate, 3, NULL))); + char *from = enc_canonize(enc_skip((char *)lua_tolstring(lstate, 2, NULL))); + char *to = enc_canonize(enc_skip((char *)lua_tolstring(lstate, 3, NULL))); vimconv_T vimconv; vimconv.vc_type = CONV_NONE; - convert_setup_ext(&vimconv, (char *)from, false, (char *)to, false); + convert_setup_ext(&vimconv, from, false, to, false); - char_u *ret = (char_u *)string_convert(&vimconv, (char *)str, &str_len); + char *ret = string_convert(&vimconv, (char *)str, &str_len); convert_setup(&vimconv, NULL, NULL); @@ -532,15 +517,13 @@ static int nlua_iconv(lua_State *lstate) if (ret == NULL) { lua_pushnil(lstate); } else { - lua_pushlstring(lstate, (char *)ret, str_len); + lua_pushlstring(lstate, ret, str_len); xfree(ret); } return 1; } -#endif - void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) { if (!is_thread) { @@ -587,12 +570,10 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) luaopen_spell(lstate); lua_setfield(lstate, -2, "spell"); -#if defined(HAVE_ICONV) // vim.iconv // depends on p_ambw, p_emoji lua_pushcfunction(lstate, &nlua_iconv); lua_setfield(lstate, -2, "iconv"); -#endif } // vim.mpack diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 79b11eca4a..56f4daed1a 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -6,23 +6,28 @@ // trees and nodes, and could be broken out as a reusable lua package #include <assert.h> -#include <inttypes.h> #include <lauxlib.h> +#include <limits.h> #include <lua.h> -#include <lualib.h> #include <stdbool.h> #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <uv.h> #include "klib/kvec.h" #include "nvim/api/private/helpers.h" -#include "nvim/buffer.h" -#include "nvim/log.h" +#include "nvim/buffer_defs.h" +#include "nvim/globals.h" #include "nvim/lua/treesitter.h" +#include "nvim/macros.h" #include "nvim/map.h" #include "nvim/memline.h" +#include "nvim/memory.h" +#include "nvim/pos.h" +#include "nvim/strings.h" +#include "nvim/types.h" #include "tree_sitter/api.h" #define TS_META_PARSER "treesitter_parser" @@ -177,19 +182,19 @@ int tslua_add_language(lua_State *L) uv_lib_t lib; if (uv_dlopen(path, &lib)) { - snprintf((char *)IObuff, IOSIZE, "Failed to load parser: uv_dlopen: %s", - uv_dlerror(&lib)); + snprintf(IObuff, IOSIZE, "Failed to load parser for language '%s': uv_dlopen: %s", + lang_name, uv_dlerror(&lib)); uv_dlclose(&lib); - lua_pushstring(L, (char *)IObuff); + lua_pushstring(L, IObuff); return lua_error(L); } TSLanguage *(*lang_parser)(void); if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) { - snprintf((char *)IObuff, IOSIZE, "Failed to load parser: uv_dlsym: %s", + snprintf(IObuff, IOSIZE, "Failed to load parser: uv_dlsym: %s", uv_dlerror(&lib)); uv_dlclose(&lib); - lua_pushstring(L, (char *)IObuff); + lua_pushstring(L, IObuff); return lua_error(L); } @@ -333,7 +338,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position return ""; } char *line = ml_get_buf(bp, (linenr_T)position.row + 1, false); - size_t len = STRLEN(line); + size_t len = strlen(line); if (position.column > len) { *bytes_read = 0; return ""; diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index b2b5dfedee..857b159af5 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -1,21 +1,26 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -#include <errno.h> #include <lauxlib.h> #include <lua.h> -#include <lualib.h> -#include <stdio.h> -#include <stdlib.h> +#include <stdbool.h> #include <string.h> +#include "luaconf.h" +#include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/linematch.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/lua/xdiff.h" +#include "nvim/macros.h" +#include "nvim/memory.h" #include "nvim/vim.h" #include "xdiff/xdiff.h" +#define COMPARED_BUFFER0 (1 << 0) +#define COMPARED_BUFFER1 (1 << 1) + typedef enum { kNluaXdiffModeUnified = 0, kNluaXdiffModeOnHunkCB, @@ -25,12 +30,81 @@ typedef enum { typedef struct { lua_State *lstate; Error *err; + mmfile_t *ma; + mmfile_t *mb; + bool linematch; + bool iwhite; } hunkpriv_t; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/xdiff.c.generated.h" #endif +static void lua_pushhunk(lua_State *lstate, long start_a, long count_a, long start_b, long count_b) +{ + // Mimic extra offsets done by xdiff, see: + // src/xdiff/xemit.c:284 + // src/xdiff/xutils.c:(356,368) + if (count_a > 0) { + start_a += 1; + } + if (count_b > 0) { + start_b += 1; + } + lua_createtable(lstate, 0, 0); + lua_pushinteger(lstate, start_a); + lua_rawseti(lstate, -2, 1); + lua_pushinteger(lstate, count_a); + lua_rawseti(lstate, -2, 2); + lua_pushinteger(lstate, start_b); + lua_rawseti(lstate, -2, 3); + lua_pushinteger(lstate, count_b); + lua_rawseti(lstate, -2, 4); + lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1); +} + +static void get_linematch_results(lua_State *lstate, mmfile_t *ma, mmfile_t *mb, long start_a, + long count_a, long start_b, long count_b, bool iwhite) +{ + // get the pointer to char of the start of the diff to pass it to linematch algorithm + const char *diff_begin[2] = { ma->ptr, mb->ptr }; + int diff_length[2] = { (int)count_a, (int)count_b }; + + fastforward_buf_to_lnum(&diff_begin[0], start_a + 1); + fastforward_buf_to_lnum(&diff_begin[1], start_b + 1); + + int *decisions = NULL; + size_t decisions_length = linematch_nbuffers(diff_begin, diff_length, 2, &decisions, iwhite); + + long lnuma = start_a, lnumb = start_b; + + long hunkstarta = lnuma; + long hunkstartb = lnumb; + long hunkcounta = 0; + long hunkcountb = 0; + for (size_t i = 0; i < decisions_length; i++) { + if (i && (decisions[i - 1] != decisions[i])) { + lua_pushhunk(lstate, hunkstarta, hunkcounta, hunkstartb, hunkcountb); + + hunkstarta = lnuma; + hunkstartb = lnumb; + hunkcounta = 0; + hunkcountb = 0; + // create a new hunk + } + if (decisions[i] & COMPARED_BUFFER0) { + lnuma++; + hunkcounta++; + } + if (decisions[i] & COMPARED_BUFFER1) { + lnumb++; + hunkcountb++; + } + } + lua_pushhunk(lstate, hunkstarta, hunkcounta, hunkstartb, hunkcountb); + xfree(decisions); +} + static int write_string(void *priv, mmbuffer_t *mb, int nbuf) { luaL_Buffer *buf = (luaL_Buffer *)priv; @@ -52,30 +126,15 @@ static int write_string(void *priv, mmbuffer_t *mb, int nbuf) // hunk_func callback used when opts.hunk_lines = true static int hunk_locations_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data) { - // Mimic extra offsets done by xdiff, see: - // src/xdiff/xemit.c:284 - // src/xdiff/xutils.c:(356,368) - if (count_a > 0) { - start_a += 1; - } - if (count_b > 0) { - start_b += 1; + hunkpriv_t *priv = (hunkpriv_t *)cb_data; + lua_State *lstate = priv->lstate; + if (priv->linematch) { + get_linematch_results(lstate, priv->ma, priv->mb, start_a, count_a, start_b, count_b, + priv->iwhite); + } else { + lua_pushhunk(lstate, start_a, count_a, start_b, count_b); } - lua_State *lstate = (lua_State *)cb_data; - lua_createtable(lstate, 0, 0); - - lua_pushinteger(lstate, start_a); - lua_rawseti(lstate, -2, 1); - lua_pushinteger(lstate, count_a); - lua_rawseti(lstate, -2, 2); - lua_pushinteger(lstate, start_b); - lua_rawseti(lstate, -2, 3); - lua_pushinteger(lstate, count_b); - lua_rawseti(lstate, -2, 4); - - lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1); - return 0; } @@ -149,7 +208,7 @@ static bool check_xdiff_opt(ObjectType actType, ObjectType expType, const char * } static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, xpparam_t *params, - Error *err) + bool *linematch, Error *err) { const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err); @@ -205,6 +264,11 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, goto exit_1; } cfg->interhunkctxlen = v->data.integer; + } else if (strequal("linematch", k.data)) { + *linematch = api_object_to_bool(*v, "linematch", false, err); + if (ERROR_SET(err)) { + goto exit_1; + } } else { struct { const char *name; @@ -244,10 +308,8 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, if (had_on_hunk) { mode = kNluaXdiffModeOnHunkCB; - cfg->hunk_func = call_on_hunk_cb; } else if (had_result_type_indices) { mode = kNluaXdiffModeLocations; - cfg->hunk_func = hunk_locations_cb; } exit_1: @@ -268,6 +330,7 @@ int nlua_xdl_diff(lua_State *lstate) xdemitconf_t cfg; xpparam_t params; xdemitcb_t ecb; + bool linematch = false; CLEAR_FIELD(cfg); CLEAR_FIELD(params); @@ -280,7 +343,7 @@ int nlua_xdl_diff(lua_State *lstate) return luaL_argerror(lstate, 3, "expected table"); } - mode = process_xdl_diff_opts(lstate, &cfg, ¶ms, &err); + mode = process_xdl_diff_opts(lstate, &cfg, ¶ms, &linematch, &err); if (ERROR_SET(&err)) { goto exit_0; @@ -288,7 +351,7 @@ int nlua_xdl_diff(lua_State *lstate) } luaL_Buffer buf; - hunkpriv_t *priv = NULL; + hunkpriv_t priv; switch (mode) { case kNluaXdiffModeUnified: luaL_buffinit(lstate, &buf); @@ -296,14 +359,24 @@ int nlua_xdl_diff(lua_State *lstate) ecb.out_line = write_string; break; case kNluaXdiffModeOnHunkCB: - priv = xmalloc(sizeof(*priv)); - priv->lstate = lstate; - priv->err = &err; - ecb.priv = priv; + cfg.hunk_func = call_on_hunk_cb; + priv = (hunkpriv_t) { + .lstate = lstate, + .err = &err, + }; + ecb.priv = &priv; break; case kNluaXdiffModeLocations: + cfg.hunk_func = hunk_locations_cb; + priv = (hunkpriv_t) { + .lstate = lstate, + .ma = &ma, + .mb = &mb, + .linematch = linematch, + .iwhite = (params.flags & XDF_IGNORE_WHITESPACE) > 0 + }; + ecb.priv = &priv; lua_createtable(lstate, 0, 0); - ecb.priv = lstate; break; } @@ -314,8 +387,6 @@ int nlua_xdl_diff(lua_State *lstate) } } - XFREE_CLEAR(priv); - exit_0: if (ERROR_SET(&err)) { luaL_where(lstate, 1); |