aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/lua/vim/shared.lua19
-rw-r--r--test/functional/lua/vim_spec.lua14
2 files changed, 23 insertions, 10 deletions
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 6e40b6ca52..bf77f0c776 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -12,7 +12,7 @@ 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
+---@param orig table Table to copy
---@returns New table of copied keys and (nested) values.
function vim.deepcopy(orig) end -- luacheck: no unused
vim.deepcopy = (function()
@@ -21,17 +21,16 @@ vim.deepcopy = (function()
end
local deepcopy_funcs = {
- table = function(orig)
+ table = function(orig, cache)
+ if cache[orig] then return cache[orig] end
local copy = {}
- if vim._empty_dict_mt ~= nil and getmetatable(orig) == vim._empty_dict_mt then
- copy = vim.empty_dict()
- end
-
+ cache[orig] = copy
+ local mt = getmetatable(orig)
for k, v in pairs(orig) do
- copy[vim.deepcopy(k)] = vim.deepcopy(v)
+ copy[vim.deepcopy(k, cache)] = vim.deepcopy(v, cache)
end
- return copy
+ return setmetatable(copy, mt)
end,
number = _id,
string = _id,
@@ -40,10 +39,10 @@ vim.deepcopy = (function()
['function'] = _id,
}
- return function(orig)
+ return function(orig, cache)
local f = deepcopy_funcs[type(orig)]
if f then
- return f(orig)
+ return f(orig, cache or {})
else
error("Cannot deepcopy object of type "..type(orig))
end
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 3832d27a22..28471bdd46 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -396,6 +396,20 @@ describe('lua stdlib', function()
return t1.f() ~= t2.f()
]]))
+ ok(exec_lua([[
+ local t1 = {a = 5}
+ t1.self = t1
+ local t2 = vim.deepcopy(t1)
+ return t2.self == t2 and t2.self ~= t1
+ ]]))
+
+ ok(exec_lua([[
+ local mt = {mt=true}
+ local t1 = setmetatable({a = 5}, mt)
+ local t2 = vim.deepcopy(t1)
+ return getmetatable(t2) == mt
+ ]]))
+
eq('Error executing lua: vim/shared.lua:0: Cannot deepcopy object of type thread',
pcall_err(exec_lua, [[
local thread = coroutine.create(function () return 0 end)