diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 91d18bbe85..44682d40e5 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -2999,6 +2999,8 @@ pipeline depend on the type passed to this function: • Non-list tables pass both the key and value of each element • Function iterators pass all of the values returned by their respective function +• Tables with a metatable implementing __call are treated as function + iterators Examples: >lua @@ -3032,6 +3034,12 @@ Examples: >lua end) -- true + local rb = vim.ringbuf(3) + rb:push("a") + rb:push("b") + vim.iter(rb):totable() + -- { "a", "b" } + < In addition to the |vim.iter()| function, the |vim.iter| module provides diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index 0e98d0437e..204d22b9be 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -14,6 +14,8 @@ --- - Non-list tables pass both the key and value of each element --- - Function iterators pass all of the values returned by their respective --- function +--- - Tables with a metatable implementing __call are treated as function +--- iterators --- --- Examples: ---
lua
@@ -46,6 +48,12 @@
 ---     return k == 'z'
 ---   end)
 ---   -- true
+---
+---   local rb = vim.ringbuf(3)
+---   rb:push("a")
+---   rb:push("b")
+---   vim.iter(rb):totable()
+---   -- { "a", "b" }
 --- 
--- --- In addition to the |vim.iter()| function, the |vim.iter| module provides @@ -889,6 +897,17 @@ end function Iter.new(src, ...) local it = {} if type(src) == 'table' then + local mt = getmetatable(src) + if mt and type(mt.__call) == 'function' then + ---@private + function it.next() + return src() + end + + setmetatable(it, Iter) + return it + end + local t = {} -- Check if source table can be treated like a list (indices are consecutive integers diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua index 6e1ecc2f7e..3b603c9911 100644 --- a/test/functional/lua/iter_spec.lua +++ b/test/functional/lua/iter_spec.lua @@ -4,6 +4,15 @@ local matches = helpers.matches local pcall_err = helpers.pcall_err describe('vim.iter', function() + it('new() on iterable class instance', function() + local rb = vim.ringbuf(3) + rb:push("a") + rb:push("b") + + local it = vim.iter(rb) + eq({"a", "b"}, it:totable()) + end) + it('filter()', function() local function odd(v) return v % 2 ~= 0