diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-19 22:57:13 +0000 |
| commit | 9be89f131f87608f224f0ee06d199fcd09d32176 (patch) | |
| tree | 11022dcfa9e08cb4ac5581b16734196128688d48 /src/nvim/lua | |
| parent | ff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff) | |
| parent | 88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff) | |
| download | rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2 rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip | |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'src/nvim/lua')
| -rw-r--r-- | src/nvim/lua/api_wrappers.c | 1 | ||||
| -rw-r--r-- | src/nvim/lua/converter.c | 179 | ||||
| -rw-r--r-- | src/nvim/lua/executor.c | 71 | ||||
| -rw-r--r-- | src/nvim/lua/secure.c | 5 | ||||
| -rw-r--r-- | src/nvim/lua/spell.c | 1 | ||||
| -rw-r--r-- | src/nvim/lua/stdlib.c | 100 | ||||
| -rw-r--r-- | src/nvim/lua/treesitter.c | 234 | ||||
| -rw-r--r-- | src/nvim/lua/xdiff.c | 15 |
8 files changed, 403 insertions, 203 deletions
diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c index 2b7b0c6471..36847d1fc9 100644 --- a/src/nvim/lua/api_wrappers.c +++ b/src/nvim/lua/api_wrappers.c @@ -5,6 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/func_attr.h" diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index 38ccb03cfc..45ead154bc 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -26,13 +26,13 @@ #include "nvim/types_defs.h" #include "nvim/vim_defs.h" -/// Determine, which keys lua table contains +/// Determine, which keys Lua table contains typedef struct { size_t maxidx; ///< Maximum positive integral value found. size_t string_keys_num; ///< Number of string keys. bool has_string_with_nul; ///< True if there is string key with NUL byte. ObjectType type; ///< If has_type_key is true then attached value. Otherwise - ///< either kObjectTypeNil, kObjectTypeDictionary or + ///< either kObjectTypeNil, kObjectTypeDict or ///< kObjectTypeArray, depending on other properties. lua_Number val; ///< If has_val_key and val_type == LUA_TNUMBER: value. bool has_type_key; ///< True if type key is present. @@ -52,7 +52,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { size_t tsize = 0; // Total number of keys. - int val_type = 0; // If has_val_key: lua type of the value. + int val_type = 0; // If has_val_key: Lua type of the value. bool has_val_key = false; // True if val key was found, // @see nlua_push_val_idx(). size_t other_keys_num = 0; // Number of keys that are not string, integral @@ -96,7 +96,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) lua_Number n = lua_tonumber(lstate, -1); if (n == (lua_Number)kObjectTypeFloat || n == (lua_Number)kObjectTypeArray - || n == (lua_Number)kObjectTypeDictionary) { + || n == (lua_Number)kObjectTypeDict) { ret.has_type_key = true; ret.type = (ObjectType)n; } else { @@ -122,6 +122,7 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) lua_pop(lstate, 1); } if (ret.has_type_key) { + assert(tsize > 0); if (ret.type == kObjectTypeFloat && (!has_val_key || val_type != LUA_TNUMBER)) { ret.type = kObjectTypeNil; @@ -156,12 +157,12 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate) if (tsize == 0 && lua_getmetatable(lstate, -1)) { nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); if (lua_rawequal(lstate, -2, -1)) { - ret.type = kObjectTypeDictionary; + ret.type = kObjectTypeDict; } lua_pop(lstate, 2); } } else if (ret.string_keys_num == tsize) { - ret.type = kObjectTypeDictionary; + ret.type = kObjectTypeDict; } else { ret.type = kObjectTypeNil; } @@ -174,14 +175,14 @@ typedef struct { typval_T *tv; ///< Location where conversion result is saved. size_t list_len; ///< Maximum length when tv is a list. bool container; ///< True if tv is a container. - bool special; ///< If true then tv is a _VAL part of special dictionary + bool special; ///< If true then tv is a _VAL part of special dict. ///< that represents mapping. int idx; ///< Container index (used to detect self-referencing structures). } TVPopStackItem; -/// Convert lua object to Vimscript typval_T +/// Convert Lua object to Vimscript typval_T /// -/// Should pop exactly one value from lua stack. +/// Should pop exactly one value from Lua stack. /// /// @param lstate Lua state. /// @param[out] ret_tv Where to put the result. @@ -219,12 +220,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) if (cur.special) { list_T *const kv_pair = tv_list_alloc(2); - typval_T s_tv = decode_string(s, len, kTrue, false, false); - if (s_tv.v_type == VAR_UNKNOWN) { - ret = false; - tv_list_unref(kv_pair); - continue; - } + typval_T s_tv = decode_string(s, len, true, false); tv_list_append_owned_tv(kv_pair, s_tv); // Value: not populated yet, need to create list item to push. @@ -280,10 +276,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) case LUA_TSTRING: { size_t len; const char *s = lua_tolstring(lstate, -1, &len); - *cur.tv = decode_string(s, len, kNone, true, false); - if (cur.tv->v_type == VAR_UNKNOWN) { - ret = false; - } + *cur.tv = decode_string(s, len, false, false); break; } case LUA_TNUMBER: { @@ -330,7 +323,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) kvi_push(stack, cur); } break; - case kObjectTypeDictionary: + case kObjectTypeDict: if (table_props.string_keys_num == 0) { cur.tv->v_type = VAR_DICT; cur.tv->vval.v_dict = tv_dict_alloc(); @@ -365,7 +358,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv) cur.tv->vval.v_float = (float_T)table_props.val; break; case kObjectTypeNil: - emsg(_("E5100: Cannot convert given lua table: table should " + emsg(_("E5100: Cannot convert given Lua table: table should " "contain either only integer keys or only string keys")); ret = false; break; @@ -393,13 +386,13 @@ nlua_pop_typval_table_processing_end: cur.tv->v_type = VAR_SPECIAL; cur.tv->vval.v_special = kSpecialVarNull; } else { - emsg(_("E5101: Cannot convert given lua type")); + emsg(_("E5101: Cannot convert given Lua type")); ret = false; } break; } default: - emsg(_("E5101: Cannot convert given lua type")); + emsg(_("E5101: Cannot convert given Lua type")); ret = false; break; } @@ -425,6 +418,8 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_ALLOW_SPECIALS true +#define TYPVAL_ENCODE_CHECK_BEFORE + #define TYPVAL_ENCODE_CONV_NIL(tv) \ do { \ if (typval_conv_special) { \ @@ -480,7 +475,7 @@ static bool typval_conv_special = false; #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ do { \ if (typval_conv_special) { \ - nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \ + nlua_create_typed_table(lstate, 0, 0, kObjectTypeDict); \ } else { \ lua_createtable(lstate, 0, 0); \ nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); \ @@ -574,6 +569,7 @@ static bool typval_conv_special = false; #undef TYPVAL_ENCODE_CONV_LIST_START #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START #undef TYPVAL_ENCODE_CONV_EMPTY_DICT +#undef TYPVAL_ENCODE_CHECK_BEFORE #undef TYPVAL_ENCODE_CONV_NIL #undef TYPVAL_ENCODE_CONV_BOOL #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER @@ -588,10 +584,9 @@ static bool typval_conv_special = false; #undef TYPVAL_ENCODE_CONV_RECURSE #undef TYPVAL_ENCODE_ALLOW_SPECIALS -/// Convert Vimscript 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. +/// Should leave single value in Lua stack. May only fail if Lua failed to grow stack. /// /// @param lstate Lua interpreter state. /// @param[in] tv typval_T to convert. @@ -659,7 +654,7 @@ static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, lua_rawset(lstate, -3); } -/// Convert given String to lua string +/// Convert given String to Lua string /// /// Leaves converted string on top of the stack. void nlua_push_String(lua_State *lstate, const String s, int flags) @@ -668,7 +663,7 @@ void nlua_push_String(lua_State *lstate, const String s, int flags) lua_pushlstring(lstate, s.data, s.size); } -/// Convert given Integer to lua number +/// Convert given Integer to Lua number /// /// Leaves converted number on top of the stack. void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) @@ -677,7 +672,7 @@ void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) lua_pushnumber(lstate, (lua_Number)n); } -/// Convert given Float to lua table +/// Convert given Float to Lua table /// /// Leaves converted table on top of the stack. void nlua_push_Float(lua_State *lstate, const Float f, int flags) @@ -693,7 +688,7 @@ void nlua_push_Float(lua_State *lstate, const Float f, int flags) } } -/// Convert given Float to lua boolean +/// Convert given Float to Lua boolean /// /// Leaves converted value on top of the stack. void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) @@ -702,20 +697,16 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) lua_pushboolean(lstate, b); } -/// Convert given Dictionary to lua table +/// Convert given Dict to Lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, int flags) +void nlua_push_Dict(lua_State *lstate, const Dict dict, int flags) FUNC_ATTR_NONNULL_ALL { - if (dict.size == 0 && (flags & kNluaPushSpecial)) { - nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); - } else { - lua_createtable(lstate, 0, (int)dict.size); - if (dict.size == 0 && !(flags & kNluaPushSpecial)) { - nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); - lua_setmetatable(lstate, -2); - } + lua_createtable(lstate, 0, (int)dict.size); + if (dict.size == 0) { + nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); + lua_setmetatable(lstate, -2); } for (size_t i = 0; i < dict.size; i++) { nlua_push_String(lstate, dict.items[i].key, flags); @@ -724,7 +715,7 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, int flags) } } -/// Convert given Array to lua table +/// Convert given Array to Lua table /// /// Leaves converted table on top of the stack. void nlua_push_Array(lua_State *lstate, const Array array, int flags) @@ -750,7 +741,7 @@ GENERATE_INDEX_FUNCTION(Tabpage) #undef GENERATE_INDEX_FUNCTION -/// Convert given Object to lua value +/// Convert given Object to Lua value /// /// Leaves converted value on top of the stack. void nlua_push_Object(lua_State *lstate, Object *obj, int flags) @@ -777,12 +768,12 @@ void nlua_push_Object(lua_State *lstate, Object *obj, int flags) nlua_push_##type(lstate, obj->data.data_key, flags); \ break; \ } - ADD_TYPE(Boolean, boolean) - ADD_TYPE(Integer, integer) - ADD_TYPE(Float, floating) - ADD_TYPE(String, string) - ADD_TYPE(Array, array) - ADD_TYPE(Dictionary, dictionary) + ADD_TYPE(Boolean, boolean) + ADD_TYPE(Integer, integer) + ADD_TYPE(Float, floating) + ADD_TYPE(String, string) + ADD_TYPE(Array, array) + ADD_TYPE(Dict, dict) #undef ADD_TYPE #define ADD_REMOTE_TYPE(type) \ case kObjectType##type: { \ @@ -796,7 +787,7 @@ void nlua_push_Object(lua_State *lstate, Object *obj, int flags) } } -/// Convert lua value to string +/// Convert Lua value to string /// /// Always pops one value from the stack. String nlua_pop_String(lua_State *lstate, Arena *arena, Error *err) @@ -811,16 +802,16 @@ String nlua_pop_String(lua_State *lstate, Arena *arena, Error *err) ret.data = (char *)lua_tolstring(lstate, -1, &(ret.size)); assert(ret.data != NULL); - // TODO(bfredl): it would be "nice" to just use the memory of the lua string + // TODO(bfredl): it would be "nice" to just use the memory of the Lua string // directly, although ensuring the lifetime of such strings is a bit tricky - // (an API call could invoke nested lua, which triggers GC, and kaboom?) + // (an API call could invoke nested Lua, which triggers GC, and kaboom?) ret.data = arena_memdupz(arena, ret.data, ret.size); lua_pop(lstate, 1); return ret; } -/// Convert lua value to integer +/// Convert Lua value to integer /// /// Always pops one value from the stack. Integer nlua_pop_Integer(lua_State *lstate, Arena *arena, Error *err) @@ -841,10 +832,10 @@ Integer nlua_pop_Integer(lua_State *lstate, Arena *arena, Error *err) return (Integer)n; } -/// Convert lua value to boolean +/// 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 +/// 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, Arena *arena, Error *err) @@ -855,7 +846,7 @@ Boolean nlua_pop_Boolean(lua_State *lstate, Arena *arena, Error *err) return ret; } -/// Convert lua value to boolean +/// Convert Lua value to boolean /// /// This follows API conventions for a Boolean value, compare api_object_to_bool /// @@ -905,9 +896,9 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons } LuaTableProps table_props = nlua_traverse_table(lstate); - if (type == kObjectTypeDictionary && table_props.type == kObjectTypeArray + if (type == kObjectTypeDict && table_props.type == kObjectTypeArray && table_props.maxidx == 0 && !table_props.has_type_key) { - table_props.type = kObjectTypeDictionary; + table_props.type = kObjectTypeDict; } if (table_props.type != type) { @@ -919,7 +910,7 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons return table_props; } -/// Convert lua table to float +/// Convert Lua table to float /// /// Always pops one value from the stack. Float nlua_pop_Float(lua_State *lstate, Arena *arena, Error *err) @@ -940,7 +931,7 @@ Float nlua_pop_Float(lua_State *lstate, Arena *arena, Error *err) return (Float)table_props.val; } -/// Convert lua table to array without determining whether it is array +/// Convert Lua table to array without determining whether it is array /// /// @param lstate Lua state. /// @param[in] table_props nlua_traverse_table() output. @@ -975,7 +966,7 @@ static Array nlua_pop_Array_unchecked(lua_State *const lstate, const LuaTablePro return ret; } -/// Convert lua table to array +/// Convert Lua table to array /// /// Always pops one value from the stack. Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) @@ -988,7 +979,7 @@ Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) return nlua_pop_Array_unchecked(lstate, table_props, arena, err); } -/// Convert lua table to dictionary +/// Convert Lua table to dictionary /// /// Always pops one value from the stack. Does not check whether whether topmost /// value on the stack is a table. @@ -996,11 +987,11 @@ Array nlua_pop_Array(lua_State *lstate, Arena *arena, Error *err) /// @param lstate Lua interpreter state. /// @param[in] table_props nlua_traverse_table() output. /// @param[out] err Location where error will be saved. -static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTableProps table_props, - bool ref, Arena *arena, Error *err) +static Dict nlua_pop_Dict_unchecked(lua_State *lstate, const LuaTableProps table_props, bool ref, + Arena *arena, Error *err) FUNC_ATTR_NONNULL_ARG(1, 5) FUNC_ATTR_WARN_UNUSED_RESULT { - Dictionary ret = arena_dict(arena, table_props.string_keys_num); + Dict ret = arena_dict(arena, table_props.string_keys_num); if (table_props.string_keys_num == 0) { lua_pop(lstate, 1); @@ -1029,11 +1020,11 @@ static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTabl if (ERROR_SET(err)) { if (!arena) { - api_free_dictionary(ret); + api_free_dict(ret); } lua_pop(lstate, 2); // stack: - return (Dictionary) { .size = 0, .items = NULL }; + return (Dict) { .size = 0, .items = NULL }; } i++; } else { @@ -1046,20 +1037,20 @@ static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTabl return ret; } -/// Convert lua table to dictionary +/// Convert Lua table to dictionary /// /// Always pops one value from the stack. -Dictionary nlua_pop_Dictionary(lua_State *lstate, bool ref, Arena *arena, Error *err) +Dict nlua_pop_Dict(lua_State *lstate, bool ref, Arena *arena, Error *err) FUNC_ATTR_NONNULL_ARG(1, 4) FUNC_ATTR_WARN_UNUSED_RESULT { const LuaTableProps table_props = nlua_check_type(lstate, err, - kObjectTypeDictionary); - if (table_props.type != kObjectTypeDictionary) { + kObjectTypeDict); + if (table_props.type != kObjectTypeDict) { lua_pop(lstate, 1); - return (Dictionary) { .size = 0, .items = NULL }; + return (Dict) { .size = 0, .items = NULL }; } - return nlua_pop_Dictionary_unchecked(lstate, table_props, ref, arena, err); + return nlua_pop_Dict_unchecked(lstate, table_props, ref, arena, err); } /// Helper structure for nlua_pop_Object @@ -1068,7 +1059,7 @@ typedef struct { bool container; ///< True if tv is a container. } ObjPopStackItem; -/// Convert lua table to object +/// Convert Lua table to object /// /// Always pops one value from the stack. Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *const err) @@ -1086,9 +1077,9 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c api_set_error(err, kErrorTypeException, "Lua failed to grow stack"); break; } - if (cur.obj->type == kObjectTypeDictionary) { + if (cur.obj->type == kObjectTypeDict) { // stack: …, dict, key - if (cur.obj->data.dictionary.size == cur.obj->data.dictionary.capacity) { + if (cur.obj->data.dict.size == cur.obj->data.dict.capacity) { lua_pop(lstate, 2); continue; } @@ -1106,10 +1097,10 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c // stack: …, dict, new key, val size_t len; const char *s = lua_tolstring(lstate, -2, &len); - const size_t idx = cur.obj->data.dictionary.size++; - cur.obj->data.dictionary.items[idx].key = CBUF_TO_ARENA_STR(arena, s, len); + const size_t idx = cur.obj->data.dict.size++; + cur.obj->data.dict.items[idx].key = CBUF_TO_ARENA_STR(arena, s, len); kvi_push(stack, cur); - cur = (ObjPopStackItem){ .obj = &cur.obj->data.dictionary.items[idx].value }; + cur = (ObjPopStackItem){ .obj = &cur.obj->data.dict.items[idx].value }; } else { // stack: …, dict lua_pop(lstate, 1); @@ -1160,14 +1151,16 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c if (table_props.maxidx != 0) { cur.obj->data.array = arena_array(arena, table_props.maxidx); cur.container = true; + assert(kv_size(stack) < SIZE_MAX); kvi_push(stack, cur); } break; - case kObjectTypeDictionary: - *cur.obj = DICTIONARY_OBJ(((Dictionary)ARRAY_DICT_INIT)); + case kObjectTypeDict: + *cur.obj = DICT_OBJ(((Dict)ARRAY_DICT_INIT)); if (table_props.string_keys_num != 0) { - cur.obj->data.dictionary = arena_dict(arena, table_props.string_keys_num); + cur.obj->data.dict = arena_dict(arena, table_props.string_keys_num); cur.container = true; + assert(kv_size(stack) < SIZE_MAX); kvi_push(stack, cur); lua_pushnil(lstate); } @@ -1200,16 +1193,14 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Arena *arena, Error *c if (is_nil) { *cur.obj = NIL; } else { - api_set_error(err, kErrorTypeValidation, - "Cannot convert userdata"); + api_set_error(err, kErrorTypeValidation, "Cannot convert userdata"); } break; } default: type_error: - api_set_error(err, kErrorTypeValidation, - "Cannot convert given lua type"); + api_set_error(err, kErrorTypeValidation, "Cannot convert given Lua type"); break; } if (!cur.container) { @@ -1287,16 +1278,16 @@ void nlua_init_types(lua_State *const lstate) lua_rawset(lstate, -3); LUA_PUSH_STATIC_STRING(lstate, "dictionary"); - lua_pushnumber(lstate, (lua_Number)kObjectTypeDictionary); + lua_pushnumber(lstate, (lua_Number)kObjectTypeDict); lua_rawset(lstate, -3); - lua_pushnumber(lstate, (lua_Number)kObjectTypeDictionary); + lua_pushnumber(lstate, (lua_Number)kObjectTypeDict); LUA_PUSH_STATIC_STRING(lstate, "dictionary"); lua_rawset(lstate, -3); lua_rawset(lstate, -3); } -// lua specific variant of api_dict_to_keydict +// Lua specific variant of api_dict_to_keydict void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_opt, Arena *arena, Error *err) { @@ -1346,8 +1337,8 @@ void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, char **err_ *(handle_T *)mem = nlua_pop_handle(L, arena, err); } else if (field->type == kObjectTypeArray) { *(Array *)mem = nlua_pop_Array(L, arena, err); - } else if (field->type == kObjectTypeDictionary) { - *(Dictionary *)mem = nlua_pop_Dictionary(L, false, arena, err); + } else if (field->type == kObjectTypeDict) { + *(Dict *)mem = nlua_pop_Dict(L, false, arena, err); } else if (field->type == kObjectTypeLuaRef) { *(LuaRef *)mem = nlua_pop_LuaRef(L, arena, err); } else { @@ -1396,8 +1387,8 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) nlua_push_String(L, *(String *)mem, 0); } else if (field->type == kObjectTypeArray) { nlua_push_Array(L, *(Array *)mem, 0); - } else if (field->type == kObjectTypeDictionary) { - nlua_push_Dictionary(L, *(Dictionary *)mem, 0); + } else if (field->type == kObjectTypeDict) { + nlua_push_Dict(L, *(Dict *)mem, 0); } else if (field->type == kObjectTypeLuaRef) { nlua_pushref(L, *(LuaRef *)mem); } else { diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index a76b8213e5..d4940f3add 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -22,6 +22,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" @@ -923,6 +924,7 @@ void nlua_free_all_mem(void) lua_State *lstate = global_lstate; nlua_unref_global(lstate, require_ref); nlua_common_free_all_mem(lstate); + tslua_free(); } static void nlua_common_free_all_mem(lua_State *lstate) @@ -1901,8 +1903,13 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, tslua_push_querycursor); lua_setfield(lstate, -2, "_create_ts_querycursor"); - lua_pushcfunction(lstate, tslua_add_language); - lua_setfield(lstate, -2, "_ts_add_language"); + lua_pushcfunction(lstate, tslua_add_language_from_object); + lua_setfield(lstate, -2, "_ts_add_language_from_object"); + +#ifdef HAVE_WASMTIME + lua_pushcfunction(lstate, tslua_add_language_from_wasm); + lua_setfield(lstate, -2, "_ts_add_language_from_wasm"); +#endif lua_pushcfunction(lstate, tslua_has_language); lua_setfield(lstate, -2, "_ts_has_language"); @@ -1923,10 +1930,14 @@ 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 *pat, int *num_results, char ***results) +static garray_T expand_result_array = GA_EMPTY_INIT_VALUE; + +/// Finds matches for Lua cmdline completion and advances xp->xp_pattern after prefix. +/// This should be called before xp->xp_pattern is first used. +void nlua_expand_pat(expand_T *xp) { lua_State *const lstate = global_lstate; - int ret = OK; + int status = FAIL; // [ vim ] lua_getglobal(lstate, "vim"); @@ -1935,60 +1946,59 @@ int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results) lua_getfield(lstate, -1, "_expand_pat"); luaL_checktype(lstate, -1, LUA_TFUNCTION); - // [ vim, vim._expand_pat, buf ] - lua_pushlstring(lstate, pat, strlen(pat)); + // [ vim, vim._expand_pat, pat ] + const char *pat = xp->xp_pattern; + assert(xp->xp_line + xp->xp_col >= pat); + ptrdiff_t patlen = xp->xp_line + xp->xp_col - pat; + lua_pushlstring(lstate, pat, (size_t)patlen); if (nlua_pcall(lstate, 1, 2) != 0) { - nlua_error(lstate, - _("Error executing vim._expand_pat: %.*s")); - return FAIL; + nlua_error(lstate, _("Error executing vim._expand_pat: %.*s")); + return; } Error err = ERROR_INIT; - *num_results = 0; - *results = NULL; - Arena arena = ARENA_EMPTY; - int prefix_len = (int)nlua_pop_Integer(lstate, &arena, &err); - if (ERROR_SET(&err)) { - ret = FAIL; + ptrdiff_t prefix_len = nlua_pop_Integer(lstate, &arena, &err); + if (ERROR_SET(&err) || prefix_len > patlen) { goto cleanup; } Array completions = nlua_pop_Array(lstate, &arena, &err); if (ERROR_SET(&err)) { - ret = FAIL; goto cleanup_array; } - garray_T result_array; - ga_init(&result_array, (int)sizeof(char *), 80); + ga_clear(&expand_result_array); + ga_init(&expand_result_array, (int)sizeof(char *), 80); + for (size_t i = 0; i < completions.size; i++) { Object v = completions.items[i]; - if (v.type != kObjectTypeString) { - ret = FAIL; goto cleanup_array; } - - GA_APPEND(char *, &result_array, string_to_cstr(v.data.string)); + GA_APPEND(char *, &expand_result_array, string_to_cstr(v.data.string)); } xp->xp_pattern += prefix_len; - *results = result_array.ga_data; - *num_results = result_array.ga_len; + status = OK; cleanup_array: arena_mem_free(arena_finish(&arena)); cleanup: - - if (ret == FAIL) { - ga_clear(&result_array); + if (status == FAIL) { + ga_clear(&expand_result_array); } +} - return ret; +int nlua_expand_get_matches(int *num_results, char ***results) +{ + *results = expand_result_array.ga_data; + *num_results = expand_result_array.ga_len; + expand_result_array = (garray_T)GA_EMPTY_INIT_VALUE; + return *num_results > 0; } static int nlua_is_thread(lua_State *lstate) @@ -2053,10 +2063,11 @@ char *nlua_register_table_as_callable(const typval_T *const arg) return name; } -void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len) +void nlua_execute_on_key(int c, char *typed_buf) { char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); + vim_unescape_ks(typed_buf); lua_State *const lstate = global_lstate; @@ -2075,7 +2086,7 @@ void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len) lua_pushlstring(lstate, buf, buf_len); // [ vim, vim._on_key, buf, typed_buf ] - lua_pushlstring(lstate, typed_buf, typed_len); + lua_pushstring(lstate, typed_buf); int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c index f62e0ace04..61277949c4 100644 --- a/src/nvim/lua/secure.c +++ b/src/nvim/lua/secure.c @@ -3,6 +3,7 @@ #include <string.h> #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -103,12 +104,12 @@ void ex_trust(exarg_T *eap) action = "deny"; } else if (strcmp(arg1, "++remove") == 0) { action = "remove"; - } else if (*arg1 != '\0') { + } else if (*arg1 != NUL) { semsg(e_invarg2, arg1); goto theend; } - if (path[0] == '\0') { + if (path[0] == NUL) { path = NULL; } diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index ba83239dc5..f4dacd7a55 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -7,6 +7,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/highlight_defs.h" diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 22ee0a1c98..ee0eabbebb 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -17,10 +17,13 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" +#include "nvim/eval/window.h" +#include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/fold.h" #include "nvim/globals.h" @@ -40,6 +43,7 @@ #include "nvim/runtime.h" #include "nvim/strings.h" #include "nvim/types_defs.h" +#include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/stdlib.c.generated.h" @@ -568,6 +572,99 @@ static int nlua_foldupdate(lua_State *lstate) return 0; } +static int nlua_with(lua_State *L) +{ + int flags = 0; + buf_T *buf = NULL; + win_T *win = NULL; + +#define APPLY_FLAG(key, flag) \ + if (strequal((key), k) && (v)) { \ + flags |= (flag); \ + } + + luaL_argcheck(L, lua_istable(L, 1), 1, "table expected"); + lua_pushnil(L); // [dict, ..., nil] + while (lua_next(L, 1)) { + // [dict, ..., key, value] + if (lua_type(L, -2) == LUA_TSTRING) { + const char *k = lua_tostring(L, -2); + bool v = lua_toboolean(L, -1); + if (strequal("buf", k)) { \ + buf = handle_get_buffer((int)luaL_checkinteger(L, -1)); + } else if (strequal("win", k)) { \ + win = handle_get_window((int)luaL_checkinteger(L, -1)); + } else { + APPLY_FLAG("sandbox", CMOD_SANDBOX); + APPLY_FLAG("silent", CMOD_SILENT); + APPLY_FLAG("emsg_silent", CMOD_ERRSILENT); + APPLY_FLAG("unsilent", CMOD_UNSILENT); + APPLY_FLAG("noautocmd", CMOD_NOAUTOCMD); + APPLY_FLAG("hide", CMOD_HIDE); + APPLY_FLAG("keepalt", CMOD_KEEPALT); + APPLY_FLAG("keepmarks", CMOD_KEEPMARKS); + APPLY_FLAG("keepjumps", CMOD_KEEPJUMPS); + APPLY_FLAG("lockmarks", CMOD_LOCKMARKS); + APPLY_FLAG("keeppatterns", CMOD_KEEPPATTERNS); + } + } + // pop the value; lua_next will pop the key. + lua_pop(L, 1); // [dict, ..., key] + } + int status = 0; + int rets = 0; + + cmdmod_T save_cmdmod = cmdmod; + cmdmod.cmod_flags = flags; + apply_cmdmod(&cmdmod); + + if (buf || win) { + try_start(); + } + + aco_save_T aco; + win_execute_T win_execute_args; + Error err = ERROR_INIT; + + if (win) { + tabpage_T *tabpage = win_find_tabpage(win); + if (!win_execute_before(&win_execute_args, win, tabpage)) { + goto end; + } + } else if (buf) { + aucmd_prepbuf(&aco, buf); + } + + int s = lua_gettop(L); + lua_pushvalue(L, 2); + status = lua_pcall(L, 0, LUA_MULTRET, 0); + rets = lua_gettop(L) - s; + + if (win) { + win_execute_after(&win_execute_args); + } else if (buf) { + aucmd_restbuf(&aco); + } + +end: + if (buf || win) { + try_end(&err); + } + + undo_cmdmod(&cmdmod); + cmdmod = save_cmdmod; + + if (status) { + return lua_error(L); + } else if (ERROR_SET(&err)) { + nlua_push_errstr(L, "%s", err.msg); + api_clear_error(&err); + return lua_error(L); + } + + return rets; +} + // Access to internal functions. For use in runtime/ static void nlua_state_add_internal(lua_State *const lstate) { @@ -582,6 +679,9 @@ static void nlua_state_add_internal(lua_State *const lstate) // _updatefolds lua_pushcfunction(lstate, &nlua_foldupdate); lua_setfield(lstate, -2, "_foldupdate"); + + lua_pushcfunction(lstate, &nlua_with); + lua_setfield(lstate, -2, "_with_c"); } void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index e87cf756a8..ab97704dfe 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -15,6 +15,10 @@ #include <tree_sitter/api.h> #include <uv.h> +#ifdef HAVE_WASMTIME +# include <wasm.h> +#endif + #include "klib/kvec.h" #include "nvim/api/private/helpers.h" #include "nvim/buffer_defs.h" @@ -24,6 +28,7 @@ #include "nvim/map_defs.h" #include "nvim/memline.h" #include "nvim/memory.h" +#include "nvim/os/fs.h" #include "nvim/pos_defs.h" #include "nvim/strings.h" #include "nvim/types_defs.h" @@ -34,7 +39,6 @@ #define TS_META_QUERY "treesitter_query" #define TS_META_QUERYCURSOR "treesitter_querycursor" #define TS_META_QUERYMATCH "treesitter_querymatch" -#define TS_META_TREECURSOR "treesitter_treecursor" typedef struct { LuaRef cb; @@ -53,6 +57,11 @@ typedef struct { static PMap(cstr_t) langs = MAP_INIT; +#ifdef HAVE_WASMTIME +static wasm_engine_t *wasmengine; +static TSWasmStore *ts_wasmstore; +#endif + // TSLanguage int tslua_has_language(lua_State *L) @@ -62,8 +71,59 @@ int tslua_has_language(lua_State *L) return 1; } -static TSLanguage *load_language(lua_State *L, const char *path, const char *lang_name, - const char *symbol) +#ifdef HAVE_WASMTIME +static char *read_file(const char *path, size_t *len) + FUNC_ATTR_MALLOC +{ + FILE *file = os_fopen(path, "r"); + if (file == NULL) { + return NULL; + } + fseek(file, 0L, SEEK_END); + *len = (size_t)ftell(file); + fseek(file, 0L, SEEK_SET); + char *data = xmalloc(*len); + if (fread(data, *len, 1, file) != 1) { + xfree(data); + fclose(file); + return NULL; + } + fclose(file); + return data; +} + +static const char *wasmerr_to_str(TSWasmErrorKind werr) +{ + switch (werr) { + case TSWasmErrorKindParse: + return "PARSE"; + case TSWasmErrorKindCompile: + return "COMPILE"; + case TSWasmErrorKindInstantiate: + return "INSTANTIATE"; + case TSWasmErrorKindAllocate: + return "ALLOCATE"; + default: + return "UNKNOWN"; + } +} +#endif + +int tslua_add_language_from_wasm(lua_State *L) +{ + return add_language(L, true); +} + +// Creates the language into the internal language map. +// +// Returns true if the language is correctly loaded in the language map +int tslua_add_language_from_object(lua_State *L) +{ + return add_language(L, false); +} + +static const TSLanguage *load_language_from_object(lua_State *L, const char *path, + const char *lang_name, const char *symbol) { uv_lib_t lib; if (uv_dlopen(path, &lib)) { @@ -91,16 +151,59 @@ static TSLanguage *load_language(lua_State *L, const char *path, const char *lan return lang; } -// Creates the language into the internal language map. -// -// Returns true if the language is correctly loaded in the language map -int tslua_add_language(lua_State *L) +static const TSLanguage *load_language_from_wasm(lua_State *L, const char *path, + const char *lang_name) +{ +#ifndef HAVE_WASMTIME + luaL_error(L, "Not supported"); + return NULL; +#else + if (wasmengine == NULL) { + wasmengine = wasm_engine_new(); + } + assert(wasmengine != NULL); + + TSWasmError werr = { 0 }; + if (ts_wasmstore == NULL) { + ts_wasmstore = ts_wasm_store_new(wasmengine, &werr); + } + + if (werr.kind > 0) { + luaL_error(L, "Error creating wasm store: (%s) %s", wasmerr_to_str(werr.kind), werr.message); + } + + size_t file_size = 0; + char *data = read_file(path, &file_size); + + if (data == NULL) { + luaL_error(L, "Unable to read file", path); + } + + const TSLanguage *lang = ts_wasm_store_load_language(ts_wasmstore, lang_name, data, + (uint32_t)file_size, &werr); + + xfree(data); + + if (werr.kind > 0) { + luaL_error(L, "Failed to load WASM parser %s: (%s) %s", path, wasmerr_to_str(werr.kind), + werr.message); + } + + if (lang == NULL) { + luaL_error(L, "Failed to load parser %s: internal error", path); + } + + return lang; +#endif +} + +static int add_language(lua_State *L, bool is_wasm) { const char *path = luaL_checkstring(L, 1); const char *lang_name = luaL_checkstring(L, 2); const char *symbol_name = lang_name; - if (lua_gettop(L) >= 3 && !lua_isnil(L, 3)) { + if (!is_wasm && lua_gettop(L) >= 3 && !lua_isnil(L, 3)) { symbol_name = luaL_checkstring(L, 3); } @@ -109,7 +212,9 @@ int tslua_add_language(lua_State *L) return 1; } - TSLanguage *lang = load_language(L, path, lang_name, symbol_name); + const TSLanguage *lang = is_wasm + ? load_language_from_wasm(L, path, lang_name) + : load_language_from_object(L, path, lang_name, symbol_name); uint32_t lang_version = ts_language_version(lang); if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION @@ -121,7 +226,7 @@ int tslua_add_language(lua_State *L) TREE_SITTER_LANGUAGE_VERSION, lang_version); } - pmap_put(cstr_t)(&langs, xstrdup(lang_name), lang); + pmap_put(cstr_t)(&langs, xstrdup(lang_name), (TSLanguage *)lang); lua_pushboolean(L, true); return 1; @@ -186,6 +291,9 @@ int tslua_inspect_lang(lua_State *L) lua_setfield(L, -2, "fields"); // [retval] + lua_pushboolean(L, ts_language_is_wasm(lang)); + lua_setfield(L, -2, "_wasm"); + lua_pushinteger(L, ts_language_version(lang)); // [retval, version] lua_setfield(L, -2, "_abi_version"); @@ -215,6 +323,13 @@ int tslua_push_parser(lua_State *L) TSParser **parser = lua_newuserdata(L, sizeof(TSParser *)); *parser = ts_parser_new(); +#ifdef HAVE_WASMTIME + if (ts_language_is_wasm(lang)) { + assert(wasmengine != NULL); + ts_parser_set_wasm_store(*parser, ts_wasmstore); + } +#endif + if (!ts_parser_set_language(*parser, lang)) { ts_parser_delete(*parser); const char *lang_name = luaL_checkstring(L, 1); @@ -279,7 +394,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position memcpy(buf, line + position.column, tocopy); // Translate embedded \n to NUL - memchrsub(buf, '\n', '\0', tocopy); + memchrsub(buf, '\n', NUL, tocopy); *bytes_read = (uint32_t)tocopy; if (tocopy < BUFSIZE) { // now add the final \n. If it didn't fit, input_cb will be called again @@ -686,20 +801,6 @@ static int tree_root(lua_State *L) return 1; } -// TSTreeCursor - -static struct luaL_Reg treecursor_meta[] = { - { "__gc", treecursor_gc }, - { NULL, NULL } -}; - -static int treecursor_gc(lua_State *L) -{ - TSTreeCursor *cursor = luaL_checkudata(L, 1, TS_META_TREECURSOR); - ts_tree_cursor_delete(cursor); - return 0; -} - // TSNode static struct luaL_Reg node_meta[] = { { "__tostring", node_tostring }, @@ -890,23 +991,14 @@ static int node_field(lua_State *L) size_t name_len; const char *field_name = luaL_checklstring(L, 2, &name_len); - TSTreeCursor cursor = ts_tree_cursor_new(node); - lua_newtable(L); // [table] - size_t curr_index = 0; - - if (ts_tree_cursor_goto_first_child(&cursor)) { - do { - const char *current_field = ts_tree_cursor_current_field_name(&cursor); - if (current_field != NULL && !strcmp(field_name, current_field)) { - push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node] - lua_rawseti(L, -2, (int)++curr_index); - } - } while (ts_tree_cursor_goto_next_sibling(&cursor)); + TSNode field = ts_node_child_by_field_name(node, field_name, (uint32_t)name_len); + if (!ts_node_is_null(field)) { + push_node(L, field, 1); // [table, node] + lua_rawseti(L, -2, 1); } - ts_tree_cursor_delete(&cursor); return 1; } @@ -1002,45 +1094,35 @@ static int node_named_descendant_for_range(lua_State *L) static int node_next_child(lua_State *L) { - TSTreeCursor *cursor = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); + uint32_t *child_index = lua_touserdata(L, lua_upvalueindex(1)); TSNode source = node_check(L, lua_upvalueindex(2)); - // First call should return first child - if (ts_node_eq(source, ts_tree_cursor_current_node(cursor))) { - if (ts_tree_cursor_goto_first_child(cursor)) { - goto push; - } else { - return 0; - } - } - - if (!ts_tree_cursor_goto_next_sibling(cursor)) { + if (*child_index >= ts_node_child_count(source)) { return 0; } -push: - push_node(L, ts_tree_cursor_current_node(cursor), lua_upvalueindex(2)); // [node] - - const char *field = ts_tree_cursor_current_field_name(cursor); + TSNode child = ts_node_child(source, *child_index); + push_node(L, child, lua_upvalueindex(2)); + const char *field = ts_node_field_name_for_child(source, *child_index); if (field != NULL) { - lua_pushstring(L, ts_tree_cursor_current_field_name(cursor)); + lua_pushstring(L, field); } else { lua_pushnil(L); } // [node, field_name_or_nil] + + (*child_index)++; + return 2; } static int node_iter_children(lua_State *L) { - TSNode node = node_check(L, 1); - - TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata] - *ud = ts_tree_cursor_new(node); + node_check(L, 1); + uint32_t *child_index = lua_newuserdata(L, sizeof(uint32_t)); // [source_node,..., udata] + *child_index = 0; - lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREECURSOR); // [udata, mt] - lua_setmetatable(L, -2); // [udata] - lua_pushvalue(L, 1); // [udata, source_node] + lua_pushvalue(L, 1); // [source_node, ..., udata, source_node] lua_pushcclosure(L, node_next_child, 2); return 1; @@ -1132,22 +1214,19 @@ static int node_prev_named_sibling(lua_State *L) static int node_named_children(lua_State *L) { TSNode source = node_check(L, 1); - TSTreeCursor cursor = ts_tree_cursor_new(source); lua_newtable(L); int curr_index = 0; - if (ts_tree_cursor_goto_first_child(&cursor)) { - do { - TSNode node = ts_tree_cursor_current_node(&cursor); - if (ts_node_is_named(node)) { - push_node(L, node, 1); - lua_rawseti(L, -2, ++curr_index); - } - } while (ts_tree_cursor_goto_next_sibling(&cursor)); + uint32_t n = ts_node_child_count(source); + for (uint32_t i = 0; i < n; i++) { + TSNode child = ts_node_child(source, i); + if (ts_node_is_named(child)) { + push_node(L, child, 1); + lua_rawseti(L, -2, ++curr_index); + } } - ts_tree_cursor_delete(&cursor); return 1; } @@ -1557,7 +1636,18 @@ void tslua_init(lua_State *L) build_meta(L, TS_META_QUERY, query_meta); build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); build_meta(L, TS_META_QUERYMATCH, querymatch_meta); - build_meta(L, TS_META_TREECURSOR, treecursor_meta); ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); } + +void tslua_free(void) +{ +#ifdef HAVE_WASMTIME + if (wasmengine != NULL) { + wasm_engine_delete(wasmengine); + } + if (ts_wasmstore != NULL) { + ts_wasm_store_delete(ts_wasmstore); + } +#endif +} diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index 035c171a14..b9f96abf73 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -67,11 +67,11 @@ static void get_linematch_results(lua_State *lstate, mmfile_t *ma, mmfile_t *mb, 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] = { count_a, count_b }; + mmfile_t ma0 = fastforward_buf_to_lnum(*ma, (linenr_T)start_a + 1); + mmfile_t mb0 = fastforward_buf_to_lnum(*mb, (linenr_T)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); + const mmfile_t *diff_begin[2] = { &ma0, &mb0 }; + int diff_length[2] = { count_a, count_b }; int *decisions = NULL; size_t decisions_length = linematch_nbuffers(diff_begin, diff_length, 2, &decisions, iwhite); @@ -185,7 +185,12 @@ static mmfile_t get_string_arg(lua_State *lstate, int idx) luaL_argerror(lstate, idx, "expected string"); } mmfile_t mf; - mf.ptr = (char *)lua_tolstring(lstate, idx, (size_t *)&mf.size); + size_t size; + mf.ptr = (char *)lua_tolstring(lstate, idx, &size); + if (size > INT_MAX) { + luaL_argerror(lstate, idx, "string too long"); + } + mf.size = (int)size; return mf; } |