diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 22:39:54 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-29 22:39:54 +0000 |
commit | 21cb7d04c387e4198ca8098a884c78b56ffcf4c2 (patch) | |
tree | 84fe5690df1551f0bb2bdfe1a13aacd29ebc1de7 /runtime/lua/vim/shared.lua | |
parent | d9c904f85a23a496df4eb6be42aa43f007b22d50 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-colorcolchar.tar.gz rneovim-colorcolchar.tar.bz2 rneovim-colorcolchar.zip |
Merge remote-tracking branch 'upstream/master' into colorcolcharcolorcolchar
Diffstat (limited to 'runtime/lua/vim/shared.lua')
-rw-r--r-- | runtime/lua/vim/shared.lua | 605 |
1 files changed, 405 insertions, 200 deletions
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index cc48e3f193..9542d93789 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -6,8 +6,48 @@ -- 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) +---@diagnostic disable-next-line: lowercase-global vim = vim or {} +local function _id(v) + return v +end + +local deepcopy + +local deepcopy_funcs = { + table = function(orig, cache) + if cache[orig] then + return cache[orig] + end + local copy = {} + + 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 +end + --- Returns a deep copy of the given object. Non-table objects are copied as --- in a typical Lua assignment, whereas table objects are copied recursively. --- Functions are naively copied, so functions in the copied table point to the @@ -17,63 +57,60 @@ vim = vim or {} ---@generic T: table ---@param orig T Table to copy ---@return T Table of copied keys and (nested) values. -function vim.deepcopy(orig) end -- luacheck: no unused -vim.deepcopy = (function() - local function _id(v) - return v - end - - local deepcopy_funcs = { - table = function(orig, cache) - if cache[orig] then - return cache[orig] - end - local copy = {} - - cache[orig] = copy - local mt = getmetatable(orig) - for k, v in pairs(orig) do - copy[vim.deepcopy(k, cache)] = vim.deepcopy(v, cache) - end - return setmetatable(copy, mt) - end, - number = _id, - string = _id, - ['nil'] = _id, - boolean = _id, - ['function'] = _id, - } +function vim.deepcopy(orig) + return deepcopy(orig) +end - return 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 +--- Gets an |iterator| that splits a string at each instance of a separator, in "lazy" fashion +--- (as opposed to |vim.split()| which is "eager"). +--- +--- Example: +--- +--- ```lua +--- for s in vim.gsplit(':aa::b:', ':', {plain=true}) do +--- print(s) +--- end +--- ``` +--- +--- If you want to also inspect the separator itself (instead of discarding it), use +--- |string.gmatch()|. Example: +--- +--- ```lua +--- for word, num in ('foo111bar222'):gmatch('([^0-9]*)(%d*)') do +--- print(('word: %s num: %s'):format(word, num)) +--- end +--- ``` +--- +--- @see |string.gmatch()| +--- @see |vim.split()| +--- @see |lua-patterns| +--- @see https://www.lua.org/pil/20.2.html +--- @see http://lua-users.org/wiki/StringLibraryTutorial +--- +--- @param s string String to split +--- @param sep string Separator or pattern +--- @param opts (table|nil) 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 trimempty = false + if type(opts) == 'boolean' then + plain = opts -- For backwards compatibility. + else + vim.validate({ s = { s, 's' }, sep = { sep, 's' }, opts = { opts, 't', true } }) + opts = opts or {} + plain, trimempty = opts.plain, opts.trimempty end -end)() - ---- Splits a string at each instance of a separator. ---- ----@see |vim.split()| ----@see |luaref-patterns| ----@see https://www.lua.org/pil/20.2.html ----@see http://lua-users.org/wiki/StringLibraryTutorial ---- ----@param s string String to split ----@param sep string Separator or pattern ----@param plain (boolean|nil) If `true` use `sep` literally (passed to string.find) ----@return fun():string (function) Iterator over the split components -function vim.gsplit(s, sep, plain) - vim.validate({ s = { s, 's' }, sep = { sep, 's' }, plain = { plain, 'b', true } }) local start = 1 local done = false + -- For `trimempty`: queue of collected segments, to be emitted at next pass. + local segs = {} + local empty_start = true -- Only empty segments seen so far. + local function _pass(i, j, ...) if i then assert(j + 1 > start, 'Infinite loop detected') @@ -87,72 +124,69 @@ function vim.gsplit(s, sep, plain) end return function() - if done or (s == '' and sep == '') then - return - end - if sep == '' then + if trimempty and #segs > 0 then + -- trimempty: Pop the collected segments. + return table.remove(segs) + elseif done or (s == '' and sep == '') then + return nil + elseif sep == '' then if start == #s then done = true end return _pass(start + 1, start) end - return _pass(s:find(sep, start, plain)) + + local seg = _pass(s:find(sep, start, plain)) + + -- Trim empty segments from start/end. + if trimempty and seg ~= '' then + empty_start = false + elseif trimempty and seg == '' then + while not done and seg == '' do + table.insert(segs, 1, '') + seg = _pass(s:find(sep, start, plain)) + end + if done and seg == '' then + return nil + elseif empty_start then + empty_start = false + segs = {} + return seg + end + if seg ~= '' then + table.insert(segs, 1, seg) + end + return table.remove(segs) + end + + return seg end end ---- Splits a string at each instance of a separator. +--- Splits a string at each instance of a separator and returns the result as a table (unlike +--- |vim.gsplit()|). --- --- Examples: ---- <pre>lua ---- split(":aa::b:", ":") --> {'','aa','','b',''} ---- split("axaby", "ab?") --> {'','x','y'} ---- split("x*yz*o", "*", {plain=true}) --> {'x','yz','o'} ---- split("|x|y|z|", "|", {trimempty=true}) --> {'x', 'y', 'z'} ---- </pre> +--- +--- ```lua +--- split(":aa::b:", ":") --> {'','aa','','b',''} +--- split("axaby", "ab?") --> {'','x','y'} +--- split("x*yz*o", "*", {plain=true}) --> {'x','yz','o'} +--- split("|x|y|z|", "|", {trimempty=true}) --> {'x', 'y', 'z'} +--- ``` --- ---@see |vim.gsplit()| +---@see |string.gmatch()| --- ---@param s string String to split ---@param sep string Separator or pattern ----@param kwargs (table|nil) Keyword arguments: ---- - plain: (boolean) If `true` use `sep` literally (passed to string.find) ---- - trimempty: (boolean) If `true` remove empty items from the front ---- and back of the list +---@param opts (table|nil) Keyword arguments |kwargs| accepted by |vim.gsplit()| ---@return string[] List of split components -function vim.split(s, sep, kwargs) - local plain - local trimempty = false - if type(kwargs) == 'boolean' then - -- Support old signature for backward compatibility - plain = kwargs - else - vim.validate({ kwargs = { kwargs, 't', true } }) - kwargs = kwargs or {} - plain = kwargs.plain - trimempty = kwargs.trimempty - end - +function vim.split(s, sep, opts) local t = {} - local skip = trimempty - for c in vim.gsplit(s, sep, plain) do - if c ~= '' then - skip = false - end - - if not skip then - table.insert(t, c) - end - end - - if trimempty then - for i = #t, 1, -1 do - if t[i] ~= '' then - break - end - table.remove(t, i) - end + for c in vim.gsplit(s, sep, opts) do + table.insert(t, c) end - return t end @@ -224,12 +258,54 @@ function vim.tbl_filter(func, t) return rettab end ---- Checks if a list-like (vector) table contains `value`. +--- Checks if a table contains a given value, specified either directly or via +--- a predicate that is checked for each value. +--- +--- Example: +--- +--- ```lua +--- vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v) +--- return vim.deep_equal(v, { 'b', 'c' }) +--- end, { predicate = true }) +--- -- true +--- ``` +--- +---@see |vim.list_contains()| for checking values in list-like tables --- ---@param t table Table to check +---@param value any Value to compare or predicate function reference +---@param opts (table|nil) 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 } }) + + local pred + if opts and opts.predicate then + vim.validate({ value = { value, 'c' } }) + pred = value + else + pred = function(v) + return v == value + end + end + + for _, v in pairs(t) do + if pred(v) then + return true + end + end + return false +end + +--- Checks if a list-like table (integer keys without gaps) contains `value`. +--- +---@see |vim.tbl_contains()| for checking values in general tables +--- +---@param t table Table to check (must be list-like, not validated) ---@param value any Value to compare ---@return boolean `true` if `t` contains `value` -function vim.tbl_contains(t, value) +function vim.list_contains(t, value) vim.validate({ t = { t, 't' } }) for _, v in ipairs(t) do @@ -251,10 +327,9 @@ function vim.tbl_isempty(t) return next(t) == nil end ---- We only merge empty tables or tables that are not a list ----@private +--- We only merge empty tables or tables that are not an array (indexed by integers) local function can_merge(v) - return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) + return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.tbl_isarray(v)) end local function tbl_extend(behavior, deep_extend, ...) @@ -295,7 +370,7 @@ local function tbl_extend(behavior, deep_extend, ...) return ret end ---- Merges two or more map-like tables. +--- Merges two or more tables. --- ---@see |extend()| --- @@ -303,13 +378,13 @@ end --- - "error": raise an error --- - "keep": use value from the leftmost map --- - "force": use value from the rightmost map ----@param ... table Two or more map-like tables +---@param ... table Two or more tables ---@return table Merged table function vim.tbl_extend(behavior, ...) return tbl_extend(behavior, false, ...) end ---- Merges recursively two or more map-like tables. +--- Merges recursively two or more tables. --- ---@see |vim.tbl_extend()| --- @@ -319,7 +394,7 @@ end --- - "error": raise an error --- - "keep": use value from the leftmost map --- - "force": use value from the rightmost map ----@param ... T2 Two or more map-like tables +---@param ... T2 Two or more tables ---@return T1|T2 (table) Merged table function vim.tbl_deep_extend(behavior, ...) return tbl_extend(behavior, true, ...) @@ -384,13 +459,14 @@ end --- Return `nil` if the key does not exist. --- --- Examples: ---- <pre>lua ---- vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true ---- vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil ---- </pre> +--- +--- ```lua +--- vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true +--- vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil +--- ``` --- ---@param o table Table to index ----@param ... string Optional strings (0 or more, variadic) via which to index the table +---@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, ...) @@ -418,8 +494,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 (number|nil) Start index on src. Defaults to 1 ----@param finish (number|nil) Final index on src. Defaults to `#src` +---@param start (integer|nil) Start index on src. Defaults to 1 +---@param finish (integer|nil) Final index on src. Defaults to `#src` ---@return T dst function vim.list_extend(dst, src, start, finish) vim.validate({ @@ -458,12 +534,12 @@ function vim.tbl_flatten(t) return result end ---- Enumerate a table sorted by its keys. +--- Enumerates key-value pairs of a table, ordered by key. --- ---@see Based on https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@param t table List-like table ----@return iterator over sorted keys and their values +---@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))) @@ -475,7 +551,6 @@ function vim.spairs(t) table.sort(keys) -- Return the iterator function. - -- TODO(justinmk): Return "iterator function, table {t}, and nil", like pairs()? local i = 0 return function() i = i + 1 @@ -485,15 +560,18 @@ function vim.spairs(t) end end ---- Tests if a Lua table can be treated as an array. +--- Tests if `t` is an "array": a table indexed _only_ by integers (potentially non-contiguous). --- ---- Empty table `{}` is assumed to be an array, unless it was created by ---- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result, ---- for example from |rpcrequest()| or |vim.fn|. +--- If the indexes start from 1 and are contiguous then the array is also a list. |vim.tbl_islist()| --- ----@param t table Table ----@return boolean `true` if array-like table, else `false` -function vim.tbl_islist(t) +--- Empty table `{}` is an array, unless it was created by |vim.empty_dict()| or returned as +--- a dict-like |API| or Vimscript result, for example from |rpcrequest()| or |vim.fn|. +--- +---@see https://github.com/openresty/luajit2#tableisarray +--- +---@param t table +---@return boolean `true` if array-like table, else `false`. +function vim.tbl_isarray(t) if type(t) ~= 'table' then return false end @@ -501,7 +579,8 @@ function vim.tbl_islist(t) local count = 0 for k, _ in pairs(t) do - if type(k) == 'number' then + --- Check if the number k is an integer + if type(k) == 'number' and k == math.floor(k) then count = count + 1 else return false @@ -520,16 +599,50 @@ function vim.tbl_islist(t) end end +--- Tests if `t` is a "list": a table indexed _only_ by contiguous integers starting from 1 (what +--- |lua-length| calls a "regular array"). +--- +--- Empty table `{}` is a list, unless it was created by |vim.empty_dict()| or returned as +--- a dict-like |API| or Vimscript result, for example from |rpcrequest()| or |vim.fn|. +--- +---@see |vim.tbl_isarray()| +--- +---@param t table +---@return boolean `true` if list-like table, else `false`. +function vim.tbl_islist(t) + if type(t) ~= 'table' then + return false + end + + 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 + if t[i] == nil then + return false + end + end + return true + end +end + --- Counts the number of non-nil values in table `t`. --- ---- <pre>lua +--- ```lua --- vim.tbl_count({ a=1, b=2 }) --> 2 --- vim.tbl_count({ 1, 2 }) --> 2 ---- </pre> +--- ``` --- ---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua ---@param t table Table ----@return number 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' } }) @@ -544,8 +657,8 @@ end --- ---@generic T ---@param list T[] (list) Table ----@param start number|nil Start range of slice ----@param finish number|nil End range of slice +---@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) function vim.list_slice(list, start, finish) local new_list = {} @@ -557,7 +670,7 @@ end --- Trim whitespace (Lua pattern "%s") from both sides of a string. --- ----@see |luaref-patterns| +---@see |lua-patterns| ---@see https://www.lua.org/pil/20.2.html ---@param s string String to trim ---@return string String with whitespace removed from its beginning and end @@ -596,58 +709,6 @@ function vim.endswith(s, suffix) return #suffix == 0 or s:sub(-#suffix) == suffix end ---- Validates a parameter specification (types and values). ---- ---- Usage example: ---- <pre>lua ---- function user.new(name, age, hobbies) ---- vim.validate{ ---- name={name, 'string'}, ---- age={age, 'number'}, ---- hobbies={hobbies, 'table'}, ---- } ---- ... ---- end ---- </pre> ---- ---- Examples with explicit argument values (can be run directly): ---- <pre>lua ---- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}} ---- --> NOP (success) ---- ---- 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') ---- </pre> ---- ---- If multiple types are valid they can be given as a list. ---- <pre>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') ---- ---- </pre> ---- ----@param opt 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 ---- - type_name: string|table type name, one of: ("table", "t", "string", ---- "s", "number", "n", "boolean", "b", "function", "f", "nil", ---- "thread", "userdata") or list of them. ---- - optional: (optional) boolean, if true, `nil` is valid ---- 2. (arg_value, fn, msg) ---- - arg_value: argument value ---- - fn: any function accepting one argument, returns true if and ---- only if the argument is valid. Can optionally return an additional ---- informative error message as the second returned value. ---- - msg: (optional) error string if validation fails -function vim.validate(opt) end -- luacheck: no unused - do local type_names = { ['table'] = 'table', @@ -671,7 +732,6 @@ do return type(val) == t or (t == 'callable' and vim.is_callable(val)) end - ---@private local function is_valid(opt) if type(opt) ~= 'table' then return false, string.format('opt: expected table, got %s', type(opt)) @@ -733,6 +793,59 @@ do return true, nil end + --- Validates a parameter specification (types and values). + --- + --- Usage example: + --- + --- ```lua + --- 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={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') + --- ``` + --- + --- 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') + --- + --- ``` + --- + ---@param opt 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 + --- - type_name: string|table type name, one of: ("table", "t", "string", + --- "s", "number", "n", "boolean", "b", "function", "f", "nil", + --- "thread", "userdata") or list of them. + --- - optional: (optional) boolean, if true, `nil` is valid + --- 2. (arg_value, fn, msg) + --- - arg_value: argument value + --- - fn: any function accepting one argument, returns true if and + --- only if the argument is valid. Can optionally return an additional + --- informative error message as the second returned value. + --- - msg: (optional) error string if validation fails function vim.validate(opt) local ok, err_msg = is_valid(opt) if not ok then @@ -755,30 +868,122 @@ function vim.is_callable(f) return type(m.__call) == 'function' end ---- Creates a table whose members are automatically created when accessed, if they don't already ---- exist. ---- ---- They mimic defaultdict in python. +--- Creates a table whose missing keys are provided by {createfn} (like Python's "defaultdict"). --- ---- If {create} is `nil`, this will create a defaulttable whose constructor function is ---- this function, effectively allowing to create nested tables on the fly: +--- If {createfn} is `nil` it defaults to defaulttable() itself, so accessing nested keys creates +--- nested tables: --- ---- <pre>lua +--- ```lua --- local a = vim.defaulttable() --- a.b.c = 1 ---- </pre> +--- ``` --- ----@param create function|nil The function called to create a missing value. ----@return table Empty table with metamethod -function vim.defaulttable(create) - create = create or vim.defaulttable +---@param createfn function?(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(_) + return vim.defaulttable() + end return setmetatable({}, { __index = function(tbl, key) - rawset(tbl, key, create()) + rawset(tbl, key, createfn(key)) return rawget(tbl, key) end, }) end +do + ---@class vim.Ringbuf<T> + ---@field private _items table[] + ---@field private _idx_read integer + ---@field private _idx_write integer + ---@field private _size integer + local Ringbuf = {} + + --- Clear all items + function Ringbuf.clear(self) + self._items = {} + self._idx_read = 0 + self._idx_write = 0 + end + + --- Adds an item, overriding the oldest item if the buffer is full. + ---@generic T + ---@param item T + function Ringbuf.push(self, item) + self._items[self._idx_write] = item + self._idx_write = (self._idx_write + 1) % self._size + if self._idx_write == self._idx_read then + self._idx_read = (self._idx_read + 1) % self._size + end + end + + --- Removes and returns the first unread item + ---@generic T + ---@return T? + function Ringbuf.pop(self) + local idx_read = self._idx_read + if idx_read == self._idx_write then + return nil + end + local item = self._items[idx_read] + self._items[idx_read] = nil + self._idx_read = (idx_read + 1) % self._size + return item + end + + --- Returns the first unread item without removing it + ---@generic T + ---@return T? + function Ringbuf.peek(self) + if self._idx_read == self._idx_write then + return nil + end + return self._items[self._idx_read] + end + + --- Create a ring buffer limited to a maximal number of items. + --- 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" + --- + --- -- Can be used as iterator. Pops remaining items: + --- for val in ringbuf do + --- print(val) + --- end + --- ``` + --- + --- Returns a Ringbuf instance with the following methods: + --- + --- - |Ringbuf:push()| + --- - |Ringbuf:pop()| + --- - |Ringbuf:peek()| + --- - |Ringbuf:clear()| + --- + ---@param size integer + ---@return vim.Ringbuf ringbuf (table) + function vim.ringbuf(size) + local ringbuf = { + _items = {}, + _size = size + 1, + _idx_read = 0, + _idx_write = 0, + } + return setmetatable(ringbuf, { + __index = Ringbuf, + __call = function(self) + return self:pop() + end, + }) + end +end + return vim --- vim:sw=2 ts=2 et |