aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNAKAI Tsuyoshi <82267684+uga-rosa@users.noreply.github.com>2023-04-14 19:01:08 +0900
committerGitHub <noreply@github.com>2023-04-14 12:01:08 +0200
commit7caf0eafd83b5a92f2ff219b3a64ffae4174b9af (patch)
tree5ef258ecfc37e9df9dc5951a2cccc4d30a8dc573
parent33e90f513851c91325a016a1303c004a1388a170 (diff)
downloadrneovim-7caf0eafd83b5a92f2ff219b3a64ffae4174b9af.tar.gz
rneovim-7caf0eafd83b5a92f2ff219b3a64ffae4174b9af.tar.bz2
rneovim-7caf0eafd83b5a92f2ff219b3a64ffae4174b9af.zip
feat(lua)!: add stricter vim.tbl_islist() and rename old one to vim.tbl_isarray() (#16440)
feat(lua)!: add stricter vim.tbl_islist(), rename vim.tbl_isarray() Problem: `vim.tbl_islist` allows gaps in tables with integer keys ("arrays"). Solution: Rename `vim.tbl_islist` to `vim.tbl_isarray`, add new `vim.tbl.islist` that checks for consecutive integer keys that start from 1.
-rw-r--r--runtime/doc/lua.txt23
-rw-r--r--runtime/doc/news.txt5
-rw-r--r--runtime/lua/vim/shared.lua47
-rw-r--r--test/functional/lua/vim_spec.lua16
4 files changed, 80 insertions, 11 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index f39adf4f8d..6fdf3775f6 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1928,6 +1928,20 @@ tbl_get({o}, {...}) *vim.tbl_get()*
Return: ~
any Nested value indexed by key (if it exists), else nil
+tbl_isarray({t}) *vim.tbl_isarray()*
+ Tests if a Lua table can be treated as an array (a table indexed by
+ integers).
+
+ 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|.
+
+ Parameters: ~
+ • {t} (table)
+
+ Return: ~
+ (boolean) `true` if array-like table, else `false`.
+
tbl_isempty({t}) *vim.tbl_isempty()*
Checks if a table is empty.
@@ -1941,17 +1955,18 @@ tbl_isempty({t}) *vim.tbl_isempty()*
• https://github.com/premake/premake-core/blob/master/src/base/table.lua
tbl_islist({t}) *vim.tbl_islist()*
- Tests if a Lua table can be treated as an array.
+ Tests if a Lua table can be treated as a list (a table indexed by
+ consecutive integers starting from 1).
- Empty table `{}` is assumed to be an array, unless it was created by
+ Empty table `{}` is assumed to be an 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|.
Parameters: ~
- • {t} (table) Table
+ • {t} (table)
Return: ~
- (boolean) `true` if array-like table, else `false`
+ (boolean) `true` if list-like table, else `false`.
tbl_keys({t}) *vim.tbl_keys()*
Return a list of all keys used in a table. However, the order of the
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index aff1a4a24e..6697b3018a 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -15,6 +15,11 @@ BREAKING CHANGES *news-breaking*
The following changes may require adaptations in user config or plugins.
+• |vim.tbl_islist()| now checks whether a table is actually list-like (i.e.,
+ has integer keys without gaps and starting from 1). For the previous
+ behavior (only check for integer keys, allow gaps or not starting with 1),
+ use |vim.tbl_isarray()|.
+
• "#" followed by a digit no longer stands for a function key at the start of
the lhs of a mapping.
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 7ecb56eb92..f700f4a6b3 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -320,10 +320,10 @@ function vim.tbl_isempty(t)
return next(t) == nil
end
---- We only merge empty tables or tables that are not a list
+--- We only merge empty tables or tables that are not an array (indexed by integers)
---@private
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, ...)
@@ -554,15 +554,15 @@ function vim.spairs(t)
end
end
---- Tests if a Lua table can be treated as an array.
+--- Tests if a Lua table can be treated as an array (a table indexed by integers).
---
--- 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|.
---
----@param t table Table
----@return boolean `true` if array-like table, else `false`
-function vim.tbl_islist(t)
+---@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
@@ -570,7 +570,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
@@ -589,6 +590,38 @@ function vim.tbl_islist(t)
end
end
+--- Tests if a Lua table can be treated as a list (a table indexed by consecutive integers starting from 1).
+---
+--- Empty table `{}` is assumed to be an 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|.
+---
+---@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
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 6b69018bc0..1ee1a13fd5 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -521,6 +521,19 @@ describe('lua stdlib', function()
]]))
end)
+ it('vim.tbl_isarray', function()
+ eq(true, exec_lua("return vim.tbl_isarray({})"))
+ eq(false, exec_lua("return vim.tbl_isarray(vim.empty_dict())"))
+ eq(true, exec_lua("return vim.tbl_isarray({'a', 'b', 'c'})"))
+ eq(false, exec_lua("return vim.tbl_isarray({'a', '32', a='hello', b='baz'})"))
+ eq(false, exec_lua("return vim.tbl_isarray({1, a='hello', b='baz'})"))
+ eq(false, exec_lua("return vim.tbl_isarray({a='hello', b='baz', 1})"))
+ eq(false, exec_lua("return vim.tbl_isarray({1, 2, nil, a='hello'})"))
+ eq(true, exec_lua("return vim.tbl_isarray({1, 2, nil, 4})"))
+ eq(true, exec_lua("return vim.tbl_isarray({nil, 2, 3, 4})"))
+ eq(false, exec_lua("return vim.tbl_isarray({1, [1.5]=2, [3]=3})"))
+ end)
+
it('vim.tbl_islist', function()
eq(true, exec_lua("return vim.tbl_islist({})"))
eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())"))
@@ -529,6 +542,9 @@ describe('lua stdlib', function()
eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})"))
eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})"))
eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})"))
+ eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, 4})"))
+ eq(false, exec_lua("return vim.tbl_islist({nil, 2, 3, 4})"))
+ eq(false, exec_lua("return vim.tbl_islist({1, [1.5]=2, [3]=3})"))
end)
it('vim.tbl_isempty', function()