aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 17:57:01 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 17:57:01 +0000
commit9837de570c5972f98e74848edc97c297a13136ea (patch)
treecc948611912d116a3f98a744e690d3d7b6e2f59a /src/nvim/lua
parentc367400b73d207833d51e09d663f969ffab37531 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-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.c18
-rw-r--r--src/nvim/lua/executor.c253
-rw-r--r--src/nvim/lua/executor.h4
-rw-r--r--src/nvim/lua/spell.c18
-rw-r--r--src/nvim/lua/stdlib.c93
-rw-r--r--src/nvim/lua/treesitter.c25
-rw-r--r--src/nvim/lua/xdiff.c147
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, &params, &err);
+ mode = process_xdl_diff_opts(lstate, &cfg, &params, &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);