aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/shared.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/shared.lua')
-rw-r--r--runtime/lua/vim/shared.lua157
1 files changed, 84 insertions, 73 deletions
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 0a663628a5..18c1e21049 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -12,8 +12,8 @@ local vim = vim or {}
--- same functions as those in the input table. Userdata and threads are not
--- copied and will throw an error.
---
---@param orig Table to copy
---@returns New table of copied keys and (nested) values.
+---@param orig Table to copy
+---@returns New table of copied keys and (nested) values.
function vim.deepcopy(orig) end -- luacheck: no unused
vim.deepcopy = (function()
local function _id(v)
@@ -52,14 +52,14 @@ end)()
--- Splits a string at each instance of a separator.
---
---@see |vim.split()|
---@see https://www.lua.org/pil/20.2.html
---@see http://lua-users.org/wiki/StringLibraryTutorial
+---@see |vim.split()|
+---@see https://www.lua.org/pil/20.2.html
+---@see http://lua-users.org/wiki/StringLibraryTutorial
---
---@param s String to split
---@param sep Separator string or pattern
---@param plain If `true` use `sep` literally (passed to String.find)
---@returns Iterator over the split components
+---@param s String to split
+---@param sep Separator string or pattern
+---@param plain If `true` use `sep` literally (passed to String.find)
+---@returns Iterator over the split components
function vim.gsplit(s, sep, plain)
vim.validate{s={s,'s'},sep={sep,'s'},plain={plain,'b',true}}
@@ -101,12 +101,12 @@ end
--- split(x*yz*o, "*", true) --> {'x','yz','o'}
--- </pre>
--
---@see |vim.gsplit()|
+---@see |vim.gsplit()|
---
---@param s String to split
---@param sep Separator string or pattern
---@param plain If `true` use `sep` literally (passed to String.find)
---@returns List-like table of the split components.
+---@param s String to split
+---@param sep Separator string or pattern
+---@param plain If `true` use `sep` literally (passed to String.find)
+---@returns List-like table of the split components.
function vim.split(s,sep,plain)
local t={} for c in vim.gsplit(s, sep, plain) do table.insert(t,c) end
return t
@@ -115,10 +115,10 @@ end
--- Return a list of all keys used in a table.
--- However, the order of the return table of keys is not guaranteed.
---
---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t Table
---@returns list of keys
+---@param t Table
+---@returns list of keys
function vim.tbl_keys(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
@@ -132,8 +132,8 @@ end
--- Return a list of all values used in a table.
--- However, the order of the return table of values is not guaranteed.
---
---@param t Table
---@returns list of values
+---@param t Table
+---@returns list of values
function vim.tbl_values(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
@@ -146,8 +146,8 @@ end
--- Apply a function to all values of a table.
---
---@param func function or callable table
---@param t table
+---@param func function or callable table
+---@param t table
function vim.tbl_map(func, t)
vim.validate{func={func,'c'},t={t,'t'}}
@@ -160,8 +160,8 @@ end
--- Filter a table using a predicate function
---
---@param func function or callable table
---@param t table
+---@param func function or callable table
+---@param t table
function vim.tbl_filter(func, t)
vim.validate{func={func,'c'},t={t,'t'}}
@@ -176,9 +176,9 @@ end
--- Checks if a list-like (vector) table contains `value`.
---
---@param t Table to check
---@param value Value to compare
---@returns true if `t` contains `value`
+---@param t Table to check
+---@param value Value to compare
+---@returns true if `t` contains `value`
function vim.tbl_contains(t, value)
vim.validate{t={t,'t'}}
@@ -192,14 +192,20 @@ end
--- Checks if a table is empty.
---
---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t Table to check
+---@param t Table to check
function vim.tbl_isempty(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
return next(t) == nil
end
+--- we only merge empty tables or tables that are not a list
+---@private
+local function can_merge(v)
+ return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v))
+end
+
local function tbl_extend(behavior, deep_extend, ...)
if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then
error('invalid "behavior": '..tostring(behavior))
@@ -219,8 +225,8 @@ local function tbl_extend(behavior, deep_extend, ...)
vim.validate{["after the second argument"] = {tbl,'t'}}
if tbl then
for k, v in pairs(tbl) do
- if type(v) == 'table' and deep_extend and not vim.tbl_islist(v) then
- ret[k] = tbl_extend(behavior, true, ret[k] or vim.empty_dict(), v)
+ if deep_extend and can_merge(v) and can_merge(ret[k]) then
+ ret[k] = tbl_extend(behavior, true, ret[k], v)
elseif behavior ~= 'force' and ret[k] ~= nil then
if behavior == 'error' then
error('key found in more than one map: '..k)
@@ -236,43 +242,48 @@ end
--- Merges two or more map-like tables.
---
---@see |extend()|
+---@see |extend()|
---
---@param behavior Decides what to do if a key is found in more than one map:
+---@param behavior Decides what to do if a key is found in more than one map:
--- - "error": raise an error
--- - "keep": use value from the leftmost map
--- - "force": use value from the rightmost map
---@param ... Two or more map-like tables.
+---@param ... Two or more map-like tables.
function vim.tbl_extend(behavior, ...)
return tbl_extend(behavior, false, ...)
end
--- Merges recursively two or more map-like tables.
---
---@see |tbl_extend()|
+---@see |tbl_extend()|
---
---@param behavior Decides what to do if a key is found in more than one map:
+---@param behavior Decides what to do if a key is found in more than one map:
--- - "error": raise an error
--- - "keep": use value from the leftmost map
--- - "force": use value from the rightmost map
---@param ... Two or more map-like tables.
+---@param ... Two or more map-like tables.
function vim.tbl_deep_extend(behavior, ...)
return tbl_extend(behavior, true, ...)
end
--- Deep compare values for equality
+---
+--- Tables are compared recursively unless they both provide the `eq` methamethod.
+--- All other types are compared using the equality `==` operator.
+---@param a first value
+---@param b second value
+---@returns `true` if values are equals, else `false`.
function vim.deep_equal(a, b)
if a == b then return true end
if type(a) ~= type(b) then return false end
if type(a) == 'table' then
- -- TODO improve this algorithm's performance.
for k, v in pairs(a) do
if not vim.deep_equal(v, b[k]) then
return false
end
end
- for k, v in pairs(b) do
- if not vim.deep_equal(v, a[k]) then
+ for k, _ in pairs(b) do
+ if a[k] == nil then
return false
end
end
@@ -286,7 +297,7 @@ end
--- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`
--
--Do note that it *modifies* the input.
---@param o table The table to add the reverse to.
+---@param o table The table to add the reverse to.
function vim.tbl_add_reverse_lookup(o)
local keys = vim.tbl_keys(o)
for _, k in ipairs(keys) do
@@ -303,13 +314,13 @@ end
---
--- NOTE: This mutates dst!
---
---@see |vim.tbl_extend()|
+---@see |vim.tbl_extend()|
---
---@param dst list which will be modified and appended to.
---@param src list from which values will be inserted.
---@param start Start index on src. defaults to 1
---@param finish Final index on src. defaults to #src
---@returns dst
+---@param dst list which will be modified and appended to.
+---@param src list from which values will be inserted.
+---@param start Start index on src. defaults to 1
+---@param finish Final index on src. defaults to #src
+---@returns dst
function vim.list_extend(dst, src, start, finish)
vim.validate {
dst = {dst, 't'};
@@ -326,10 +337,10 @@ end
--- Creates a copy of a list-like table such that any nested tables are
--- "unrolled" and appended to the result.
---
---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t List-like table
---@returns Flattened copy of the given list-like table.
+---@param t List-like table
+---@returns Flattened copy of the given list-like table.
function vim.tbl_flatten(t)
local result = {}
local function _tbl_flatten(_t)
@@ -353,8 +364,8 @@ end
--- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
--- for example from |rpcrequest()| or |vim.fn|.
---
---@param t Table
---@returns `true` if array-like table, else `false`.
+---@param t Table
+---@returns `true` if array-like table, else `false`.
function vim.tbl_islist(t)
if type(t) ~= 'table' then
return false
@@ -389,9 +400,9 @@ end
--- vim.tbl_count({ 1, 2 }) => 2
--- </pre>
---
---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
---@param t Table
---@returns Number that is the number of the value in table
+---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
+---@param t Table
+---@returns Number that is the number of the value in table
function vim.tbl_count(t)
vim.validate{t={t,'t'}}
@@ -402,10 +413,10 @@ end
--- Creates a copy of a table containing only elements from start to end (inclusive)
---
---@param list table table
---@param start integer Start range of slice
---@param finish integer End range of slice
---@returns Copy of table sliced from start to finish (inclusive)
+---@param list table table
+---@param start integer Start range of slice
+---@param finish integer End range of slice
+---@returns Copy of table sliced from start to finish (inclusive)
function vim.list_slice(list, start, finish)
local new_list = {}
for i = start or 1, finish or #list do
@@ -416,9 +427,9 @@ end
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
---
---@see https://www.lua.org/pil/20.2.html
---@param s String to trim
---@returns String with whitespace removed from its beginning and end
+---@see https://www.lua.org/pil/20.2.html
+---@param s String to trim
+---@returns String with whitespace removed from its beginning and end
function vim.trim(s)
vim.validate{s={s,'s'}}
return s:match('^%s*(.*%S)') or ''
@@ -426,9 +437,9 @@ end
--- Escapes magic chars in a Lua pattern.
---
---@see https://github.com/rxi/lume
---@param s String to escape
---@returns %-escaped pattern string
+---@see https://github.com/rxi/lume
+---@param s String to escape
+---@returns %-escaped pattern string
function vim.pesc(s)
vim.validate{s={s,'s'}}
return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')
@@ -436,9 +447,9 @@ end
--- Tests if `s` starts with `prefix`.
---
---@param s (string) a string
---@param prefix (string) a prefix
---@return (boolean) true if `prefix` is a prefix of s
+---@param s (string) a string
+---@param prefix (string) a prefix
+---@return (boolean) true if `prefix` is a prefix of s
function vim.startswith(s, prefix)
vim.validate { s = {s, 's'}; prefix = {prefix, 's'}; }
return s:sub(1, #prefix) == prefix
@@ -446,9 +457,9 @@ end
--- Tests if `s` ends with `suffix`.
---
---@param s (string) a string
---@param suffix (string) a suffix
---@return (boolean) true if `suffix` is a suffix of s
+---@param s (string) a string
+---@param suffix (string) a suffix
+---@return (boolean) true if `suffix` is a suffix of s
function vim.endswith(s, suffix)
vim.validate { s = {s, 's'}; suffix = {suffix, 's'}; }
return #suffix == 0 or s:sub(-#suffix) == suffix
@@ -480,7 +491,7 @@ end
--- => error('arg1: expected even number, got 3')
--- </pre>
---
---@param opt Map of parameter names to validations. Each key is a parameter
+---@param opt Map of parameter names to validations. 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
@@ -564,8 +575,8 @@ do
end
--- Returns true if object `f` can be called as a function.
---
---@param f Any object
---@return true if `f` is callable, else false
+---@param f Any object
+---@return true if `f` is callable, else false
function vim.is_callable(f)
if type(f) == 'function' then return true end
local m = getmetatable(f)