aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
commit1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch)
treecd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/lua
parenteaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-aucmd_textputpost.tar.gz
rneovim-aucmd_textputpost.tar.bz2
rneovim-aucmd_textputpost.zip
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/lua')
-rw-r--r--src/nvim/lua/base64.c70
-rw-r--r--src/nvim/lua/base64.h7
-rw-r--r--src/nvim/lua/converter.c149
-rw-r--r--src/nvim/lua/converter.h17
-rw-r--r--src/nvim/lua/executor.c285
-rw-r--r--src/nvim/lua/executor.h21
-rw-r--r--src/nvim/lua/secure.c119
-rw-r--r--src/nvim/lua/secure.h7
-rw-r--r--src/nvim/lua/spell.c23
-rw-r--r--src/nvim/lua/spell.h9
-rw-r--r--src/nvim/lua/stdlib.c134
-rw-r--r--src/nvim/lua/stdlib.h7
-rw-r--r--src/nvim/lua/treesitter.c517
-rw-r--r--src/nvim/lua/treesitter.h11
-rw-r--r--src/nvim/lua/xdiff.c76
-rw-r--r--src/nvim/lua/xdiff.h9
16 files changed, 1007 insertions, 454 deletions
diff --git a/src/nvim/lua/base64.c b/src/nvim/lua/base64.c
new file mode 100644
index 0000000000..c1f43a37d7
--- /dev/null
+++ b/src/nvim/lua/base64.c
@@ -0,0 +1,70 @@
+#include <assert.h>
+#include <lauxlib.h>
+#include <lua.h>
+#include <stddef.h>
+
+#include "nvim/base64.h"
+#include "nvim/lua/base64.h"
+#include "nvim/memory.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/base64.c.generated.h"
+#endif
+
+static int nlua_base64_encode(lua_State *L)
+{
+ if (lua_gettop(L) < 1) {
+ return luaL_error(L, "Expected 1 argument");
+ }
+
+ if (lua_type(L, 1) != LUA_TSTRING) {
+ luaL_argerror(L, 1, "expected string");
+ }
+
+ size_t src_len = 0;
+ const char *src = lua_tolstring(L, 1, &src_len);
+
+ const char *ret = base64_encode(src, src_len);
+ assert(ret != NULL);
+ lua_pushstring(L, ret);
+ xfree((void *)ret);
+
+ return 1;
+}
+
+static int nlua_base64_decode(lua_State *L)
+{
+ if (lua_gettop(L) < 1) {
+ return luaL_error(L, "Expected 1 argument");
+ }
+
+ if (lua_type(L, 1) != LUA_TSTRING) {
+ luaL_argerror(L, 1, "expected string");
+ }
+
+ size_t src_len = 0;
+ const char *src = lua_tolstring(L, 1, &src_len);
+
+ const char *ret = base64_decode(src, src_len);
+ if (ret == NULL) {
+ return luaL_error(L, "Invalid input");
+ }
+
+ lua_pushstring(L, ret);
+ xfree((void *)ret);
+
+ return 1;
+}
+
+static const luaL_Reg base64_functions[] = {
+ { "encode", nlua_base64_encode },
+ { "decode", nlua_base64_decode },
+ { NULL, NULL },
+};
+
+int luaopen_base64(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_register(L, NULL, base64_functions);
+ return 1;
+}
diff --git a/src/nvim/lua/base64.h b/src/nvim/lua/base64.h
new file mode 100644
index 0000000000..3c95968cda
--- /dev/null
+++ b/src/nvim/lua/base64.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <lua.h> // IWYU pragma: keep
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/base64.h.generated.h"
+#endif
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 6160b84485..4598d48c4a 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -1,6 +1,3 @@
-// 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>
@@ -10,26 +7,24 @@
#include <stdlib.h>
#include <string.h>
+#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/memory.h"
-// FIXME: vim.h is not actually needed, but otherwise it states MAXPATHL is
-// redefined
-#include "klib/kvec.h"
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.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/garray.h"
+#include "nvim/func_attr.h"
#include "nvim/gettext.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/types.h"
-#include "nvim/vim.h"
+#include "nvim/types_defs.h"
+#include "nvim/vim_defs.h"
/// Determine, which keys lua table contains
typedef struct {
@@ -183,7 +178,7 @@ typedef struct {
int idx; ///< Container index (used to detect self-referencing structures).
} TVPopStackItem;
-/// Convert lua object to VimL typval_T
+/// Convert lua object to Vimscript typval_T
///
/// Should pop exactly one value from lua stack.
///
@@ -459,7 +454,7 @@ static bool typval_conv_special = false;
TYPVAL_ENCODE_CONV_NUMBER(tv, flt)
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
- lua_pushlstring(lstate, (const char *)(str), (len))
+ lua_pushlstring(lstate, (str), (len))
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
@@ -469,9 +464,7 @@ static bool typval_conv_special = false;
#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
do { \
const blob_T *const blob_ = (blob); \
- lua_pushlstring(lstate, \
- blob_ != NULL ? (const char *)blob_->bv_ga.ga_data : "", \
- (size_t)(len)); \
+ lua_pushlstring(lstate, blob_ != NULL ? blob_->bv_ga.ga_data : "", (size_t)(len)); \
} while (0)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
@@ -603,7 +596,7 @@ static bool typval_conv_special = false;
#undef TYPVAL_ENCODE_CONV_RECURSE
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
-/// Convert VimL typval_T to lua value
+/// Convert Vimscript typval_T to lua value
///
/// Should leave single value in lua stack. May only fail if lua failed to grow
/// stack.
@@ -630,8 +623,7 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special)
/// Push value which is a type index
///
-/// Used for all “typed” tables: i.e. for all tables which represent VimL
-/// values.
+/// Used for all “typed” tables: i.e. for all tables which represent Vimscript values.
static inline void nlua_push_type_idx(lua_State *lstate)
FUNC_ATTR_NONNULL_ALL
{
@@ -659,7 +651,7 @@ static inline void nlua_push_type(lua_State *lstate, ObjectType type)
lua_pushnumber(lstate, (lua_Number)type);
}
-/// Create lua table which has an entry that determines its VimL type
+/// Create Lua table which has an entry that determines its Vimscript type
///
/// @param[out] lstate Lua state.
/// @param[in] narr Number of “array” entries to be populated later.
@@ -816,7 +808,7 @@ String nlua_pop_String(lua_State *lstate, Error *err)
{
if (lua_type(lstate, -1) != LUA_TSTRING) {
lua_pop(lstate, 1);
- api_set_error(err, kErrorTypeValidation, "Expected lua string");
+ api_set_error(err, kErrorTypeValidation, "Expected Lua string");
return (String) { .size = 0, .data = NULL };
}
String ret;
@@ -837,7 +829,7 @@ Integer nlua_pop_Integer(lua_State *lstate, Error *err)
{
if (lua_type(lstate, -1) != LUA_TNUMBER) {
lua_pop(lstate, 1);
- api_set_error(err, kErrorTypeValidation, "Expected lua number");
+ api_set_error(err, kErrorTypeValidation, "Expected Lua number");
return 0;
}
const lua_Number n = lua_tonumber(lstate, -1);
@@ -852,6 +844,9 @@ Integer nlua_pop_Integer(lua_State *lstate, Error *err)
/// Convert lua value to boolean
///
+/// Despite the name of the function, this uses lua semantics for booleans.
+/// thus `err` is never set as any lua value can be co-erced into a lua bool
+///
/// Always pops one value from the stack.
Boolean nlua_pop_Boolean(lua_State *lstate, Error *err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
@@ -861,6 +856,36 @@ Boolean nlua_pop_Boolean(lua_State *lstate, Error *err)
return ret;
}
+/// Convert lua value to boolean
+///
+/// This follows API conventions for a Boolean value, compare api_object_to_bool
+///
+/// Always pops one value from the stack.
+Boolean nlua_pop_Boolean_strict(lua_State *lstate, Error *err)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ Boolean ret = false;
+ switch (lua_type(lstate, -1)) {
+ case LUA_TBOOLEAN:
+ ret = lua_toboolean(lstate, -1);
+ break;
+
+ case LUA_TNUMBER:
+ ret = (lua_tonumber(lstate, -1) != 0);
+ break;
+
+ case LUA_TNIL:
+ ret = false;
+ break;
+
+ default:
+ api_set_error(err, kErrorTypeValidation, "not a boolean");
+ }
+
+ lua_pop(lstate, 1);
+ return ret;
+}
+
/// Check whether typed table on top of the stack has given type
///
/// @param[in] lstate Lua state.
@@ -874,7 +899,8 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons
{
if (lua_type(lstate, -1) != LUA_TTABLE) {
if (err) {
- api_set_error(err, kErrorTypeValidation, "Expected lua table");
+ api_set_error(err, kErrorTypeValidation, "Expected Lua %s",
+ (type == kObjectTypeFloat) ? "number" : "table");
}
return (LuaTableProps) { .type = kObjectTypeNil };
}
@@ -887,7 +913,7 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons
if (table_props.type != type) {
if (err) {
- api_set_error(err, kErrorTypeValidation, "Unexpected type");
+ api_set_error(err, kErrorTypeValidation, "Expected %s-like Lua table", api_typename(type));
}
}
@@ -1171,7 +1197,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
break;
case kObjectTypeNil:
api_set_error(err, kErrorTypeValidation,
- "Cannot convert given lua table");
+ "Cannot convert given Lua table");
break;
default:
abort();
@@ -1227,26 +1253,19 @@ LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err)
return rv;
}
-#define GENERATE_INDEX_FUNCTION(type) \
- type nlua_pop_##type(lua_State *lstate, Error *err) \
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
- { \
- type ret; \
- if (lua_type(lstate, -1) != LUA_TNUMBER) { \
- api_set_error(err, kErrorTypeValidation, "Expected Lua number"); \
- ret = (type) - 1; \
- } else { \
- ret = (type)lua_tonumber(lstate, -1); \
- } \
- lua_pop(lstate, 1); \
- return ret; \
+handle_T nlua_pop_handle(lua_State *lstate, Error *err)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ handle_T ret;
+ if (lua_type(lstate, -1) != LUA_TNUMBER) {
+ api_set_error(err, kErrorTypeValidation, "Expected Lua number");
+ ret = (handle_T) - 1;
+ } else {
+ ret = (handle_T)lua_tonumber(lstate, -1);
}
-
-GENERATE_INDEX_FUNCTION(Buffer)
-GENERATE_INDEX_FUNCTION(Window)
-GENERATE_INDEX_FUNCTION(Tabpage)
-
-#undef GENERATE_INDEX_FUNCTION
+ lua_pop(lstate, 1);
+ return ret;
+}
/// Record some auxiliary values in vim module
///
@@ -1295,10 +1314,11 @@ void nlua_init_types(lua_State *const lstate)
lua_rawset(lstate, -3);
}
-void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err)
+// lua specific variant of api_dict_to_keydict
+void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_opt, Error *err)
{
if (!lua_istable(L, -1)) {
- api_set_error(err, kErrorTypeValidation, "Expected lua table");
+ api_set_error(err, kErrorTypeValidation, "Expected Lua table");
lua_pop(L, -1);
return;
}
@@ -1308,14 +1328,45 @@ void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err)
// [dict, key, value]
size_t len;
const char *s = lua_tolstring(L, -2, &len);
- Object *field = hashy(retval, s, len);
+ KeySetLink *field = hashy(s, len);
if (!field) {
api_set_error(err, kErrorTypeValidation, "invalid key: %.*s", (int)len, s);
lua_pop(L, 3); // []
return;
}
- *field = nlua_pop_Object(L, true, err);
+ if (field->opt_index >= 0) {
+ OptKeySet *ks = (OptKeySet *)retval;
+ ks->is_set_ |= (1ULL << field->opt_index);
+ }
+ char *mem = ((char *)retval + field->ptr_off);
+
+ if (field->type == kObjectTypeNil) {
+ *(Object *)mem = nlua_pop_Object(L, true, err);
+ } else if (field->type == kObjectTypeInteger) {
+ *(Integer *)mem = nlua_pop_Integer(L, err);
+ } else if (field->type == kObjectTypeBoolean) {
+ *(Boolean *)mem = nlua_pop_Boolean_strict(L, err);
+ } else if (field->type == kObjectTypeString) {
+ *(String *)mem = nlua_pop_String(L, err);
+ } else if (field->type == kObjectTypeFloat) {
+ *(Float *)mem = nlua_pop_Float(L, err);
+ } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
+ || field->type == kObjectTypeTabpage) {
+ *(handle_T *)mem = nlua_pop_handle(L, err);
+ } else if (field->type == kObjectTypeArray) {
+ *(Array *)mem = nlua_pop_Array(L, err);
+ } else if (field->type == kObjectTypeDictionary) {
+ *(Dictionary *)mem = nlua_pop_Dictionary(L, false, err);
+ } else if (field->type == kObjectTypeLuaRef) {
+ *(LuaRef *)mem = nlua_pop_LuaRef(L, err);
+ } else {
+ abort();
+ }
+ if (ERROR_SET(err)) {
+ *err_opt = field->str;
+ break;
+ }
}
// [dict]
lua_pop(L, 1);
diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h
index ddc0acfbfa..a502df80d9 100644
--- a/src/nvim/lua/converter.h
+++ b/src/nvim/lua/converter.h
@@ -1,15 +1,14 @@
-#ifndef NVIM_LUA_CONVERTER_H
-#define NVIM_LUA_CONVERTER_H
+#pragma once
-#include <lua.h>
-#include <stdbool.h>
-#include <stdint.h>
+#include <lua.h> // IWYU pragma: keep
-#include "nvim/api/private/defs.h"
-#include "nvim/eval/typval.h"
-#include "nvim/func_attr.h"
+#include "nvim/api/private/defs.h" // IWYU pragma: keep
+#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
+
+#define nlua_pop_Buffer nlua_pop_handle
+#define nlua_pop_Window nlua_pop_handle
+#define nlua_pop_Tabpage nlua_pop_handle
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/converter.h.generated.h"
#endif
-#endif // NVIM_LUA_CONVERTER_H
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 1415ceeaed..06d16efb05 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1,12 +1,11 @@
-// 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 <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <tree_sitter/api.h>
#include <uv.h>
@@ -16,9 +15,9 @@
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/ascii.h"
-#include "nvim/buffer_defs.h"
+#include "nvim/ascii_defs.h"
#include "nvim/change.h"
+#include "nvim/cmdexpand_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
@@ -42,25 +41,24 @@
#include "nvim/lua/executor.h"
#include "nvim/lua/stdlib.h"
#include "nvim/lua/treesitter.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.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/option_vars.h"
#include "nvim/os/fileio.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
-#include "nvim/pos.h"
+#include "nvim/pos_defs.h"
#include "nvim/profile.h"
#include "nvim/runtime.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/usercmd.h"
-#include "nvim/version.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
#include "nvim/window.h"
static int in_fast_callback = 0;
@@ -109,11 +107,16 @@ typedef enum luv_err_type {
kThreadCallback,
} luv_err_t;
+lua_State *get_global_lstate(void)
+{
+ return global_lstate;
+}
+
/// Convert lua error into a Vim error message
///
/// @param lstate Lua interpreter state.
-/// @param[in] msg Message base, must contain one `%s`.
-static void nlua_error(lua_State *const lstate, const char *const msg)
+/// @param[in] msg Message base, must contain one `%*s`.
+void nlua_error(lua_State *const lstate, const char *const msg)
FUNC_ATTR_NONNULL_ALL
{
size_t len;
@@ -135,8 +138,8 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
}
if (in_script) {
- os_errmsg(str);
- os_errmsg("\n");
+ fprintf(stderr, msg, (int)len, str);
+ fprintf(stderr, "\n");
} else {
msg_ext_set_kind("lua_error");
semsg_multiline(msg, (int)len, str);
@@ -150,7 +153,7 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
/// @param lstate Lua interpreter state
/// @param[in] nargs Number of arguments expected by the function being called.
/// @param[in] nresults Number of results the function returns.
-static int nlua_pcall(lua_State *lstate, int nargs, int nresults)
+int nlua_pcall(lua_State *lstate, int nargs, int nresults)
{
lua_getglobal(lstate, "debug");
lua_getfield(lstate, -1, "traceback");
@@ -165,17 +168,6 @@ static int nlua_pcall(lua_State *lstate, int nargs, int nresults)
return status;
}
-/// Gets the version of the current Nvim build.
-///
-/// @param lstate Lua interpreter state.
-static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
-{
- Dictionary version = version_dict();
- nlua_push_Dictionary(lstate, version, true);
- api_free_dictionary(version);
- return 1;
-}
-
static void nlua_luv_error_event(void **argv)
{
char *error = (char *)argv[0];
@@ -211,9 +203,7 @@ 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()
- os_errmsg(e_outofmem);
- os_errmsg("\n");
- preserve_exit();
+ preserve_exit(e_outofmem);
}
const char *error = lua_tostring(lstate, -1);
@@ -349,7 +339,7 @@ static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg
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++) {
+ for (; i + lua_arg0 < argc; i++) {
lua_pushstring(L, argv[i + lua_arg0]);
lua_rawseti(L, -2, i + 1); // _G.arg[i+1] = "--foo"
}
@@ -381,6 +371,12 @@ static int nlua_schedule(lua_State *const lstate)
return lua_error(lstate);
}
+ // If main_loop is closing don't schedule tasks to run in the future,
+ // otherwise any refs allocated here will not be cleaned up.
+ if (main_loop.closing) {
+ return 0;
+ }
+
LuaRef cb = nlua_ref_global(lstate, 1);
multiqueue_put(main_loop.events, nlua_schedule_event,
@@ -390,7 +386,8 @@ static int nlua_schedule(lua_State *const lstate)
// Dummy timer callback. Used by f_wait().
static void dummy_timer_due_cb(TimeWatcher *tw, void *data)
-{}
+{
+}
// Dummy timer close callback. Used by f_wait().
static void dummy_timer_close_cb(TimeWatcher *tw, void *data)
@@ -414,6 +411,10 @@ static bool nlua_wait_condition(lua_State *lstate, int *status, bool *callback_r
static int nlua_wait(lua_State *lstate)
FUNC_ATTR_NONNULL_ALL
{
+ if (in_fast_callback) {
+ return luaL_error(lstate, e_luv_api_disabled, "vim.wait");
+ }
+
intptr_t timeout = luaL_checkinteger(lstate, 1);
if (timeout < 0) {
return luaL_error(lstate, "timeout must be >= 0");
@@ -452,8 +453,7 @@ static int nlua_wait(lua_State *lstate)
fast_only = lua_toboolean(lstate, 4);
}
- MultiQueue *loop_events = fast_only || in_fast_callback > 0
- ? main_loop.fast_events : main_loop.events;
+ MultiQueue *loop_events = fast_only ? main_loop.fast_events : main_loop.events;
TimeWatcher *tw = xmalloc(sizeof(TimeWatcher));
@@ -469,12 +469,16 @@ static int nlua_wait(lua_State *lstate)
int pcall_status = 0;
bool callback_result = false;
+ // Flush screen updates before blocking.
+ ui_flush();
+
LOOP_PROCESS_EVENTS_UNTIL(&main_loop,
loop_events,
(int)timeout,
got_int || (is_function ? nlua_wait_condition(lstate,
&pcall_status,
- &callback_result) : false));
+ &callback_result)
+ : false));
// Stop dummy timer
time_watcher_stop(tw);
@@ -572,7 +576,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan
lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.empty_dict");
lua_setfield(lstate, -2, "_empty_dict_mt");
- // vim.loop
+ // vim.uv
if (is_standalone) {
// do nothing, use libluv like in a standalone interpreter
} else if (is_thread) {
@@ -585,9 +589,12 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan
}
luaopen_luv(lstate);
lua_pushvalue(lstate, -1);
- lua_setfield(lstate, -3, "loop");
+ lua_setfield(lstate, -3, "uv");
+
+ lua_pushvalue(lstate, -1);
+ lua_setfield(lstate, -3, "loop"); // deprecated
- // package.loaded.luv = vim.loop
+ // package.loaded.luv = vim.uv
// otherwise luv will be reinitialized when require'luv'
lua_getglobal(lstate, "package");
lua_getfield(lstate, -1, "loaded");
@@ -622,7 +629,7 @@ static bool nlua_init_packages(lua_State *lstate, bool is_standalone)
lua_getfield(lstate, -1, "preload"); // [package, preload]
for (size_t i = 0; i < ARRAY_SIZE(builtin_modules); i++) {
ModuleDef def = builtin_modules[i];
- lua_pushinteger(lstate, (long)i); // [package, preload, i]
+ lua_pushinteger(lstate, (lua_Integer)i); // [package, preload, i]
lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure]
lua_setfield(lstate, -2, def.name); // [package, preload]
@@ -636,7 +643,7 @@ static bool nlua_init_packages(lua_State *lstate, bool is_standalone)
lua_getglobal(lstate, "require");
lua_pushstring(lstate, "vim._init_packages");
if (nlua_pcall(lstate, 1, 0)) {
- os_errmsg((char *)lua_tostring(lstate, -1));
+ os_errmsg(lua_tostring(lstate, -1));
os_errmsg("\n");
return false;
}
@@ -741,10 +748,6 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// vim.types, vim.type_idx, vim.val_idx
nlua_init_types(lstate);
- // neovim version
- lua_pushcfunction(lstate, &nlua_nvim_version);
- lua_setfield(lstate, -2, "version");
-
// schedule
lua_pushcfunction(lstate, &nlua_schedule);
lua_setfield(lstate, -2, "schedule");
@@ -852,7 +855,7 @@ void nlua_run_script(char **argv, int argc, int lua_arg0)
exit(lua_ok ? 0 : 1);
}
-lua_State *nlua_init_state(bool thread)
+static lua_State *nlua_init_state(bool thread)
{
// If it is called from the main thread, it will attempt to rebuild the cache.
const uv_thread_t self = uv_thread_self();
@@ -926,12 +929,13 @@ static void nlua_common_free_all_mem(lua_State *lstate)
if (nlua_track_refs) {
// in case there are leaked luarefs, leak the associated memory
// to get LeakSanitizer stacktraces on exit
- pmap_destroy(handle_T)(&ref_state->ref_markers);
+ map_destroy(int, &ref_state->ref_markers);
}
#endif
lua_close(lstate);
}
+
static void nlua_print_event(void **argv)
{
char *str = argv[0];
@@ -960,10 +964,13 @@ static void nlua_print_event(void **argv)
}
break;
}
- msg(str + start);
+ msg(str + start, 0);
+ if (msg_silent == 0) {
+ msg_didout = true; // Make blank lines work properly
+ }
}
if (len && str[len - 1] == NUL) { // Last was newline
- msg("");
+ msg("", 0);
}
xfree(str);
}
@@ -1110,7 +1117,7 @@ static int nlua_debug(lua_State *lstate)
.v_type = VAR_UNKNOWN,
},
};
- for (;;) {
+ while (true) {
lua_settop(lstate, 0);
typval_T input;
get_user_input(input_args, &input, false, false);
@@ -1122,7 +1129,7 @@ static int nlua_debug(lua_State *lstate)
tv_clear(&input);
return 0;
}
- if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string,
+ if (luaL_loadbuffer(lstate, input.vval.v_string,
strlen(input.vval.v_string), "=(debug command)")) {
nlua_error(lstate, _("E5115: Error while loading debug string: %.*s"));
} else if (nlua_pcall(lstate, 0, 0)) {
@@ -1145,7 +1152,7 @@ static bool viml_func_is_fast(const char *name)
if (fdef) {
return fdef->fast;
}
- // Not a vimL function
+ // Not a Vimscript function
return false;
}
@@ -1155,7 +1162,7 @@ int nlua_call(lua_State *lstate)
size_t name_len;
const char *name = luaL_checklstring(lstate, 1, &name_len);
if (!nlua_is_deferred_safe() && !viml_func_is_fast(name)) {
- return luaL_error(lstate, e_luv_api_disabled, "vimL function");
+ return luaL_error(lstate, e_luv_api_disabled, "Vimscript function");
}
int nargs = lua_gettop(lstate) - 1;
@@ -1174,28 +1181,29 @@ int nlua_call(lua_State *lstate)
}
}
- TRY_WRAP({
- // TODO(bfredl): this should be simplified in error handling refactor
- force_abort = false;
- suppress_errthrow = false;
- did_throw = false;
- did_emsg = false;
+ // TODO(bfredl): this should be simplified in error handling refactor
+ force_abort = false;
+ suppress_errthrow = false;
+ did_throw = false;
+ did_emsg = false;
- try_start();
- typval_T rettv;
- funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.fe_firstline = curwin->w_cursor.lnum;
- funcexe.fe_lastline = curwin->w_cursor.lnum;
- funcexe.fe_evaluate = true;
+ typval_T rettv;
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.fe_firstline = curwin->w_cursor.lnum;
+ funcexe.fe_lastline = curwin->w_cursor.lnum;
+ funcexe.fe_evaluate = true;
+
+ TRY_WRAP(&err, {
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (TRY_WRAP) to capture abort-causing non-exception errors.
- (void)call_func((char *)name, (int)name_len, &rettv, nargs, vim_args, &funcexe);
- if (!try_end(&err)) {
- nlua_push_typval(lstate, &rettv, false);
- }
- tv_clear(&rettv);
+ (void)call_func(name, (int)name_len, &rettv, nargs, vim_args, &funcexe);
});
+ if (!ERROR_SET(&err)) {
+ nlua_push_typval(lstate, &rettv, false);
+ }
+ tv_clear(&rettv);
+
free_vim_args:
while (i > 0) {
tv_clear(&vim_args[--i]);
@@ -1300,13 +1308,16 @@ LuaRef nlua_ref(lua_State *lstate, nlua_ref_state_t *ref_state, int index)
#ifdef NLUA_TRACK_REFS
if (nlua_track_refs) {
// dummy allocation to make LeakSanitizer track our luarefs
- pmap_put(handle_T)(&ref_state->ref_markers, ref, xmalloc(3));
+ pmap_put(int)(&ref_state->ref_markers, ref, xmalloc(3));
}
#endif
}
return ref;
}
+// TODO(lewis6991): Currently cannot be run in __gc metamethods as they are
+// invoked in lua_close() which can be invoked after the ref_markers map is
+// destroyed in nlua_common_free_all_mem.
LuaRef nlua_ref_global(lua_State *lstate, int index)
{
return nlua_ref(lstate, nlua_global_refs, index);
@@ -1320,7 +1331,7 @@ void nlua_unref(lua_State *lstate, nlua_ref_state_t *ref_state, LuaRef ref)
#ifdef NLUA_TRACK_REFS
// NB: don't remove entry from map to track double-unref
if (nlua_track_refs) {
- xfree(pmap_get(handle_T)(&ref_state->ref_markers, ref));
+ xfree(pmap_get(int)(&ref_state->ref_markers, ref));
}
#endif
luaL_unref(lstate, LUA_REGISTRYINDEX, ref);
@@ -1493,7 +1504,7 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
/// Call a LuaCallable given some typvals
///
-/// Used to call any lua callable passed from Lua into VimL
+/// Used to call any Lua callable passed from Lua into Vimscript.
///
/// @param[in] lstate Lua State
/// @param[in] lua_cb Lua Callable
@@ -1628,24 +1639,25 @@ bool nlua_is_deferred_safe(void)
///
/// Used for :lua.
///
-/// @param eap VimL command being run.
+/// @param eap Vimscript command being run.
void ex_lua(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
size_t len;
char *code = script_get(eap, &len);
- if (eap->skip) {
+ if (eap->skip || code == NULL) {
xfree(code);
return;
}
- // When =expr is used transform it to print(vim.inspect(expr))
- if (code[0] == '=') {
- len += sizeof("vim.pretty_print()") - sizeof("=");
+ // When =expr is used transform it to vim.print(expr)
+ if (eap->cmdidx == CMD_equal || code[0] == '=') {
+ size_t off = (eap->cmdidx == CMD_equal) ? 0 : 1;
+ len += sizeof("vim.print()") - 1 - off;
// code_buf needs to be 1 char larger then len for null byte in the end.
// lua nlua_typval_exec doesn't expect null terminated string so len
// needs to end before null byte.
char *code_buf = xmallocz(len);
- vim_snprintf(code_buf, len + 1, "vim.pretty_print(%s)", code + 1);
+ vim_snprintf(code_buf, len + 1, "vim.print(%s)", code + off);
xfree(code);
code = code_buf;
}
@@ -1659,7 +1671,7 @@ void ex_lua(exarg_T *const eap)
///
/// Used for :luado.
///
-/// @param eap VimL command being run.
+/// @param eap Vimscript command being run.
void ex_luado(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
@@ -1667,7 +1679,7 @@ void ex_luado(exarg_T *const eap)
emsg(_("cannot save undo information"));
return;
}
- const char *const cmd = (const char *)eap->arg;
+ const char *const cmd = eap->arg;
const size_t cmd_len = strlen(cmd);
lua_State *const lstate = global_lstate;
@@ -1708,7 +1720,9 @@ void ex_luado(exarg_T *const eap)
break;
}
lua_pushvalue(lstate, -1);
- const char *old_line = (const char *)ml_get_buf(curbuf, l, false);
+ const char *const old_line = ml_get_buf(curbuf, l);
+ // Get length of old_line here as calling Lua code may free it.
+ const size_t old_line_len = strlen(old_line);
lua_pushstring(lstate, old_line);
lua_pushnumber(lstate, (lua_Number)l);
if (nlua_pcall(lstate, 2, 1)) {
@@ -1716,8 +1730,6 @@ void ex_luado(exarg_T *const eap)
break;
}
if (lua_isstring(lstate, -1)) {
- size_t old_line_len = strlen(old_line);
-
size_t new_line_len;
const char *const new_line = lua_tolstring(lstate, -1, &new_line_len);
char *const new_line_transformed = xmemdupz(new_line, new_line_len);
@@ -1740,11 +1752,11 @@ void ex_luado(exarg_T *const eap)
///
/// Used for :luafile.
///
-/// @param eap VimL command being run.
+/// @param eap Vimscript command being run.
void ex_luafile(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
- nlua_exec_file((const char *)eap->arg);
+ nlua_exec_file(eap->arg);
}
/// Executes Lua code from a file or "-" (stdin).
@@ -1768,13 +1780,12 @@ bool nlua_exec_file(const char *path)
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);
+ ptrdiff_t read_size = file_read(stdin_dup, IObuff, 64);
if (read_size < 0) { // Error.
return false;
}
@@ -1876,7 +1887,7 @@ int nlua_expand_pat(expand_T *xp, char *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, pat, strlen(pat));
if (nlua_pcall(lstate, 1, 2) != 0) {
nlua_error(lstate,
@@ -1995,7 +2006,7 @@ char *nlua_register_table_as_callable(const typval_T *const arg)
void nlua_execute_on_key(int c)
{
char buf[NUMBUFLEN];
- size_t buf_len = special_to_buf(c, mod_mask, false, (char_u *)buf);
+ size_t buf_len = special_to_buf(c, mod_mask, false, buf);
lua_State *const lstate = global_lstate;
@@ -2041,9 +2052,9 @@ void nlua_set_sctx(sctx_T *current)
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
+ // like vim.o/opt etc are defined in _options.lua
char *ignorelist[] = {
- "vim/_meta.lua",
+ "vim/_options.lua",
"vim/keymap.lua",
};
int ignorelist_size = sizeof(ignorelist) / sizeof(ignorelist[0]);
@@ -2073,10 +2084,15 @@ void nlua_set_sctx(sctx_T *current)
break;
}
char *source_path = fix_fname(info->source + 1);
- get_current_script_id(&source_path, current);
- xfree(source_path);
- current->sc_lnum = info->currentline;
+ int sid = find_script_by_name(source_path);
+ if (sid > 0) {
+ xfree(source_path);
+ } else {
+ new_script_item(source_path, &sid);
+ }
+ current->sc_sid = sid;
current->sc_seq = -1;
+ current->sc_lnum = info->currentline;
cleanup:
xfree(info);
@@ -2103,7 +2119,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
lua_setfield(lstate, -2, "line2");
lua_newtable(lstate); // f-args table
- lua_pushstring(lstate, (const char *)eap->arg);
+ lua_pushstring(lstate, eap->arg);
lua_pushvalue(lstate, -1); // Reference for potential use on f-args
lua_setfield(lstate, -4, "args");
@@ -2286,79 +2302,16 @@ plain:
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)
+/// Execute the vim._defaults module to set up default mappings and autocommands
+void nlua_init_defaults(void)
{
- lua_State *const lstate = global_lstate;
- const int top = lua_gettop(lstate);
+ lua_State *const L = global_lstate;
+ assert(L);
- 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_getglobal(L, "require");
+ lua_pushstring(L, "vim._defaults");
+ if (nlua_pcall(L, 1, 0)) {
+ os_errmsg(lua_tostring(L, -1));
+ os_errmsg("\n");
}
-
- lua_settop(lstate, top);
- return success;
}
diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h
index c6747833e5..b38faddbb3 100644
--- a/src/nvim/lua/executor.h
+++ b/src/nvim/lua/executor.h
@@ -1,5 +1,4 @@
-#ifndef NVIM_LUA_EXECUTOR_H
-#define NVIM_LUA_EXECUTOR_H
+#pragma once
#include <lauxlib.h>
#include <lua.h>
@@ -7,13 +6,15 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/assert.h"
-#include "nvim/eval/typval.h"
+#include "nvim/assert_defs.h"
+#include "nvim/cmdexpand_defs.h"
+#include "nvim/eval/typval_defs.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/macros_defs.h"
+#include "nvim/map_defs.h"
+#include "nvim/types_defs.h"
#include "nvim/usercmd.h"
// Generated by msgpack-gen.lua
@@ -24,7 +25,7 @@ typedef struct {
LuaRef empty_dict_ref;
int ref_count;
#if __has_feature(address_sanitizer)
- PMap(handle_T) ref_markers;
+ PMap(int) ref_markers;
#endif
} nlua_ref_state_t;
@@ -43,7 +44,5 @@ typedef struct {
# include "lua/executor.h.generated.h"
#endif
-EXTERN nlua_ref_state_t *nlua_global_refs INIT(= NULL);
-EXTERN bool nlua_disable_preload INIT(= false);
-
-#endif // NVIM_LUA_EXECUTOR_H
+EXTERN nlua_ref_state_t *nlua_global_refs INIT( = NULL);
+EXTERN bool nlua_disable_preload INIT( = false);
diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c
new file mode 100644
index 0000000000..65c13f8872
--- /dev/null
+++ b/src/nvim/lua/secure.c
@@ -0,0 +1,119 @@
+#include <lua.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/charset.h"
+#include "nvim/ex_cmds_defs.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/lua/executor.h"
+#include "nvim/lua/secure.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/secure.c.generated.h"
+#endif
+
+char *nlua_read_secure(const char *path)
+{
+ lua_State *const lstate = get_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;
+}
+
+static bool nlua_trust(const char *action, const char *path)
+{
+ lua_State *const lstate = get_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(0, "Allowed \"%s\" in trust database.", msg);
+ } else if (strcmp(action, "deny") == 0) {
+ smsg(0, "Denied \"%s\" in trust database.", msg);
+ } else if (strcmp(action, "remove") == 0) {
+ smsg(0, "Removed \"%s\" from trust database.", msg);
+ }
+ } else {
+ semsg(e_trustfile, msg);
+ }
+ }
+
+ lua_settop(lstate, top);
+ return success;
+}
+
+void ex_trust(exarg_T *eap)
+{
+ const char *const p = skiptowhite(eap->arg);
+ char *arg1 = xmemdupz(eap->arg, (size_t)(p - eap->arg));
+ const char *action = "allow";
+ const char *path = skipwhite(p);
+
+ if (strcmp(arg1, "++deny") == 0) {
+ action = "deny";
+ } else if (strcmp(arg1, "++remove") == 0) {
+ action = "remove";
+ } else if (*arg1 != '\0') {
+ semsg(e_invarg2, arg1);
+ goto theend;
+ }
+
+ if (path[0] == '\0') {
+ path = NULL;
+ }
+
+ nlua_trust(action, path);
+
+theend:
+ xfree(arg1);
+}
diff --git a/src/nvim/lua/secure.h b/src/nvim/lua/secure.h
new file mode 100644
index 0000000000..c69c0d4f8f
--- /dev/null
+++ b/src/nvim/lua/secure.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/secure.h.generated.h"
+#endif
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
index d510d25e90..c261c5105e 100644
--- a/src/nvim/lua/spell.c
+++ b/src/nvim/lua/spell.c
@@ -1,6 +1,3 @@
-// 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>
@@ -8,7 +5,7 @@
#include <stdbool.h>
#include <stddef.h>
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
@@ -16,7 +13,6 @@
#include "nvim/lua/spell.h"
#include "nvim/message.h"
#include "nvim/spell.h"
-#include "nvim/types.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/spell.c.generated.h" // IWYU pragma: export
@@ -39,7 +35,7 @@ int nlua_spell_check(lua_State *lstate)
const int wo_spell_save = curwin->w_p_spell;
if (!curwin->w_p_spell) {
- did_set_spelllang(curwin);
+ parse_spelllang(curwin);
curwin->w_p_spell = true;
}
@@ -51,7 +47,6 @@ int nlua_spell_check(lua_State *lstate)
}
hlf_T attr = HLF_COUNT;
- size_t len = 0;
size_t pos = 0;
int capcol = -1;
int no_res = 0;
@@ -61,7 +56,7 @@ int nlua_spell_check(lua_State *lstate)
while (*str != NUL) {
attr = HLF_COUNT;
- len = spell_check(curwin, (char *)str, &attr, &capcol, false);
+ size_t len = spell_check(curwin, (char *)str, &attr, &capcol, false);
assert(len <= INT_MAX);
if (attr != HLF_COUNT) {
@@ -70,11 +65,11 @@ int nlua_spell_check(lua_State *lstate)
lua_pushlstring(lstate, str, len);
lua_rawseti(lstate, -2, 1);
- result = attr == HLF_SPB ? "bad" :
- attr == HLF_SPR ? "rare" :
- attr == HLF_SPL ? "local" :
- attr == HLF_SPC ? "caps" :
- NULL;
+ result = attr == HLF_SPB
+ ? "bad" : (attr == HLF_SPR
+ ? "rare" : (attr == HLF_SPL
+ ? "local" : (attr == HLF_SPC
+ ? "caps" : NULL)));
assert(result != NULL);
@@ -82,7 +77,7 @@ int nlua_spell_check(lua_State *lstate)
lua_rawseti(lstate, -2, 2);
// +1 for 1-indexing
- lua_pushinteger(lstate, (long)pos + 1);
+ lua_pushinteger(lstate, (lua_Integer)pos + 1);
lua_rawseti(lstate, -2, 3);
lua_rawseti(lstate, -2, ++no_res);
diff --git a/src/nvim/lua/spell.h b/src/nvim/lua/spell.h
index 8f798a5191..6f1b322e5b 100644
--- a/src/nvim/lua/spell.h
+++ b/src/nvim/lua/spell.h
@@ -1,12 +1,7 @@
-#ifndef NVIM_LUA_SPELL_H
-#define NVIM_LUA_SPELL_H
+#pragma once
-#include <lauxlib.h>
-#include <lua.h>
-#include <lualib.h>
+#include <lua.h> // IWYU pragma: keep
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/spell.h.generated.h"
#endif
-
-#endif // NVIM_LUA_SPELL_H
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index 6ebca6d97e..33770b2e62 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -1,6 +1,3 @@
-// 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>
@@ -11,30 +8,36 @@
#include <string.h>
#include <sys/types.h>
-#include "auto/config.h"
+#ifdef NVIM_VENDOR_BIT
+# include "bit.h"
+#endif
+
#include "cjson/lua_cjson.h"
#include "mpack/lmpack.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
-#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/typval_defs.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_eval.h"
+#include "nvim/fold.h"
+#include "nvim/func_attr.h"
#include "nvim/globals.h"
+#include "nvim/lua/base64.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/spell.h"
#include "nvim/lua/stdlib.h"
#include "nvim/lua/xdiff.h"
-#include "nvim/map.h"
+#include "nvim/map_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/pos.h"
+#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
-#include "nvim/types.h"
-#include "nvim/vim.h"
+#include "nvim/runtime.h"
+#include "nvim/strings.h"
+#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/stdlib.c.generated.h"
@@ -78,20 +81,20 @@ static int regex_match_line(lua_State *lstate)
return luaL_error(lstate, "not enough args");
}
- long bufnr = luaL_checkinteger(lstate, 2);
+ handle_T bufnr = (handle_T)luaL_checkinteger(lstate, 2);
linenr_T rownr = (linenr_T)luaL_checkinteger(lstate, 3);
- long start = 0, end = -1;
+ int start = 0, end = -1;
if (narg >= 4) {
- start = luaL_checkinteger(lstate, 4);
+ start = (int)luaL_checkinteger(lstate, 4);
}
if (narg >= 5) {
- end = luaL_checkinteger(lstate, 5);
+ end = (int)luaL_checkinteger(lstate, 5);
if (end < 0) {
return luaL_error(lstate, "invalid end");
}
}
- buf_T *buf = bufnr ? handle_get_buffer((int)bufnr) : curbuf;
+ buf_T *buf = bufnr ? handle_get_buffer(bufnr) : curbuf;
if (!buf || buf->b_ml.ml_mfp == NULL) {
return luaL_error(lstate, "invalid buffer");
}
@@ -100,7 +103,7 @@ static int regex_match_line(lua_State *lstate)
return luaL_error(lstate, "invalid row");
}
- char *line = ml_get_buf(buf, rownr + 1, false);
+ char *line = ml_get_buf(buf, rownr + 1);
size_t len = strlen(line);
if (start < 0 || (size_t)start > len) {
@@ -178,8 +181,8 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
size_t codepoints = 0, codeunits = 0;
mb_utflen(s1, (size_t)idx, &codepoints, &codeunits);
- lua_pushinteger(lstate, (long)codepoints);
- lua_pushinteger(lstate, (long)codeunits);
+ lua_pushinteger(lstate, (lua_Integer)codepoints);
+ lua_pushinteger(lstate, (lua_Integer)codeunits);
return 2;
}
@@ -199,7 +202,7 @@ static int nlua_str_utf_pos(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
size_t clen;
for (size_t i = 0; i < s1_len && s1[i] != NUL; i += clen) {
clen = (size_t)utf_ptr2len_len(s1 + i, (int)(s1_len - i));
- lua_pushinteger(lstate, (long)i + 1);
+ lua_pushinteger(lstate, (lua_Integer)i + 1);
lua_rawseti(lstate, -2, (int)idx);
idx++;
}
@@ -218,11 +221,11 @@ static int nlua_str_utf_start(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
size_t s1_len;
const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
- long offset = luaL_checkinteger(lstate, 2);
+ ptrdiff_t offset = luaL_checkinteger(lstate, 2);
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int head_offset = utf_cp_head_off((char_u *)s1, (char_u *)s1 + offset - 1);
+ int head_offset = -utf_cp_head_off(s1, s1 + offset - 1);
lua_pushinteger(lstate, head_offset);
return 1;
}
@@ -238,7 +241,7 @@ static int nlua_str_utf_end(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
size_t s1_len;
const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
- long offset = luaL_checkinteger(lstate, 2);
+ ptrdiff_t offset = luaL_checkinteger(lstate, 2);
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
@@ -271,7 +274,7 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return luaL_error(lstate, "index out of range");
}
- lua_pushinteger(lstate, (long)byteidx);
+ lua_pushinteger(lstate, (lua_Integer)byteidx);
return 1;
}
@@ -282,10 +285,8 @@ int nlua_regex(lua_State *lstate)
const char *text = luaL_checkstring(lstate, 1);
regprog_T *prog = NULL;
- TRY_WRAP({
- try_start();
- prog = vim_regcomp((char *)text, RE_AUTO | RE_MAGIC | RE_STRICT);
- try_end(&err);
+ TRY_WRAP(&err, {
+ prog = vim_regcomp(text, RE_AUTO | RE_MAGIC | RE_STRICT);
});
if (ERROR_SET(&err)) {
@@ -356,6 +357,9 @@ int nlua_setvar(lua_State *lstate)
Error err = ERROR_INIT;
dictitem_T *di = dict_check_writable(dict, key, del, &err);
if (ERROR_SET(&err)) {
+ nlua_push_errstr(lstate, "%s", err.msg);
+ api_clear_error(&err);
+ lua_error(lstate);
return 0;
}
@@ -391,6 +395,15 @@ int nlua_setvar(lua_State *lstate)
di = tv_dict_item_alloc_len(key.data, key.size);
tv_dict_add(dict, di);
} else {
+ bool type_error = false;
+ if (dict == &vimvardict
+ && !before_set_vvar(key.data, di, &tv, true, watched, &type_error)) {
+ tv_clear(&tv);
+ if (type_error) {
+ return luaL_error(lstate, "Setting v:%s to value with wrong type", key.data);
+ }
+ return 0;
+ }
if (watched) {
tv_copy(&di->di_tv, &oldtv);
}
@@ -452,7 +465,7 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
int ret = 0;
assert(s1[s1_len] == NUL);
assert(s2[s2_len] == NUL);
- do {
+ while (true) {
nul1 = memchr(s1, NUL, s1_len);
nul2 = memchr(s2, NUL, s2_len);
ret = STRICMP(s1, s2);
@@ -476,7 +489,7 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
} else {
break;
}
- } while (true);
+ }
lua_pop(lstate, 2);
lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0)));
return 1;
@@ -501,7 +514,7 @@ static int nlua_iconv(lua_State *lstate)
const char *str = lua_tolstring(lstate, 1, &str_len);
char *from = enc_canonize(enc_skip((char *)lua_tolstring(lstate, 2, NULL)));
- char *to = enc_canonize(enc_skip((char *)lua_tolstring(lstate, 3, NULL)));
+ char *to = enc_canonize(enc_skip((char *)lua_tolstring(lstate, 3, NULL)));
vimconv_T vimconv;
vimconv.vc_type = CONV_NONE;
@@ -524,6 +537,31 @@ static int nlua_iconv(lua_State *lstate)
return 1;
}
+// Like 'zx' but don't call newFoldLevel()
+static int nlua_foldupdate(lua_State *lstate)
+{
+ curwin->w_foldinvalid = true; // recompute folds
+ foldOpenCursor();
+
+ return 0;
+}
+
+// Access to internal functions. For use in runtime/
+static void nlua_state_add_internal(lua_State *const lstate)
+{
+ // _getvar
+ lua_pushcfunction(lstate, &nlua_getvar);
+ lua_setfield(lstate, -2, "_getvar");
+
+ // _setvar
+ lua_pushcfunction(lstate, &nlua_setvar);
+ lua_setfield(lstate, -2, "_setvar");
+
+ // _updatefolds
+ lua_pushcfunction(lstate, &nlua_foldupdate);
+ lua_setfield(lstate, -2, "_foldupdate");
+}
+
void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
{
if (!is_thread) {
@@ -558,14 +596,6 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
lua_setfield(lstate, -2, "__index"); // [meta]
lua_pop(lstate, 1); // don't use metatable now
- // _getvar
- lua_pushcfunction(lstate, &nlua_getvar);
- lua_setfield(lstate, -2, "_getvar");
-
- // _setvar
- lua_pushcfunction(lstate, &nlua_setvar);
- lua_setfield(lstate, -2, "_setvar");
-
// vim.spell
luaopen_spell(lstate);
lua_setfield(lstate, -2, "spell");
@@ -574,6 +604,12 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
// depends on p_ambw, p_emoji
lua_pushcfunction(lstate, &nlua_iconv);
lua_setfield(lstate, -2, "iconv");
+
+ // vim.base64
+ luaopen_base64(lstate);
+ lua_setfield(lstate, -2, "base64");
+
+ nlua_state_add_internal(lstate);
}
// vim.mpack
@@ -589,6 +625,19 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
lua_setfield(lstate, -2, "mpack");
lua_pop(lstate, 3);
+ // vim.lpeg
+ int luaopen_lpeg(lua_State *);
+ luaopen_lpeg(lstate);
+ lua_pushvalue(lstate, -1);
+ lua_setfield(lstate, -4, "lpeg");
+
+ // package.loaded.lpeg = vim.lpeg
+ lua_getglobal(lstate, "package");
+ lua_getfield(lstate, -1, "loaded");
+ lua_pushvalue(lstate, -3);
+ lua_setfield(lstate, -2, "lpeg");
+ lua_pop(lstate, 4);
+
// vim.diff
lua_pushcfunction(lstate, &nlua_xdl_diff);
lua_setfield(lstate, -2, "diff");
@@ -596,6 +645,13 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
// vim.json
lua_cjson_new(lstate);
lua_setfield(lstate, -2, "json");
+
+#ifdef NVIM_VENDOR_BIT
+ // if building with puc lua, use internal fallback for require'bit'
+ int top = lua_gettop(lstate);
+ luaopen_bit(lstate);
+ lua_settop(lstate, top);
+#endif
}
/// like luaL_error, but allow cleanup
diff --git a/src/nvim/lua/stdlib.h b/src/nvim/lua/stdlib.h
index 17aec6714d..26e96055ae 100644
--- a/src/nvim/lua/stdlib.h
+++ b/src/nvim/lua/stdlib.h
@@ -1,10 +1,7 @@
-#ifndef NVIM_LUA_STDLIB_H
-#define NVIM_LUA_STDLIB_H
+#pragma once
-#include <lua.h>
+#include <lua.h> // IWYU pragma: keep
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/stdlib.h.generated.h"
#endif
-
-#endif // NVIM_LUA_STDLIB_H
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 56f4daed1a..008b3f2e95 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -1,11 +1,9 @@
-// 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
-
// lua bindings for tree-sitter.
// NB: this file mostly contains a generic lua interface for tree-sitter
// trees and nodes, and could be broken out as a reusable lua package
#include <assert.h>
+#include <ctype.h>
#include <lauxlib.h>
#include <limits.h>
#include <lua.h>
@@ -14,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <tree_sitter/api.h>
#include <uv.h>
#include "klib/kvec.h"
@@ -21,14 +20,13 @@
#include "nvim/buffer_defs.h"
#include "nvim/globals.h"
#include "nvim/lua/treesitter.h"
-#include "nvim/macros.h"
-#include "nvim/map.h"
+#include "nvim/macros_defs.h"
+#include "nvim/map_defs.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/pos.h"
+#include "nvim/pos_defs.h"
#include "nvim/strings.h"
-#include "nvim/types.h"
-#include "tree_sitter/api.h"
+#include "nvim/types_defs.h"
#define TS_META_PARSER "treesitter_parser"
#define TS_META_TREE "treesitter_tree"
@@ -43,6 +41,17 @@ typedef struct {
int max_match_id;
} TSLua_cursor;
+typedef struct {
+ LuaRef cb;
+ lua_State *lstate;
+ bool lex;
+ bool parse;
+} TSLuaLoggerOpts;
+
+typedef struct {
+ TSTree *tree;
+} TSLuaTree;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/treesitter.c.generated.h"
#endif
@@ -51,8 +60,13 @@ static struct luaL_Reg parser_meta[] = {
{ "__gc", parser_gc },
{ "__tostring", parser_tostring },
{ "parse", parser_parse },
+ { "reset", parser_reset },
{ "set_included_ranges", parser_set_ranges },
{ "included_ranges", parser_get_ranges },
+ { "set_timeout", parser_set_timeout },
+ { "timeout", parser_get_timeout },
+ { "_set_logger", parser_set_logger },
+ { "_logger", parser_get_logger },
{ NULL, NULL }
};
@@ -61,6 +75,7 @@ static struct luaL_Reg tree_meta[] = {
{ "__tostring", tree_tostring },
{ "root", tree_root },
{ "edit", tree_edit },
+ { "included_ranges", tree_get_ranges },
{ "copy", tree_copy },
{ NULL, NULL }
};
@@ -78,6 +93,8 @@ static struct luaL_Reg node_meta[] = {
{ "field", node_field },
{ "named", node_named },
{ "missing", node_missing },
+ { "extra", node_extra },
+ { "has_changes", node_has_changes },
{ "has_error", node_has_error },
{ "sexpr", node_sexpr },
{ "child_count", node_child_count },
@@ -95,7 +112,9 @@ static struct luaL_Reg node_meta[] = {
{ "prev_named_sibling", node_prev_named_sibling },
{ "named_children", node_named_children },
{ "root", node_root },
+ { "tree", node_tree },
{ "byte_length", node_byte_length },
+ { "equal", node_equal },
{ NULL, NULL }
};
@@ -132,9 +151,9 @@ static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
lua_pop(L, 1); // [] (don't use it now)
}
-/// init the tslua library
+/// Init the tslua library.
///
-/// all global state is stored in the regirstry of the lua_State
+/// All global state is stored in the registry of the lua_State.
void tslua_init(lua_State *L)
{
// type metatables
@@ -145,15 +164,13 @@ void tslua_init(lua_State *L)
build_meta(L, TS_META_QUERYCURSOR, querycursor_meta);
build_meta(L, TS_META_TREECURSOR, treecursor_meta);
-#ifdef NVIM_TS_HAS_SET_ALLOCATOR
ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree);
-#endif
}
int tslua_has_language(lua_State *L)
{
const char *lang_name = luaL_checkstring(L, 1);
- lua_pushboolean(L, pmap_has(cstr_t)(&langs, lang_name));
+ lua_pushboolean(L, map_has(cstr_t, &langs, lang_name));
return 1;
}
@@ -170,7 +187,7 @@ int tslua_add_language(lua_State *L)
symbol_name = luaL_checkstring(L, 3);
}
- if (pmap_has(cstr_t)(&langs, lang_name)) {
+ if (map_has(cstr_t, &langs, lang_name)) {
lua_pushboolean(L, true);
return 1;
}
@@ -223,11 +240,11 @@ int tslua_add_language(lua_State *L)
int tslua_remove_lang(lua_State *L)
{
const char *lang_name = luaL_checkstring(L, 1);
- bool present = pmap_has(cstr_t)(&langs, lang_name);
+ bool present = map_has(cstr_t, &langs, lang_name);
if (present) {
- char *key = (char *)pmap_key(cstr_t)(&langs, lang_name);
- pmap_del(cstr_t)(&langs, lang_name);
- xfree(key);
+ cstr_t key;
+ pmap_del(cstr_t)(&langs, lang_name, &key);
+ xfree((void *)key);
}
lua_pushboolean(L, present);
return 1;
@@ -309,6 +326,17 @@ static TSParser **parser_check(lua_State *L, uint16_t index)
return luaL_checkudata(L, index, TS_META_PARSER);
}
+static void logger_gc(TSLogger logger)
+{
+ if (!logger.log) {
+ return;
+ }
+
+ TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)logger.payload;
+ luaL_unref(opts->lstate, LUA_REGISTRYINDEX, opts->cb);
+ xfree(opts);
+}
+
static int parser_gc(lua_State *L)
{
TSParser **p = parser_check(L, 1);
@@ -316,6 +344,7 @@ static int parser_gc(lua_State *L)
return 0;
}
+ logger_gc(ts_parser_logger(*p));
ts_parser_delete(*p);
return 0;
}
@@ -329,7 +358,7 @@ static int parser_tostring(lua_State *L)
static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position,
uint32_t *bytes_read)
{
- buf_T *bp = payload;
+ buf_T *bp = payload;
#define BUFSIZE 256
static char buf[BUFSIZE];
@@ -337,7 +366,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
*bytes_read = 0;
return "";
}
- char *line = ml_get_buf(bp, (linenr_T)position.row + 1, false);
+ char *line = ml_get_buf(bp, (linenr_T)position.row + 1);
size_t len = strlen(line);
if (position.column > len) {
*bytes_read = 0;
@@ -359,19 +388,29 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
#undef BUFSIZE
}
-static void push_ranges(lua_State *L, const TSRange *ranges, const size_t length)
+static void push_ranges(lua_State *L, const TSRange *ranges, const size_t length,
+ bool include_bytes)
{
lua_createtable(L, (int)length, 0);
for (size_t i = 0; i < length; i++) {
- lua_createtable(L, 4, 0);
+ lua_createtable(L, include_bytes ? 6 : 4, 0);
+ int j = 1;
lua_pushinteger(L, ranges[i].start_point.row);
- lua_rawseti(L, -2, 1);
+ lua_rawseti(L, -2, j++);
lua_pushinteger(L, ranges[i].start_point.column);
- lua_rawseti(L, -2, 2);
+ lua_rawseti(L, -2, j++);
+ if (include_bytes) {
+ lua_pushinteger(L, ranges[i].start_byte);
+ lua_rawseti(L, -2, j++);
+ }
lua_pushinteger(L, ranges[i].end_point.row);
- lua_rawseti(L, -2, 3);
+ lua_rawseti(L, -2, j++);
lua_pushinteger(L, ranges[i].end_point.column);
- lua_rawseti(L, -2, 4);
+ lua_rawseti(L, -2, j++);
+ if (include_bytes) {
+ lua_pushinteger(L, ranges[i].end_byte);
+ lua_rawseti(L, -2, j++);
+ }
lua_rawseti(L, -2, (int)(i + 1));
}
@@ -386,14 +425,14 @@ static int parser_parse(lua_State *L)
TSTree *old_tree = NULL;
if (!lua_isnil(L, 2)) {
- TSTree **tmp = tree_check(L, 2);
- old_tree = tmp ? *tmp : NULL;
+ TSLuaTree *ud = tree_check(L, 2);
+ old_tree = ud ? ud->tree : NULL;
}
TSTree *new_tree = NULL;
size_t len;
const char *str;
- long bufnr;
+ handle_T bufnr;
buf_T *buf;
TSInput input;
@@ -406,13 +445,13 @@ static int parser_parse(lua_State *L)
break;
case LUA_TNUMBER:
- bufnr = lua_tointeger(L, 3);
- buf = handle_get_buffer((handle_T)bufnr);
+ bufnr = (handle_T)lua_tointeger(L, 3);
+ buf = handle_get_buffer(bufnr);
if (!buf) {
#define BUFSIZE 256
char ebuf[BUFSIZE] = { 0 };
- vim_snprintf(ebuf, BUFSIZE, "invalid buffer handle: %ld", bufnr);
+ vim_snprintf(ebuf, BUFSIZE, "invalid buffer handle: %d", bufnr);
return luaL_argerror(L, 3, ebuf);
#undef BUFSIZE
}
@@ -426,34 +465,46 @@ static int parser_parse(lua_State *L)
return luaL_argerror(L, 3, "expected either string or buffer handle");
}
+ bool include_bytes = (lua_gettop(L) >= 4) && lua_toboolean(L, 4);
+
// Sometimes parsing fails (timeout, or wrong parser ABI)
// In those case, just return an error.
if (!new_tree) {
return luaL_error(L, "An error occurred when parsing.");
}
- // The new tree will be pushed to the stack, without copy, ownership is now to
- // the lua GC.
- // Old tree is still owned by the lua GC.
+ // The new tree will be pushed to the stack, without copy, ownership is now to the lua GC.
+ // Old tree is owned by lua GC since before
uint32_t n_ranges = 0;
- TSRange *changed = old_tree ? ts_tree_get_changed_ranges(old_tree, new_tree, &n_ranges) : NULL;
+ TSRange *changed = old_tree ? ts_tree_get_changed_ranges(old_tree, new_tree, &n_ranges) : NULL;
- push_tree(L, new_tree, false); // [tree]
+ push_tree(L, new_tree); // [tree]
- push_ranges(L, changed, n_ranges); // [tree, ranges]
+ push_ranges(L, changed, n_ranges, include_bytes); // [tree, ranges]
xfree(changed);
return 2;
}
+static int parser_reset(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (p && *p) {
+ ts_parser_reset(*p);
+ }
+
+ return 0;
+}
+
static int tree_copy(lua_State *L)
{
- TSTree **tree = tree_check(L, 1);
- if (!(*tree)) {
+ TSLuaTree *ud = tree_check(L, 1);
+ if (!ud) {
return 0;
}
- push_tree(L, *tree, true); // [tree]
+ TSTree *copy = ts_tree_copy(ud->tree);
+ push_tree(L, copy); // [tree]
return 1;
}
@@ -465,8 +516,8 @@ static int tree_edit(lua_State *L)
return lua_error(L);
}
- TSTree **tree = tree_check(L, 1);
- if (!(*tree)) {
+ TSLuaTree *ud = tree_check(L, 1);
+ if (!ud) {
return 0;
}
@@ -480,11 +531,29 @@ static int tree_edit(lua_State *L)
TSInputEdit edit = { start_byte, old_end_byte, new_end_byte,
start_point, old_end_point, new_end_point };
- ts_tree_edit(*tree, &edit);
+ ts_tree_edit(ud->tree, &edit);
return 0;
}
+static int tree_get_ranges(lua_State *L)
+{
+ TSLuaTree *ud = tree_check(L, 1);
+ if (!ud) {
+ return 0;
+ }
+
+ bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2);
+
+ uint32_t len;
+ TSRange *ranges = ts_tree_included_ranges(ud->tree, &len);
+
+ push_ranges(L, ranges, len, include_bytes);
+
+ xfree(ranges);
+ return 1;
+}
+
// Use the top of the stack (without popping it) to create a TSRange, it can be
// either a lua table or a TSNode
static void range_from_lua(lua_State *L, TSRange *range)
@@ -590,58 +659,159 @@ static int parser_get_ranges(lua_State *L)
return 0;
}
+ bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2);
+
uint32_t len;
const TSRange *ranges = ts_parser_included_ranges(*p, &len);
- push_ranges(L, ranges, len);
+ push_ranges(L, ranges, len, include_bytes);
+ return 1;
+}
+
+static int parser_set_timeout(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (!p) {
+ return 0;
+ }
+
+ if (lua_gettop(L) < 2) {
+ luaL_error(L, "integer expected");
+ }
+
+ uint32_t timeout = (uint32_t)luaL_checkinteger(L, 2);
+ ts_parser_set_timeout_micros(*p, timeout);
+ return 0;
+}
+
+static int parser_get_timeout(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (!p) {
+ return 0;
+ }
+
+ lua_pushinteger(L, (lua_Integer)ts_parser_timeout_micros(*p));
+ return 1;
+}
+
+static void logger_cb(void *payload, TSLogType logtype, const char *s)
+{
+ TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)payload;
+ if ((!opts->lex && logtype == TSLogTypeLex)
+ || (!opts->parse && logtype == TSLogTypeParse)) {
+ return;
+ }
+
+ lua_State *lstate = opts->lstate;
+
+ lua_rawgeti(lstate, LUA_REGISTRYINDEX, opts->cb);
+ lua_pushstring(lstate, logtype == TSLogTypeParse ? "parse" : "lex");
+ lua_pushstring(lstate, s);
+ if (lua_pcall(lstate, 2, 0, 0)) {
+ luaL_error(lstate, "Error executing treesitter logger callback");
+ }
+}
+
+static int parser_set_logger(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (!p) {
+ return 0;
+ }
+
+ if (!lua_isboolean(L, 2)) {
+ return luaL_argerror(L, 2, "boolean expected");
+ }
+
+ if (!lua_isboolean(L, 3)) {
+ return luaL_argerror(L, 3, "boolean expected");
+ }
+
+ if (!lua_isfunction(L, 4)) {
+ return luaL_argerror(L, 4, "function expected");
+ }
+
+ TSLuaLoggerOpts *opts = xmalloc(sizeof(TSLuaLoggerOpts));
+ lua_pushvalue(L, 4);
+ LuaRef ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ *opts = (TSLuaLoggerOpts){
+ .lex = lua_toboolean(L, 2),
+ .parse = lua_toboolean(L, 3),
+ .cb = ref,
+ .lstate = L
+ };
+
+ TSLogger logger = {
+ .payload = (void *)opts,
+ .log = logger_cb
+ };
+
+ ts_parser_set_logger(*p, logger);
+ return 0;
+}
+
+static int parser_get_logger(lua_State *L)
+{
+ TSParser **p = parser_check(L, 1);
+ if (!p) {
+ return 0;
+ }
+
+ TSLogger logger = ts_parser_logger(*p);
+ if (logger.log) {
+ TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)logger.payload;
+ lua_rawgeti(L, LUA_REGISTRYINDEX, opts->cb);
+ } else {
+ lua_pushnil(L);
+ }
+
return 1;
}
// Tree methods
-/// push tree interface on lua stack.
+/// Push tree interface on to the lua stack.
///
-/// This makes a copy of the tree, so ownership of the argument is unaffected.
-void push_tree(lua_State *L, TSTree *tree, bool do_copy)
+/// The tree is not copied. Ownership of the tree is transferred from C to
+/// Lua. If needed use ts_tree_copy() in the caller
+static void push_tree(lua_State *L, TSTree *tree)
{
if (tree == NULL) {
lua_pushnil(L);
return;
}
- TSTree **ud = lua_newuserdata(L, sizeof(TSTree *)); // [udata]
- if (do_copy) {
- *ud = ts_tree_copy(tree);
- } else {
- *ud = tree;
- }
+ TSLuaTree *ud = lua_newuserdata(L, sizeof(TSLuaTree)); // [udata]
+
+ ud->tree = tree;
lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREE); // [udata, meta]
lua_setmetatable(L, -2); // [udata]
- // table used for node wrappers to keep a reference to tree wrapper
- // NB: in lua 5.3 the uservalue for the node could just be the tree, but
- // in lua 5.1 the uservalue (fenv) must be a table.
+ // To prevent the tree from being garbage collected, create a reference to it
+ // in the fenv which will be passed to userdata nodes of the tree.
+ // Note: environments (fenvs) associated with userdata have no meaning in Lua
+ // and are only used to associate a table.
lua_createtable(L, 1, 0); // [udata, reftable]
lua_pushvalue(L, -2); // [udata, reftable, udata]
lua_rawseti(L, -2, 1); // [udata, reftable]
lua_setfenv(L, -2); // [udata]
}
-static TSTree **tree_check(lua_State *L, int index)
+static TSLuaTree *tree_check(lua_State *L, int index)
{
- TSTree **ud = luaL_checkudata(L, index, TS_META_TREE);
+ TSLuaTree *ud = luaL_checkudata(L, index, TS_META_TREE);
return ud;
}
static int tree_gc(lua_State *L)
{
- TSTree **tree = tree_check(L, 1);
- if (!tree) {
- return 0;
+ TSLuaTree *ud = tree_check(L, 1);
+ if (ud) {
+ ts_tree_delete(ud->tree);
}
-
- ts_tree_delete(*tree);
return 0;
}
@@ -653,20 +823,20 @@ static int tree_tostring(lua_State *L)
static int tree_root(lua_State *L)
{
- TSTree **tree = tree_check(L, 1);
- if (!tree) {
+ TSLuaTree *ud = tree_check(L, 1);
+ if (!ud) {
return 0;
}
- TSNode root = ts_tree_root_node(*tree);
+ TSNode root = ts_tree_root_node(ud->tree);
push_node(L, root, 1);
return 1;
}
// Node methods
-/// push node interface on lua stack
+/// Push node interface on to the Lua stack
///
-/// top of stack must either be the tree this node belongs to or another node
+/// Top of stack must either be the tree this node belongs to or another node
/// of the same tree! This value is not popped. Can only be called inside a
/// cfunction with the tslua environment.
static void push_node(lua_State *L, TSNode node, int uindex)
@@ -680,6 +850,8 @@ static void push_node(lua_State *L, TSNode node, int uindex)
*ud = node;
lua_getfield(L, LUA_REGISTRYINDEX, TS_META_NODE); // [udata, meta]
lua_setmetatable(L, -2); // [udata]
+
+ // Copy the fenv which contains the nodes tree.
lua_getfenv(L, uindex); // [udata, reftable]
lua_setfenv(L, -2); // [udata]
}
@@ -740,12 +912,26 @@ static int node_range(lua_State *L)
if (!node_check(L, 1, &node)) {
return 0;
}
+
+ bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2);
+
TSPoint start = ts_node_start_point(node);
TSPoint end = ts_node_end_point(node);
- lua_pushnumber(L, start.row);
- lua_pushnumber(L, start.column);
- lua_pushnumber(L, end.row);
- lua_pushnumber(L, end.column);
+
+ if (include_bytes) {
+ lua_pushinteger(L, start.row);
+ lua_pushinteger(L, start.column);
+ lua_pushinteger(L, ts_node_start_byte(node));
+ lua_pushinteger(L, end.row);
+ lua_pushinteger(L, end.column);
+ lua_pushinteger(L, ts_node_end_byte(node));
+ return 6;
+ }
+
+ lua_pushinteger(L, start.row);
+ lua_pushinteger(L, start.column);
+ lua_pushinteger(L, end.row);
+ lua_pushinteger(L, end.column);
return 4;
}
@@ -757,9 +943,9 @@ static int node_start(lua_State *L)
}
TSPoint start = ts_node_start_point(node);
uint32_t start_byte = ts_node_start_byte(node);
- lua_pushnumber(L, start.row);
- lua_pushnumber(L, start.column);
- lua_pushnumber(L, start_byte);
+ lua_pushinteger(L, start.row);
+ lua_pushinteger(L, start.column);
+ lua_pushinteger(L, start_byte);
return 3;
}
@@ -771,9 +957,9 @@ static int node_end(lua_State *L)
}
TSPoint end = ts_node_end_point(node);
uint32_t end_byte = ts_node_end_byte(node);
- lua_pushnumber(L, end.row);
- lua_pushnumber(L, end.column);
- lua_pushnumber(L, end_byte);
+ lua_pushinteger(L, end.row);
+ lua_pushinteger(L, end.column);
+ lua_pushinteger(L, end_byte);
return 3;
}
@@ -784,7 +970,7 @@ static int node_child_count(lua_State *L)
return 0;
}
uint32_t count = ts_node_child_count(node);
- lua_pushnumber(L, count);
+ lua_pushinteger(L, count);
return 1;
}
@@ -795,7 +981,7 @@ static int node_named_child_count(lua_State *L)
return 0;
}
uint32_t count = ts_node_named_child_count(node);
- lua_pushnumber(L, count);
+ lua_pushinteger(L, count);
return 1;
}
@@ -816,7 +1002,7 @@ static int node_symbol(lua_State *L)
return 0;
}
TSSymbol symbol = ts_node_symbol(node);
- lua_pushnumber(L, symbol);
+ lua_pushinteger(L, symbol);
return 1;
}
@@ -882,6 +1068,26 @@ static int node_missing(lua_State *L)
return 1;
}
+static int node_extra(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ lua_pushboolean(L, ts_node_is_extra(node));
+ return 1;
+}
+
+static int node_has_changes(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ lua_pushboolean(L, ts_node_has_changes(node));
+ return 1;
+}
+
static int node_has_error(lua_State *L)
{
TSNode node;
@@ -898,8 +1104,8 @@ static int node_child(lua_State *L)
if (!node_check(L, 1, &node)) {
return 0;
}
- long num = lua_tointeger(L, 2);
- TSNode child = ts_node_child(node, (uint32_t)num);
+ uint32_t num = (uint32_t)lua_tointeger(L, 2);
+ TSNode child = ts_node_child(node, num);
push_node(L, child, 1);
return 1;
@@ -911,8 +1117,8 @@ static int node_named_child(lua_State *L)
if (!node_check(L, 1, &node)) {
return 0;
}
- long num = lua_tointeger(L, 2);
- TSNode child = ts_node_named_child(node, (uint32_t)num);
+ uint32_t num = (uint32_t)lua_tointeger(L, 2);
+ TSNode child = ts_node_named_child(node, num);
push_node(L, child, 1);
return 1;
@@ -1108,6 +1314,19 @@ static int node_root(lua_State *L)
return 1;
}
+static int node_tree(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+
+ lua_getfenv(L, 1); // [udata, reftable]
+ lua_rawgeti(L, -1, 1); // [udata, reftable, tree_udata]
+
+ return 1;
+}
+
static int node_byte_length(lua_State *L)
{
TSNode node;
@@ -1118,7 +1337,23 @@ static int node_byte_length(lua_State *L)
uint32_t start_byte = ts_node_start_byte(node);
uint32_t end_byte = ts_node_end_byte(node);
- lua_pushnumber(L, end_byte - start_byte);
+ lua_pushinteger(L, end_byte - start_byte);
+ return 1;
+}
+
+static int node_equal(lua_State *L)
+{
+ TSNode node1;
+ if (!node_check(L, 1, &node1)) {
+ return 0;
+ }
+
+ TSNode node2;
+ if (!node_check(L, 2, &node2)) {
+ return luaL_error(L, "TSNode expected");
+ }
+
+ lua_pushboolean(L, ts_node_eq(node1, node2));
return 1;
}
@@ -1213,11 +1448,12 @@ static int node_rawquery(lua_State *L)
} else {
cursor = ts_query_cursor_new();
}
- // TODO(clason): API introduced after tree-sitter release 0.19.5
- // remove guard when minimum ts version is bumped to 0.19.6+
-#ifdef NVIM_TS_HAS_SET_MATCH_LIMIT
- ts_query_cursor_set_match_limit(cursor, 64);
+
+#ifdef NVIM_TS_HAS_SET_MAX_START_DEPTH
+ // reset the start depth
+ ts_query_cursor_set_max_start_depth(cursor, UINT32_MAX);
#endif
+ ts_query_cursor_set_match_limit(cursor, 256);
ts_query_cursor_exec(cursor, query, node);
bool captures = lua_toboolean(L, 3);
@@ -1228,6 +1464,29 @@ static int node_rawquery(lua_State *L)
ts_query_cursor_set_point_range(cursor, (TSPoint){ start, 0 }, (TSPoint){ end, 0 });
}
+ if (lua_gettop(L) >= 6 && !lua_isnil(L, 6)) {
+ if (!lua_istable(L, 6)) {
+ return luaL_error(L, "table expected");
+ }
+ lua_pushnil(L);
+ // stack: [dict, ..., nil]
+ while (lua_next(L, 6)) {
+ // stack: [dict, ..., key, value]
+ if (lua_type(L, -2) == LUA_TSTRING) {
+ char *k = (char *)lua_tostring(L, -2);
+ if (strequal("max_start_depth", k)) {
+ // TODO(lewis6991): remove ifdef when min TS version is 0.20.9
+#ifdef NVIM_TS_HAS_SET_MAX_START_DEPTH
+ uint32_t max_start_depth = (uint32_t)lua_tointeger(L, -1);
+ ts_query_cursor_set_max_start_depth(cursor, max_start_depth);
+#endif
+ }
+ }
+ lua_pop(L, 1); // pop the value; lua_next will pop the key.
+ // stack: [dict, ..., key]
+ }
+ }
+
TSLua_cursor *ud = lua_newuserdata(L, sizeof(*ud)); // [udata]
ud->cursor = cursor;
ud->predicated_match = -1;
@@ -1281,8 +1540,9 @@ int tslua_parse_query(lua_State *L)
TSQuery *query = ts_query_new(lang, src, (uint32_t)len, &error_offset, &error_type);
if (!query) {
- return luaL_error(L, "query: %s at position %d for language %s",
- query_err_string(error_type), (int)error_offset, lang_name);
+ char err_msg[IOSIZE];
+ query_err_string(src, (int)error_offset, error_type, err_msg, sizeof(err_msg));
+ return luaL_error(L, "%s", err_msg);
}
TSQuery **ud = lua_newuserdata(L, sizeof(TSQuery *)); // [udata]
@@ -1292,24 +1552,79 @@ int tslua_parse_query(lua_State *L)
return 1;
}
-static const char *query_err_string(TSQueryError err)
+static const char *query_err_to_string(TSQueryError error_type)
{
- switch (err) {
+ switch (error_type) {
case TSQueryErrorSyntax:
- return "invalid syntax";
+ return "Invalid syntax:\n";
case TSQueryErrorNodeType:
- return "invalid node type";
+ return "Invalid node type ";
case TSQueryErrorField:
- return "invalid field";
+ return "Invalid field name ";
case TSQueryErrorCapture:
- return "invalid capture";
+ return "Invalid capture name ";
case TSQueryErrorStructure:
- return "invalid structure";
+ return "Impossible pattern:\n";
default:
return "error";
}
}
+static void query_err_string(const char *src, int error_offset, TSQueryError error_type, char *err,
+ size_t errlen)
+{
+ int line_start = 0;
+ int row = 0;
+ const char *error_line = NULL;
+ int error_line_len = 0;
+
+ const char *end_str;
+ do {
+ const char *src_tmp = src + line_start;
+ end_str = strchr(src_tmp, '\n');
+ int line_length = end_str != NULL ? (int)(end_str - src_tmp) : (int)strlen(src_tmp);
+ int line_end = line_start + line_length;
+ if (line_end > error_offset) {
+ error_line = src_tmp;
+ error_line_len = line_length;
+ break;
+ }
+ line_start = line_end + 1;
+ row++;
+ } while (end_str != NULL);
+
+ int column = error_offset - line_start;
+
+ const char *type_msg = query_err_to_string(error_type);
+ snprintf(err, errlen, "Query error at %d:%d. %s", row + 1, column + 1, type_msg);
+ size_t offset = strlen(err);
+ errlen = errlen - offset;
+ err = err + offset;
+
+ // Error types that report names
+ if (error_type == TSQueryErrorNodeType
+ || error_type == TSQueryErrorField
+ || error_type == TSQueryErrorCapture) {
+ const char *suffix = src + error_offset;
+ int suffix_len = 0;
+ char c = suffix[suffix_len];
+ while (isalnum(c) || c == '_' || c == '-' || c == '.') {
+ c = suffix[++suffix_len];
+ }
+ snprintf(err, errlen, "\"%.*s\":\n", suffix_len, suffix);
+ offset = strlen(err);
+ errlen = errlen - offset;
+ err = err + offset;
+ }
+
+ if (!error_line) {
+ snprintf(err, errlen, "Unexpected EOF\n");
+ return;
+ }
+
+ snprintf(err, errlen, "%.*s\n%*s^\n", error_line_len, error_line, column, "");
+}
+
static TSQuery *query_check(lua_State *L, int index)
{
TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY);
@@ -1367,7 +1682,7 @@ static int query_inspect(lua_State *L)
&strlen);
lua_pushlstring(L, str, strlen); // [retval, patterns, pat, pred, item]
} else if (step[k].type == TSQueryPredicateStepTypeCapture) {
- lua_pushnumber(L, step[k].value_id + 1); // [..., pat, pred, item]
+ lua_pushinteger(L, step[k].value_id + 1); // [..., pat, pred, item]
} else {
abort();
}
diff --git a/src/nvim/lua/treesitter.h b/src/nvim/lua/treesitter.h
index b69fb9dfae..4ef9a10602 100644
--- a/src/nvim/lua/treesitter.h
+++ b/src/nvim/lua/treesitter.h
@@ -1,14 +1,7 @@
-#ifndef NVIM_LUA_TREESITTER_H
-#define NVIM_LUA_TREESITTER_H
+#pragma once
-#include <lauxlib.h>
-#include <lua.h>
-#include <lualib.h>
-
-#include "tree_sitter/api.h"
+#include <lua.h> // IWYU pragma: keep
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/treesitter.h.generated.h"
#endif
-
-#endif // NVIM_LUA_TREESITTER_H
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
index 857b159af5..16c3aa5e11 100644
--- a/src/nvim/lua/xdiff.c
+++ b/src/nvim/lua/xdiff.c
@@ -1,9 +1,7 @@
-// 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 <lauxlib.h>
#include <lua.h>
#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
#include "luaconf.h"
@@ -13,9 +11,9 @@
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/lua/xdiff.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
#include "nvim/memory.h"
-#include "nvim/vim.h"
+#include "nvim/pos_defs.h"
#include "xdiff/xdiff.h"
#define COMPARED_BUFFER0 (1 << 0)
@@ -32,7 +30,7 @@ typedef struct {
Error *err;
mmfile_t *ma;
mmfile_t *mb;
- bool linematch;
+ int64_t linematch;
bool iwhite;
} hunkpriv_t;
@@ -63,25 +61,25 @@ static void lua_pushhunk(lua_State *lstate, long start_a, long count_a, long sta
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)
+static void get_linematch_results(lua_State *lstate, mmfile_t *ma, mmfile_t *mb, int start_a,
+ int count_a, int start_b, int 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 };
+ int diff_length[2] = { count_a, count_b };
- fastforward_buf_to_lnum(&diff_begin[0], start_a + 1);
- fastforward_buf_to_lnum(&diff_begin[1], start_b + 1);
+ fastforward_buf_to_lnum(&diff_begin[0], (linenr_T)start_a + 1);
+ fastforward_buf_to_lnum(&diff_begin[1], (linenr_T)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;
+ int lnuma = start_a, lnumb = start_b;
- long hunkstarta = lnuma;
- long hunkstartb = lnumb;
- long hunkcounta = 0;
- long hunkcountb = 0;
+ int hunkstarta = lnuma;
+ int hunkstartb = lnumb;
+ int hunkcounta = 0;
+ int 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);
@@ -109,8 +107,8 @@ static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
{
luaL_Buffer *buf = (luaL_Buffer *)priv;
for (int i = 0; i < nbuf; i++) {
- const long size = mb[i].size;
- for (long total = 0; total < size; total += LUAL_BUFFERSIZE) {
+ const int size = mb[i].size;
+ for (int total = 0; total < size; total += LUAL_BUFFERSIZE) {
const int tocopy = MIN((int)(size - total), LUAL_BUFFERSIZE);
char *p = luaL_prepbuffer(buf);
if (!p) {
@@ -124,11 +122,11 @@ 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)
+static int hunk_locations_cb(int start_a, int count_a, int start_b, int count_b, void *cb_data)
{
hunkpriv_t *priv = (hunkpriv_t *)cb_data;
lua_State *lstate = priv->lstate;
- if (priv->linematch) {
+ if (priv->linematch > 0 && count_a + count_b <= priv->linematch) {
get_linematch_results(lstate, priv->ma, priv->mb, start_a, count_a, start_b, count_b,
priv->iwhite);
} else {
@@ -139,7 +137,7 @@ static int hunk_locations_cb(long start_a, long count_a, long start_b, long coun
}
// hunk_func callback used when opts.on_hunk is given
-static int call_on_hunk_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data)
+static int call_on_hunk_cb(int start_a, int count_a, int start_b, int count_b, void *cb_data)
{
// Mimic extra offsets done by xdiff, see:
// src/xdiff/xemit.c:284
@@ -193,11 +191,11 @@ static bool check_xdiff_opt(ObjectType actType, ObjectType expType, const char *
{
if (actType != expType) {
const char *type_str =
- expType == kObjectTypeString ? "string" :
- expType == kObjectTypeInteger ? "integer" :
- expType == kObjectTypeBoolean ? "boolean" :
- expType == kObjectTypeLuaRef ? "function" :
- "NA";
+ expType == kObjectTypeString
+ ? "string" : (expType == kObjectTypeInteger
+ ? "integer" : (expType == kObjectTypeBoolean
+ ? "boolean" : (expType == kObjectTypeLuaRef
+ ? "function" : "NA")));
api_set_error(err, kErrorTypeValidation, "%s is not a %s", name,
type_str);
@@ -208,7 +206,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,
- bool *linematch, Error *err)
+ int64_t *linematch, Error *err)
{
const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err);
@@ -257,16 +255,20 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg,
if (check_xdiff_opt(v->type, kObjectTypeInteger, "ctxlen", err)) {
goto exit_1;
}
- cfg->ctxlen = v->data.integer;
+ cfg->ctxlen = (long)v->data.integer;
} else if (strequal("interhunkctxlen", k.data)) {
if (check_xdiff_opt(v->type, kObjectTypeInteger, "interhunkctxlen",
err)) {
goto exit_1;
}
- cfg->interhunkctxlen = v->data.integer;
+ cfg->interhunkctxlen = (long)v->data.integer;
} else if (strequal("linematch", k.data)) {
- *linematch = api_object_to_bool(*v, "linematch", false, err);
- if (ERROR_SET(err)) {
+ if (v->type == kObjectTypeBoolean) {
+ *linematch = v->data.boolean ? INT64_MAX : 0;
+ } else if (v->type == kObjectTypeInteger) {
+ *linematch = v->data.integer;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "linematch must be a boolean or integer");
goto exit_1;
}
} else {
@@ -330,7 +332,7 @@ int nlua_xdl_diff(lua_State *lstate)
xdemitconf_t cfg;
xpparam_t params;
xdemitcb_t ecb;
- bool linematch = false;
+ int64_t linematch = 0;
CLEAR_FIELD(cfg);
CLEAR_FIELD(params);
@@ -362,18 +364,18 @@ int nlua_xdl_diff(lua_State *lstate)
cfg.hunk_func = call_on_hunk_cb;
priv = (hunkpriv_t) {
.lstate = lstate,
- .err = &err,
+ .err = &err,
};
ecb.priv = &priv;
break;
case kNluaXdiffModeLocations:
cfg.hunk_func = hunk_locations_cb;
priv = (hunkpriv_t) {
- .lstate = lstate,
- .ma = &ma,
- .mb = &mb,
+ .lstate = lstate,
+ .ma = &ma,
+ .mb = &mb,
.linematch = linematch,
- .iwhite = (params.flags & XDF_IGNORE_WHITESPACE) > 0
+ .iwhite = (params.flags & XDF_IGNORE_WHITESPACE) > 0
};
ecb.priv = &priv;
lua_createtable(lstate, 0, 0);
diff --git a/src/nvim/lua/xdiff.h b/src/nvim/lua/xdiff.h
index b172d2f922..2ea74a79e8 100644
--- a/src/nvim/lua/xdiff.h
+++ b/src/nvim/lua/xdiff.h
@@ -1,12 +1,7 @@
-#ifndef NVIM_LUA_XDIFF_H
-#define NVIM_LUA_XDIFF_H
+#pragma once
-#include <lauxlib.h>
-#include <lua.h>
-#include <lualib.h>
+#include <lua.h> // IWYU pragma: keep
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/xdiff.h.generated.h"
#endif
-
-#endif // NVIM_LUA_XDIFF_H