feat(lua): use callable table as iterator in vim.iter (#23957)

A table passed to `vim.iter` can be a class instance with a `__call`
implementation for the iterator protocol.
This commit is contained in:
Mathias Fußenegger 2023-06-10 20:33:23 +02:00 committed by GitHub
parent b302da9ad2
commit 302d3cfb96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 0 deletions

View File

@ -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

View File

@ -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:
--- <pre>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" }
--- </pre>
---
--- 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

View File

@ -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