aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/lua.txt6
-rw-r--r--runtime/doc/news.txt3
-rw-r--r--runtime/lua/vim/shared.lua13
-rw-r--r--test/functional/lua/vim_spec.lua7
4 files changed, 21 insertions, 8 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 0a7c53a482..0beee1507a 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -2230,6 +2230,12 @@ vim.tbl_count({t}) *vim.tbl_count()*
vim.tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()*
Merges recursively two or more tables.
+ Only values that are empty tables or tables that are not |lua-list|s
+ (indexed by consecutive integers starting from 1) are merged recursively.
+ This is useful for merging nested tables like default and user
+ configurations where lists should be treated as literals (i.e., are
+ overwritten instead of merged).
+
Parameters: ~
• {behavior} (`'error'|'keep'|'force'`) Decides what to do if a key is
found in more than one map:
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index ff41238912..bc1b9487b7 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -214,9 +214,6 @@ These existing features changed their behavior.
more emoji characters than before, including those encoded with multiple
emoji codepoints combined with ZWJ (zero width joiner) codepoints.
-• |vim.tbl_deep_extend()| no longer ignores any values for which |vim.isarray()|
- returns `true`.
-
==============================================================================
REMOVED FEATURES *news-removed*
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 2f10380bad..4d06cdd77d 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -354,6 +354,12 @@ function vim.tbl_isempty(t)
return next(t) == nil
end
+--- We only merge empty tables or tables that are not list-like (indexed by consecutive integers
+--- starting from 1)
+local function can_merge(v)
+ return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.islist(v))
+end
+
--- Recursive worker for tbl_extend
--- @param behavior 'error'|'keep'|'force'
--- @param deep_extend boolean
@@ -368,7 +374,7 @@ local function tbl_extend_rec(behavior, deep_extend, ...)
local tbl = select(i, ...) --[[@as table<any,any>]]
if tbl then
for k, v in pairs(tbl) do
- if deep_extend and type(v) == 'table' and type(ret[k]) == 'table' then
+ if deep_extend and can_merge(v) and can_merge(ret[k]) then
ret[k] = tbl_extend_rec(behavior, true, ret[k], v)
elseif behavior ~= 'force' and ret[k] ~= nil then
if behavior == 'error' then
@@ -421,6 +427,11 @@ end
--- Merges recursively two or more tables.
---
+--- Only values that are empty tables or tables that are not |lua-list|s (indexed by consecutive
+--- integers starting from 1) are merged recursively. This is useful for merging nested tables
+--- like default and user configurations where lists should be treated as literals (i.e., are
+--- overwritten instead of merged).
+---
---@see |vim.tbl_extend()|
---
---@generic T1: table
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 7f10dcd8da..599b688bf4 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -1071,12 +1071,11 @@ describe('lua stdlib', function()
]])
)
- -- Fix github issue #23654
ok(exec_lua([[
- local a = { sub = { [1] = 'a' } }
- local b = { sub = { b = 'a' } }
+ local a = { sub = { 'a', 'b' } }
+ local b = { sub = { 'b', 'c' } }
local c = vim.tbl_deep_extend('force', a, b)
- return vim.deep_equal(c, { sub = { [1] = 'a', b = 'a' } })
+ return vim.deep_equal(c, { sub = { 'b', 'c' } })
]]))
matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]]))