diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 6a1d94d34b..5285f0b1b5 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -893,6 +893,9 @@ vim.empty_dict() *vim.empty_dict()* Note: If numeric keys are present in the table, Nvim ignores the metatable marker and converts the dict to a list/array anyway. + Return: ~ + (`table`) + vim.iconv({str}, {from}, {to}, {opts}) *vim.iconv()* The result is a String, which is the text {str} converted from encoding {from} to encoding {to}. When the conversion fails `nil` is returned. When diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua index 83ef4efb9f..71ac3bcfcd 100644 --- a/runtime/lua/vim/_init_packages.lua +++ b/runtime/lua/vim/_init_packages.lua @@ -86,6 +86,7 @@ setmetatable(vim, { --- ---@private --- TODO: should be in vim.shared when vim.shared always uses nvim-lua +--- @diagnostic disable-next-line:duplicate-set-field function vim.empty_dict() return setmetatable({}, vim._empty_dict_mt) end diff --git a/runtime/lua/vim/_meta/builtin.lua b/runtime/lua/vim/_meta/builtin.lua index dd849e5247..a422a65792 100644 --- a/runtime/lua/vim/_meta/builtin.lua +++ b/runtime/lua/vim/_meta/builtin.lua @@ -83,6 +83,7 @@ function vim.in_fast_event() end --- --- Note: If numeric keys are present in the table, Nvim ignores the metatable --- marker and converts the dict to a list/array anyway. +--- @return table function vim.empty_dict() end --- Sends {event} to {channel} via |RPC| and returns immediately. If {channel} diff --git a/runtime/lua/vim/_meta/misc.lua b/runtime/lua/vim/_meta/misc.lua index 0d70e16314..ab80e18434 100644 --- a/runtime/lua/vim/_meta/misc.lua +++ b/runtime/lua/vim/_meta/misc.lua @@ -10,6 +10,7 @@ --- vim.fn[func]({...}) --- ``` --- ---- @param func fun() +--- @param func string --- @param ... any +--- @return any function vim.call(func, ...) end diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index dd0f7c2e1e..5cf8390843 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -63,6 +63,10 @@ function vim.deepcopy(orig, noref) return deepcopy(orig, not noref and {} or nil) end +--- @class vim.gsplit.Opts +--- @field plain? boolean Use `sep` literally (as in string.find). +--- @field trimempty? boolean Discard empty segments at start and end of the sequence. + --- Gets an |iterator| that splits a string at each instance of a separator, in "lazy" fashion --- (as opposed to |vim.split()| which is "eager"). --- @@ -91,12 +95,12 @@ end --- --- @param s string String to split --- @param sep string Separator or pattern ---- @param opts (table|nil) Keyword arguments |kwargs|: +--- @param opts? vim.gsplit.Opts (table) Keyword arguments |kwargs|: --- - plain: (boolean) Use `sep` literally (as in string.find). --- - trimempty: (boolean) Discard empty segments at start and end of the sequence. ---@return fun():string|nil (function) Iterator over the split components function vim.gsplit(s, sep, opts) - local plain + local plain --- @type boolean? local trimempty = false if type(opts) == 'boolean' then plain = opts -- For backwards compatibility. @@ -113,6 +117,11 @@ function vim.gsplit(s, sep, opts) local segs = {} local empty_start = true -- Only empty segments seen so far. + --- @param i integer? + --- @param j integer + --- @param ... unknown + --- @return string + --- @return ... local function _pass(i, j, ...) if i then assert(j + 1 > start, 'Infinite loop detected') @@ -201,10 +210,11 @@ end ---@param t table (table) Table ---@return T[] (list) List of keys function vim.tbl_keys(t) - assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) + vim.validate({ t = { t, 't' } }) + --- @cast t table local keys = {} - for k, _ in pairs(t) do + for k in pairs(t) do table.insert(keys, k) end return keys @@ -217,10 +227,12 @@ end ---@param t table (table) Table ---@return T[] (list) List of values function vim.tbl_values(t) - assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) + vim.validate({ t = { t, 't' } }) local values = {} - for _, v in pairs(t) do + for _, v in + pairs(t --[[@as table]]) + do table.insert(values, v) end return values @@ -234,8 +246,9 @@ end ---@return table Table of transformed values function vim.tbl_map(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) + --- @cast t table - local rettab = {} + local rettab = {} --- @type table for k, v in pairs(t) do rettab[k] = func(v) end @@ -250,16 +263,20 @@ end ---@return T[] (table) Table of filtered values function vim.tbl_filter(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) + --- @cast t table - local rettab = {} + local rettab = {} --- @type table for _, entry in pairs(t) do if func(entry) then - table.insert(rettab, entry) + rettab[#rettab + 1] = entry end end return rettab end +--- @class vim.tbl_contains.Opts +--- @field predicate? boolean + --- Checks if a table contains a given value, specified either directly or via --- a predicate that is checked for each value. --- @@ -276,13 +293,14 @@ end --- ---@param t table Table to check ---@param value any Value to compare or predicate function reference ----@param opts (table|nil) Keyword arguments |kwargs|: +---@param opts? vim.tbl_contains.Opts (table) Keyword arguments |kwargs|: --- - predicate: (boolean) `value` is a function reference to be checked (default false) ---@return boolean `true` if `t` contains `value` function vim.tbl_contains(t, value, opts) vim.validate({ t = { t, 't' }, opts = { opts, 't', true } }) + --- @cast t table - local pred + local pred --- @type fun(v: any): boolean? if opts and opts.predicate then vim.validate({ value = { value, 'c' } }) pred = value @@ -309,6 +327,7 @@ end ---@return boolean `true` if `t` contains `value` function vim.list_contains(t, value) vim.validate({ t = { t, 't' } }) + --- @cast t table for _, v in ipairs(t) do if v == value then @@ -325,7 +344,7 @@ end ---@param t table Table to check ---@return boolean `true` if `t` is empty function vim.tbl_isempty(t) - assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) + vim.validate({ t = { t, 't' } }) return next(t) == nil end @@ -347,7 +366,7 @@ local function tbl_extend(behavior, deep_extend, ...) ) end - local ret = {} + local ret = {} --- @type table if vim._empty_dict_mt ~= nil and getmetatable(select(1, ...)) == vim._empty_dict_mt then ret = vim.empty_dict() end @@ -355,6 +374,7 @@ local function tbl_extend(behavior, deep_extend, ...) for i = 1, select('#', ...) do local tbl = select(i, ...) vim.validate({ ['after the second argument'] = { tbl, 't' } }) + --- @cast tbl table if tbl then for k, v in pairs(tbl) do if deep_extend and can_merge(v) and can_merge(ret[k]) then @@ -417,12 +437,14 @@ function vim.deep_equal(a, b) return false end if type(a) == 'table' then + --- @cast a table + --- @cast b table for k, v in pairs(a) do if not vim.deep_equal(v, b[k]) then return false end end - for k, _ in pairs(b) do + for k in pairs(b) do if a[k] == nil then return false end @@ -440,6 +462,8 @@ end ---@param o table Table to add the reverse to ---@return table o function vim.tbl_add_reverse_lookup(o) + --- @cast o table + --- @type any[] local keys = vim.tbl_keys(o) for _, k in ipairs(keys) do local v = o[k] @@ -469,7 +493,6 @@ end --- ---@param o table Table to index ---@param ... any Optional keys (0 or more, variadic) via which to index the table ---- ---@return any Nested value indexed by key (if it exists), else nil function vim.tbl_get(o, ...) local keys = { ... } @@ -477,7 +500,7 @@ function vim.tbl_get(o, ...) return nil end for i, k in ipairs(keys) do - o = o[k] + o = o[k] --- @type any if o == nil then return nil elseif type(o) ~= 'table' and next(keys, i) then @@ -521,6 +544,7 @@ end ---@return table Flattened copy of the given list-like table function vim.tbl_flatten(t) local result = {} + --- @param _t table local function _tbl_flatten(_t) local n = #_t for i = 1, n do @@ -543,7 +567,8 @@ end ---@param t table Dict-like table ---@return function # |for-in| iterator over sorted keys and their values function vim.spairs(t) - assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) + vim.validate({ t = { t, 't' } }) + --- @cast t table -- collect the keys local keys = {} @@ -578,6 +603,8 @@ function vim.tbl_isarray(t) return false end + --- @cast t table + local count = 0 for k, _ in pairs(t) do @@ -642,6 +669,7 @@ end ---@return integer Number of non-nil values in table function vim.tbl_count(t) vim.validate({ t = { t, 't' } }) + --- @cast t table local count = 0 for _ in pairs(t) do @@ -658,7 +686,7 @@ end ---@param finish integer|nil End range of slice ---@return T[] (list) Copy of table sliced from start to finish (inclusive) function vim.list_slice(list, start, finish) - local new_list = {} + local new_list = {} --- @type `T`[] for i = start or 1, finish or #list do new_list[#new_list + 1] = list[i] end @@ -707,6 +735,16 @@ function vim.endswith(s, suffix) end do + --- @alias vim.validate.Type + --- | 't' | 'table' + --- | 's' | 'string' + --- | 'n' | 'number' + --- | 'f' | 'function' + --- | 'c' | 'callable' + --- | 'nil' + --- | 'thread' + --- | 'userdata + local type_names = { ['table'] = 'table', t = 'table', @@ -725,10 +763,17 @@ do ['userdata'] = 'userdata', } + --- @class vim.validate.Spec {[1]: any, [2]: string|string[], [3]: boolean } + --- @field [1] any Argument value + --- @field [2] string|string[]|fun(v:any):boolean, string? Type name, or callable + --- @field [3]? boolean + local function _is_type(val, t) return type(val) == t or (t == 'callable' and vim.is_callable(val)) end + --- @param opt table + --- @return boolean, string? local function is_valid(opt) if type(opt) ~= 'table' then return false, string.format('opt: expected table, got %s', type(opt)) @@ -787,7 +832,7 @@ do end end - return true, nil + return true end --- Validates a parameter specification (types and values). @@ -829,7 +874,7 @@ do --- --- ``` --- - ---@param opt table Names of parameters to validate. Each key is a parameter + ---@param opt table (table) Names of parameters to validate. Each key is a parameter --- name; each value is a tuple in one of these forms: --- 1. (arg_value, type_name, optional) --- - arg_value: argument value