From d51b6157473c4830313b566116aa3ad38dc97412 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 13 Dec 2023 14:04:24 +0100 Subject: refactor: fix luals warnings --- runtime/lua/vim/shared.lua | 5 ----- 1 file changed, 5 deletions(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 9542d93789..bbbc888727 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -617,11 +617,6 @@ function vim.tbl_islist(t) local num_elem = vim.tbl_count(t) if num_elem == 0 then - -- TODO(bfredl): in the future, we will always be inside nvim - -- then this check can be deleted. - if vim._empty_dict_mt == nil then - return nil - end return getmetatable(t) ~= vim._empty_dict_mt else for i = 1, num_elem do -- cgit From 67f53323446d45bad7a22e92493f6402316a8ba1 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Thu, 28 Dec 2023 18:00:30 -0500 Subject: fix(docs): clean up non-docstring comments for vimdoc gen These non-docstring comments can be included into doxygen's brief description and then appear in the succeeding function documentation. --- runtime/lua/vim/shared.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index bbbc888727..fd795aae49 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -579,7 +579,7 @@ function vim.tbl_isarray(t) local count = 0 for k, _ in pairs(t) do - --- Check if the number k is an integer + -- Check if the number k is an integer if type(k) == 'number' and k == math.floor(k) then count = count + 1 else -- cgit From 3734519e3b4ba1bf19ca772104170b0ef776be46 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 2 Jan 2024 15:47:55 +0000 Subject: feat(lua): add noref to deepcopy Problem: Currently `deepcopy` hashes every single tables it copies so it can be reused. For tables of mostly unique items that are non recursive, this hashing is unnecessarily expensive Solution: Port the `noref` argument from Vimscripts `deepcopy()`. The below benchmark demonstrates the results for two extreme cases of tables of different sizes. One table that uses the same table lots of times and one with all unique tables. | test | `noref=false` (ms) | `noref=true` (ms) | | -------------------- | ------------------ | ----------------- | | unique tables (50) | 6.59 | 2.62 | | shared tables (50) | 3.24 | 6.40 | | unique tables (2000) | 23381.48 | 2884.53 | | shared tables (2000) | 3505.54 | 14038.80 | The results are basically the inverse of each other where `noref` is much more performance on tables with unique fields, and `not noref` is more performant on tables that reuse fields. --- runtime/lua/vim/shared.lua | 70 ++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index bbbc888727..87ab21a28f 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -9,43 +9,36 @@ ---@diagnostic disable-next-line: lowercase-global vim = vim or {} -local function _id(v) - return v -end +---@generic T +---@param orig T +---@param cache? table +---@return T +local function deepcopy(orig, cache) + if orig == vim.NIL then + return vim.NIL + elseif type(orig) == 'userdata' or type(orig) == 'thread' then + error('Cannot deepcopy object of type ' .. type(orig)) + elseif type(orig) ~= 'table' then + return orig + end -local deepcopy + --- @cast orig table -local deepcopy_funcs = { - table = function(orig, cache) - if cache[orig] then - return cache[orig] - end - local copy = {} + if cache and cache[orig] then + return cache[orig] + end + local copy = {} --- @type table + + if cache then cache[orig] = copy - local mt = getmetatable(orig) - for k, v in pairs(orig) do - copy[deepcopy(k, cache)] = deepcopy(v, cache) - end - return setmetatable(copy, mt) - end, - number = _id, - string = _id, - ['nil'] = _id, - boolean = _id, - ['function'] = _id, -} - -deepcopy = function(orig, _cache) - local f = deepcopy_funcs[type(orig)] - if f then - return f(orig, _cache or {}) - else - if type(orig) == 'userdata' and orig == vim.NIL then - return vim.NIL - end - error('Cannot deepcopy object of type ' .. type(orig)) end + + for k, v in pairs(orig) do + copy[deepcopy(k, cache)] = deepcopy(v, cache) + end + + return setmetatable(copy, getmetatable(orig)) end --- Returns a deep copy of the given object. Non-table objects are copied as @@ -54,11 +47,20 @@ end --- same functions as those in the input table. Userdata and threads are not --- copied and will throw an error. --- +--- Note: `noref=true` is much more performant on tables with unique table +--- fields, while `noref=false` is more performant on tables that reuse table +--- fields. +--- ---@generic T: table ---@param orig T Table to copy +---@param noref? boolean +--- When `false` (default) a contained table is only copied once and all +--- references point to this single copy. When `true` every occurrence of a +--- table results in a new copy. This also means that a cyclic reference can +--- cause `deepcopy()` to fail. ---@return T Table of copied keys and (nested) values. -function vim.deepcopy(orig) - return deepcopy(orig) +function vim.deepcopy(orig, noref) + return deepcopy(orig, not noref and {} or nil) end --- Gets an |iterator| that splits a string at each instance of a separator, in "lazy" fashion -- cgit From 2f9ee9b6cfc61a0504fc0bc22bdf481828e2ea91 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 9 Jan 2024 17:36:46 +0000 Subject: fix(doc): improve doc generation of types using lpeg Added a lpeg grammar for LuaCATS and use it in lua2dox.lua --- runtime/lua/vim/shared.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 24bc97bf8e..e76d148b1b 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -875,7 +875,7 @@ end --- a.b.c = 1 --- ``` --- ----@param createfn function?(key:any):any Provides the value for a missing `key`. +---@param createfn? fun(key:any):any Provides the value for a missing `key`. ---@return table # Empty table with `__index` metamethod. function vim.defaulttable(createfn) createfn = createfn or function(_) -- cgit From 2e982f1aad9f1a03562b7a451d642f76b04c37cb Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 22 Jan 2024 18:23:28 +0100 Subject: refactor: create function for deferred loading The benefit of this is that users only pay for what they use. If e.g. only `vim.lsp.buf_get_clients()` is called then they don't need to load all modules under `vim.lsp` which could lead to significant startuptime saving. Also `vim.lsp.module` is a bit nicer to user compared to `require("vim.lsp.module")`. This isn't used for some nested modules such as `filetype` as it breaks tests with error messages such as "attempt to index field 'detect'". It's not entirely certain the reason for this, but it is likely it is due to filetype being precompiled which would imply deferred loading isn't needed for performance reasons. --- runtime/lua/vim/shared.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index e76d148b1b..fa7690e41e 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -983,4 +983,24 @@ do end end +--- @private +--- @generic T +--- @param root string +--- @param mod T +--- @return T +function vim._defer_require(root, mod) + return setmetatable({}, { + ---@param t table + ---@param k string + __index = function(t, k) + if not mod[k] then + return + end + local name = string.format('%s.%s', root, k) + t[k] = require(name) + return t[k] + end, + }) +end + return vim -- cgit From 59cf827f99d53ec8dbb90e48a7561c0cb8b8ca6f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 7 Feb 2024 17:22:03 +0000 Subject: refactor(lsp): move client code to a regular Lua class Problem: The LSP client code is implemented as a complicated closure-class (class defined in a single function). Solution: Move LSP client code to a more conventional Lua class and move to a separate file. --- runtime/lua/vim/shared.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index fa7690e41e..dd0f7c2e1e 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -895,6 +895,7 @@ do ---@field private _idx_read integer ---@field private _idx_write integer ---@field private _size integer + ---@overload fun(self): table? local Ringbuf = {} --- Clear all items -- cgit From 35f453f65df2cab4eaeda99c205d1fda235b7bc9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 15 Feb 2024 10:53:51 +0000 Subject: fix: type warnings in shared.lua --- runtime/lua/vim/shared.lua | 85 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 20 deletions(-) (limited to 'runtime/lua/vim/shared.lua') 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 -- cgit From 9beb40a4db5613601fc1a4b828a44e5977eca046 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 15 Feb 2024 17:16:04 +0000 Subject: feat(docs): replace lua2dox.lua Problem: The documentation flow (`gen_vimdoc.py`) has several issues: - it's not very versatile - depends on doxygen - doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C. - The intermediate XML files and filters makes it too much like a rube goldberg machine. Solution: Re-implement the flow using Lua, LPEG and treesitter. - `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic. - `lua2dox.lua` is gone! - No more XML files. - Doxygen is now longer used and instead we now use: - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`). - LPEG for C parsing (see `scripts/cdoc_parser.lua`) - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`). - Treesitter for Markdown parsing (see `scripts/text_utils.lua`). - The generated `runtime/doc/*.mpack` files have been removed. - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly. - Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change). --- runtime/lua/vim/shared.lua | 92 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 46 deletions(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 5cf8390843..83fdfede89 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -6,6 +6,7 @@ -- or the test suite. (Eventually the test suite will be run in a worker process, -- so this wouldn't be a separate case to consider) +---@nodoc ---@diagnostic disable-next-line: lowercase-global vim = vim or {} @@ -191,8 +192,8 @@ end --- ---@param s string String to split ---@param sep string Separator or pattern ----@param opts (table|nil) Keyword arguments |kwargs| accepted by |vim.gsplit()| ----@return string[] List of split components +---@param opts? table Keyword arguments |kwargs| accepted by |vim.gsplit()| +---@return string[] : List of split components function vim.split(s, sep, opts) local t = {} for c in vim.gsplit(s, sep, opts) do @@ -206,9 +207,9 @@ end --- ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@generic T: table +---@generic T ---@param t table (table) Table ----@return T[] (list) List of keys +---@return T[] : List of keys function vim.tbl_keys(t) vim.validate({ t = { t, 't' } }) --- @cast t table @@ -225,7 +226,7 @@ end --- ---@generic T ---@param t table (table) Table ----@return T[] (list) List of values +---@return T[] : List of values function vim.tbl_values(t) vim.validate({ t = { t, 't' } }) @@ -243,7 +244,7 @@ end ---@generic T ---@param func fun(value: T): any (function) Function ---@param t table (table) Table ----@return table Table of transformed values +---@return table : Table of transformed values function vim.tbl_map(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) --- @cast t table @@ -260,7 +261,7 @@ end ---@generic T ---@param func fun(value: T): boolean (function) Function ---@param t table (table) Table ----@return T[] (table) Table of filtered values +---@return T[] : Table of filtered values function vim.tbl_filter(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) --- @cast t table @@ -401,7 +402,7 @@ end --- - "keep": use value from the leftmost map --- - "force": use value from the rightmost map ---@param ... table Two or more tables ----@return table Merged table +---@return table : Merged table function vim.tbl_extend(behavior, ...) return tbl_extend(behavior, false, ...) end @@ -456,7 +457,7 @@ end --- Add the reverse lookup values to an existing table. --- For example: ---- ``tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`` +--- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }` --- --- Note that this *modifies* the input. ---@param o table Table to add the reverse to @@ -493,7 +494,7 @@ 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 +---@return any : Nested value indexed by key (if it exists), else nil function vim.tbl_get(o, ...) local keys = { ... } if #keys == 0 then @@ -519,8 +520,8 @@ end ---@generic T: table ---@param dst T List which will be modified and appended to ---@param src table List from which values will be inserted ----@param start (integer|nil) Start index on src. Defaults to 1 ----@param finish (integer|nil) Final index on src. Defaults to `#src` +---@param start integer? Start index on src. Defaults to 1 +---@param finish integer? Final index on src. Defaults to `#src` ---@return T dst function vim.list_extend(dst, src, start, finish) vim.validate({ @@ -666,7 +667,7 @@ end --- ---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua ---@param t table Table ----@return integer Number of non-nil values in table +---@return integer : Number of non-nil values in table function vim.tbl_count(t) vim.validate({ t = { t, 't' } }) --- @cast t table @@ -681,10 +682,10 @@ end --- Creates a copy of a table containing only elements from start to end (inclusive) --- ---@generic T ----@param list T[] (list) Table +---@param list T[] Table ---@param start integer|nil Start range of slice ---@param finish integer|nil End range of slice ----@return T[] (list) Copy of table sliced from start to finish (inclusive) +---@return T[] Copy of table sliced from start to finish (inclusive) function vim.list_slice(list, start, finish) local new_list = {} --- @type `T`[] for i = start or 1, finish or #list do @@ -840,38 +841,37 @@ do --- Usage example: --- --- ```lua - --- function user.new(name, age, hobbies) - --- vim.validate{ - --- name={name, 'string'}, - --- age={age, 'number'}, - --- hobbies={hobbies, 'table'}, - --- } - --- ... - --- end + --- function user.new(name, age, hobbies) + --- vim.validate{ + --- name={name, 'string'}, + --- age={age, 'number'}, + --- hobbies={hobbies, 'table'}, + --- } + --- ... + --- end --- ``` --- --- Examples with explicit argument values (can be run directly): --- --- ```lua - --- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}} - --- --> NOP (success) + --- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}} + --- --> NOP (success) --- - --- vim.validate{arg1={1, 'table'}} - --- --> error('arg1: expected table, got number') + --- vim.validate{arg1={1, 'table'}} + --- --> error('arg1: expected table, got number') --- - --- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}} - --- --> error('arg1: expected even number, got 3') + --- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}} + --- --> error('arg1: expected even number, got 3') --- ``` --- --- If multiple types are valid they can be given as a list. --- --- ```lua - --- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}} - --- -- NOP (success) - --- - --- vim.validate{arg1={1, {'string', 'table'}}} - --- -- error('arg1: expected string|table, got number') + --- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}} + --- -- NOP (success) --- + --- vim.validate{arg1={1, {'string', 'table'}}} + --- -- error('arg1: expected string|table, got number') --- ``` --- ---@param opt table (table) Names of parameters to validate. Each key is a parameter @@ -989,19 +989,19 @@ do --- Once the buffer is full, adding a new entry overrides the oldest entry. --- --- ```lua - --- local ringbuf = vim.ringbuf(4) - --- ringbuf:push("a") - --- ringbuf:push("b") - --- ringbuf:push("c") - --- ringbuf:push("d") - --- ringbuf:push("e") -- overrides "a" - --- print(ringbuf:pop()) -- returns "b" - --- print(ringbuf:pop()) -- returns "c" + --- local ringbuf = vim.ringbuf(4) + --- ringbuf:push("a") + --- ringbuf:push("b") + --- ringbuf:push("c") + --- ringbuf:push("d") + --- ringbuf:push("e") -- overrides "a" + --- print(ringbuf:pop()) -- returns "b" + --- print(ringbuf:pop()) -- returns "c" --- - --- -- Can be used as iterator. Pops remaining items: - --- for val in ringbuf do - --- print(val) - --- end + --- -- Can be used as iterator. Pops remaining items: + --- for val in ringbuf do + --- print(val) + --- end --- ``` --- --- Returns a Ringbuf instance with the following methods: -- cgit From a5fe8f59d98398d04bed8586cee73864bbcdde92 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 27 Feb 2024 15:20:32 +0000 Subject: docs: improve/add documentation of Lua types - Added `@inlinedoc` so single use Lua types can be inlined into the functions docs. E.g. ```lua --- @class myopts --- @inlinedoc --- --- Documentation for some field --- @field somefield integer --- @param opts myOpts function foo(opts) end ``` Will be rendered as ``` foo(opts) Parameters: - {opts} (table) Object with the fields: - somefield (integer) Documentation for some field ``` - Marked many classes with with `@nodoc` or `(private)`. We can eventually introduce these when we want to. --- runtime/lua/vim/shared.lua | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 83fdfede89..ec70630df3 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -65,8 +65,13 @@ function vim.deepcopy(orig, noref) 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. +--- @inlinedoc +--- +--- Use `sep` literally (as in string.find). +--- @field plain? boolean +--- +--- Discard empty segments at start and end of the sequence. +--- @field trimempty? boolean --- Gets an |iterator| that splits a string at each instance of a separator, in "lazy" fashion --- (as opposed to |vim.split()| which is "eager"). @@ -96,10 +101,8 @@ end --- --- @param s string String to split --- @param sep string Separator or pattern ---- @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 +--- @param opts? vim.gsplit.Opts Keyword arguments |kwargs|: +--- @return fun():string|nil (function) Iterator over the split components function vim.gsplit(s, sep, opts) local plain --- @type boolean? local trimempty = false @@ -192,7 +195,7 @@ end --- ---@param s string String to split ---@param sep string Separator or pattern ----@param opts? table Keyword arguments |kwargs| accepted by |vim.gsplit()| +---@param opts? vim.gsplit.Opts Keyword arguments |kwargs|: ---@return string[] : List of split components function vim.split(s, sep, opts) local t = {} @@ -276,6 +279,9 @@ function vim.tbl_filter(func, t) end --- @class vim.tbl_contains.Opts +--- @inlinedoc +--- +--- `value` is a function reference to be checked (default false) --- @field predicate? boolean --- Checks if a table contains a given value, specified either directly or via @@ -294,8 +300,7 @@ end --- ---@param t table Table to check ---@param value any Value to compare or predicate function reference ----@param opts? vim.tbl_contains.Opts (table) Keyword arguments |kwargs|: ---- - predicate: (boolean) `value` is a function reference to be checked (default false) +---@param opts? vim.tbl_contains.Opts Keyword arguments |kwargs|: ---@return boolean `true` if `t` contains `value` function vim.tbl_contains(t, value, opts) vim.validate({ t = { t, 't' }, opts = { opts, 't', true } }) @@ -764,6 +769,7 @@ do ['userdata'] = 'userdata', } + --- @nodoc --- @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 -- cgit From a4290f462ed7dc81e17b09bd27877b106b24b6bd Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 5 Mar 2024 12:06:15 +0000 Subject: docs(lua): improvements for LSP and Diagnostic --- runtime/lua/vim/shared.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index ec70630df3..18d7c8b13e 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -102,7 +102,7 @@ end --- @param s string String to split --- @param sep string Separator or pattern --- @param opts? vim.gsplit.Opts Keyword arguments |kwargs|: ---- @return fun():string|nil (function) Iterator over the split components +--- @return fun():string? : Iterator over the split components function vim.gsplit(s, sep, opts) local plain --- @type boolean? local trimempty = false @@ -245,8 +245,8 @@ end --- Apply a function to all values of a table. --- ---@generic T ----@param func fun(value: T): any (function) Function ----@param t table (table) Table +---@param func fun(value: T): any Function +---@param t table Table ---@return table : Table of transformed values function vim.tbl_map(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) @@ -570,8 +570,10 @@ end --- ---@see Based on https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@param t table Dict-like table ----@return function # |for-in| iterator over sorted keys and their values +---@generic T: table, K, V +---@param t T Dict-like table +---@return fun(table: table, index?: K):K, V # |for-in| iterator over sorted keys and their values +---@return T function vim.spairs(t) vim.validate({ t = { t, 't' } }) --- @cast t table @@ -1018,7 +1020,7 @@ do --- - |Ringbuf:clear()| --- ---@param size integer - ---@return vim.Ringbuf ringbuf (table) + ---@return vim.Ringbuf ringbuf function vim.ringbuf(size) local ringbuf = { _items = {}, -- cgit From ea44f74d84f87ce5aff2ef7797be986900bd74a6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 6 Mar 2024 10:03:55 +0000 Subject: refactor(types): more fixes --- runtime/lua/vim/shared.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 18d7c8b13e..6e50b87dd5 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -592,7 +592,8 @@ function vim.spairs(t) if keys[i] then return keys[i], t[keys[i]] end - end + end, + t end --- Tests if `t` is an "array": a table indexed _only_ by integers (potentially non-contiguous). -- cgit From 3d2aeec68d6a03a07394eea154447166f6487078 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 6 Mar 2024 09:40:11 +0000 Subject: refactor(lua): more efficient vim.tbl_islist No need to run a full iteration of the table. Simply return false when the next key isn't what we expect. --- runtime/lua/vim/shared.lua | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 6e50b87dd5..561d9e3f1b 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -652,18 +652,21 @@ function vim.tbl_islist(t) return false end - local num_elem = vim.tbl_count(t) - - if num_elem == 0 then + if next(t) == nil then return getmetatable(t) ~= vim._empty_dict_mt - else - for i = 1, num_elem do - if t[i] == nil then - return false - end + end + + local j = 1 + for _ in + pairs(t--[[@as table]]) + do + if t[j] == nil then + return false end - return true + j = j + 1 end + + return true end --- Counts the number of non-nil values in table `t`. -- cgit From e52c25b7617ac6401b080f76b0e227161dfef230 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 2 Mar 2024 13:11:23 -0800 Subject: feat(lua): deprecate vim.tbl_add_reverse_lookup --- runtime/lua/vim/shared.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim/shared.lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 561d9e3f1b..bd553598c7 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -465,9 +465,12 @@ end --- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }` --- --- Note that this *modifies* the input. +---@deprecated ---@param o table Table to add the reverse to ---@return table o function vim.tbl_add_reverse_lookup(o) + vim.deprecate('vim.tbl_add_reverse_lookup', nil, '0.12') + --- @cast o table --- @type any[] local keys = vim.tbl_keys(o) -- cgit