refactor(iter): move helper functions under vim.iter

vim.iter is now both a function and a module (similar to vim.version).
This commit is contained in:
Gregory Anders 2023-04-24 19:57:40 -06:00
parent 147bb87245
commit 1e73891d69
5 changed files with 214 additions and 230 deletions

View File

@ -1653,26 +1653,6 @@ endswith({s}, {suffix}) *vim.endswith()*
Return: ~
(boolean) `true` if `suffix` is a suffix of `s`
filter({f}, {src}, {...}) *vim.filter()*
Filter a table or iterator.
This is a convenience function that performs: >lua
vim.iter(src):filter(f):totable()
<
Parameters: ~
• {f} function(...):bool Filter function. Accepts the current
iterator or table values as arguments and returns true if those
values should be kept in the final table
• {src} table|function Table or iterator function to filter
Return: ~
(table)
See also: ~
• |Iter:filter()|
gsplit({s}, {sep}, {opts}) *vim.gsplit()*
Splits a string at each instance of a separator.
@ -1718,64 +1698,6 @@ is_callable({f}) *vim.is_callable()*
Return: ~
(boolean) `true` if `f` is callable, else `false`
iter({src}, {...}) *vim.iter()*
Create an Iter |lua-iter| object from a table or iterator.
The input value can be a table or a function iterator (see |luaref-in|).
This function wraps the input value into an interface which allows
chaining multiple pipeline stages in an efficient manner. Each pipeline
stage receives as input the output values from the prior stage. The values
used in the first stage of the pipeline depend on the type passed to this
function:
• List tables pass only the value of each element
• Non-list tables pass both the key and value of each element
• Function iterators pass all of the values returned by their respective
function
Examples: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 })
it:map(function(v)
return v * 3
end)
it:rev()
it:skip(2)
it:totable()
-- { 9, 6, 3 }
vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
if i > 2 then return v end
end):totable()
-- { 3, 4, 5 }
local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
it:map(function(s) return tonumber(s) end)
for i, d in it:enumerate() do
print(string.format("Column %d is %d", i, d))
end
-- Column 1 is 1
-- Column 2 is 2
-- Column 3 is 3
-- Column 4 is 4
-- Column 5 is 5
vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
return k == 'z'
end)
-- true
<
Parameters: ~
• {src} table|function Table or iterator.
Return: ~
Iter |lua-iter|
See also: ~
• |lua-iter|
list_contains({t}, {value}) *vim.list_contains()*
Checks if a list-like table (integer keys without gaps) contains `value`.
@ -1818,26 +1740,6 @@ list_slice({list}, {start}, {finish}) *vim.list_slice()*
Return: ~
(list) Copy of table sliced from start to finish (inclusive)
map({f}, {src}, {...}) *vim.map()*
Map and filter a table or iterator.
This is a convenience function that performs: >lua
vim.iter(src):map(f):totable()
<
Parameters: ~
• {f} function(...):?any Map function. Accepts the current iterator
or table values as arguments and returns one or more new
values. Nil values are removed from the final table.
• {src} table|function Table or iterator function to filter
Return: ~
(table)
See also: ~
• |Iter:map()|
pesc({s}) *vim.pesc()*
Escapes magic chars in |lua-patterns|.
@ -2099,20 +2001,6 @@ tbl_values({t}) *vim.tbl_values()*
Return: ~
(list) List of values
totable({f}, {...}) *vim.totable()*
Collect an iterator into a table.
This is a convenience function that performs: >lua
vim.iter(f):totable()
<
Parameters: ~
• {f} (function) Iterator function
Return: ~
(table)
trim({s}) *vim.trim()*
Trim whitespace (Lua pattern "%s") from both sides of a string.
@ -2933,6 +2821,79 @@ range({spec}) *vim.version.range()*
==============================================================================
Lua module: iter *lua-iter*
The *vim.iter* module provides a generic "iterator" interface over tables
and iterator functions.
*vim.iter()* wraps its table or function argument into an *Iter* object
with methods (such as |Iter:filter()| and |Iter:map()|) that transform the
underlying source data. These methods can be chained together to create
iterator "pipelines". Each pipeline stage receives as input the output
values from the prior stage. The values used in the first stage of the
pipeline depend on the type passed to this function:
• List tables pass only the value of each element
• Non-list tables pass both the key and value of each element
• Function iterators pass all of the values returned by their respective
function
Examples: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 })
it:map(function(v)
return v * 3
end)
it:rev()
it:skip(2)
it:totable()
-- { 9, 6, 3 }
vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
if i > 2 then return v end
end):totable()
-- { 3, 4, 5 }
local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
it:map(function(s) return tonumber(s) end)
for i, d in it:enumerate() do
print(string.format("Column %d is %d", i, d))
end
-- Column 1 is 1
-- Column 2 is 2
-- Column 3 is 3
-- Column 4 is 4
-- Column 5 is 5
vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
return k == 'z'
end)
-- true
<
In addition to the |vim.iter()| function, the |vim.iter| module provides
convenience functions like |vim.iter.filter()| and |vim.iter.totable()|.
filter({f}, {src}, {...}) *vim.iter.filter()*
Filter a table or iterator.
This is a convenience function that performs: >lua
vim.iter(src):filter(f):totable()
<
Parameters: ~
• {f} function(...):bool Filter function. Accepts the current
iterator or table values as arguments and returns true if those
values should be kept in the final table
• {src} table|function Table or iterator function to filter
Return: ~
(table)
See also: ~
• |Iter:filter()|
Iter:all({self}, {pred}) *Iter:all()*
Return true if all of the items in the iterator match the given predicate.
@ -2971,9 +2932,7 @@ Iter:enumerate({self}) *Iter:enumerate()*
vim.iter(ipairs(t))
<
over
>lua
over >lua
vim.iter(t):enumerate()
<
@ -3331,16 +3290,38 @@ Iter:totable({self}) *Iter:totable()*
Return: ~
(table)
new({src}, {...}) *new()*
Create a new Iter object from a table or iterator.
map({f}, {src}, {...}) *vim.iter.map()*
Map and filter a table or iterator.
This is a convenience function that performs: >lua
vim.iter(src):map(f):totable()
<
Parameters: ~
• {src} table|function Table or iterator to drain values from
• {f} function(...):?any Map function. Accepts the current iterator
or table values as arguments and returns one or more new
values. Nil values are removed from the final table.
• {src} table|function Table or iterator function to filter
Return: ~
Iter
(table)
next() *next()*
TODO: Documentation
See also: ~
• |Iter:map()|
totable({f}, {...}) *vim.iter.totable()*
Collect an iterator into a table.
This is a convenience function that performs: >lua
vim.iter(f):totable()
<
Parameters: ~
• {f} (function) Iterator function
Return: ~
(table)
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@ -55,6 +55,7 @@ vim._submodules = {
inspect = true,
version = true,
fs = true,
iter = true,
}
-- These are for loading runtime modules in the vim namespace lazily.

View File

@ -1,4 +1,56 @@
--- Iterator implementation.
---@defgroup lua-iter
---
--- The \*vim.iter\* module provides a generic "iterator" interface over tables and iterator
--- functions.
---
--- \*vim.iter()\* wraps its table or function argument into an \*Iter\* object with methods (such
--- as |Iter:filter()| and |Iter:map()|) that transform the underlying source data. These methods
--- can be chained together to create iterator "pipelines". Each pipeline stage receives as input
--- the output values from the prior stage. The values used in the first stage of the pipeline
--- depend on the type passed to this function:
---
--- - List tables pass only the value of each element
--- - Non-list tables pass both the key and value of each element
--- - Function iterators pass all of the values returned by their respective
--- function
---
--- Examples:
--- <pre>lua
--- local it = vim.iter({ 1, 2, 3, 4, 5 })
--- it:map(function(v)
--- return v * 3
--- end)
--- it:rev()
--- it:skip(2)
--- it:totable()
--- -- { 9, 6, 3 }
---
--- vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
--- if i > 2 then return v end
--- end):totable()
--- -- { 3, 4, 5 }
---
--- local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
--- it:map(function(s) return tonumber(s) end)
--- for i, d in it:enumerate() do
--- print(string.format("Column %d is %d", i, d))
--- end
--- -- Column 1 is 1
--- -- Column 2 is 2
--- -- Column 3 is 3
--- -- Column 4 is 4
--- -- Column 5 is 5
---
--- vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
--- return k == 'z'
--- end)
--- -- true
--- </pre>
---
--- In addition to the |vim.iter()| function, the |vim.iter| module provides convenience functions
--- like |vim.iter.filter()| and |vim.iter.totable()|.
local M = {}
---@class Iter
local Iter = {}
@ -733,7 +785,6 @@ end
--- </pre>
---
--- over
---
--- <pre>lua
--- vim.iter(t):enumerate()
--- </pre>
@ -776,6 +827,7 @@ end
---
---@param src table|function Table or iterator to drain values from
---@return Iter
---@private
function Iter.new(src, ...)
local it = {}
if type(src) == 'table' then
@ -807,6 +859,7 @@ function Iter.new(src, ...)
end
end
---@private
function it.next()
return fn(src(s, var))
end
@ -832,4 +885,57 @@ function ListIter.new(t)
return it
end
return Iter
--- Collect an iterator into a table.
---
--- This is a convenience function that performs:
--- <pre>lua
--- vim.iter(f):totable()
--- </pre>
---
---@param f function Iterator function
---@return table
function M.totable(f, ...)
return Iter.new(f, ...):totable()
end
--- Filter a table or iterator.
---
--- This is a convenience function that performs:
--- <pre>lua
--- vim.iter(src):filter(f):totable()
--- </pre>
---
---@see |Iter:filter()|
---
---@param f function(...):bool Filter function. Accepts the current iterator or table values as
--- arguments and returns true if those values should be kept in the
--- final table
---@param src table|function Table or iterator function to filter
---@return table
function M.filter(f, src, ...)
return Iter.new(src, ...):filter(f):totable()
end
--- Map and filter a table or iterator.
---
--- This is a convenience function that performs:
--- <pre>lua
--- vim.iter(src):map(f):totable()
--- </pre>
---
---@see |Iter:map()|
---
---@param f function(...):?any Map function. Accepts the current iterator or table values as
--- arguments and returns one or more new values. Nil values are removed
--- from the final table.
---@param src table|function Table or iterator function to filter
---@return table
function M.map(f, src, ...)
return Iter.new(src, ...):map(f):totable()
end
return setmetatable(M, {
__call = function(_, ...)
return Iter.new(...)
end,
})

View File

@ -881,109 +881,4 @@ function vim.defaulttable(create)
})
end
--- Create an Iter |lua-iter| object from a table or iterator.
---
--- The input value can be a table or a function iterator (see |luaref-in|).
---
--- This function wraps the input value into an interface which allows chaining
--- multiple pipeline stages in an efficient manner. Each pipeline stage
--- receives as input the output values from the prior stage. The values used in
--- the first stage of the pipeline depend on the type passed to this function:
---
--- - List tables pass only the value of each element
--- - Non-list tables pass both the key and value of each element
--- - Function iterators pass all of the values returned by their respective
--- function
---
--- Examples:
--- <pre>lua
--- local it = vim.iter({ 1, 2, 3, 4, 5 })
--- it:map(function(v)
--- return v * 3
--- end)
--- it:rev()
--- it:skip(2)
--- it:totable()
--- -- { 9, 6, 3 }
---
--- vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
--- if i > 2 then return v end
--- end):totable()
--- -- { 3, 4, 5 }
---
--- local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
--- it:map(function(s) return tonumber(s) end)
--- for i, d in it:enumerate() do
--- print(string.format("Column %d is %d", i, d))
--- end
--- -- Column 1 is 1
--- -- Column 2 is 2
--- -- Column 3 is 3
--- -- Column 4 is 4
--- -- Column 5 is 5
---
--- vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
--- return k == 'z'
--- end)
--- -- true
--- </pre>
---
---@see |lua-iter|
---
---@param src table|function Table or iterator.
---@return Iter @|lua-iter|
function vim.iter(src, ...)
local Iter = require('vim.iter')
return Iter.new(src, ...)
end
--- Collect an iterator into a table.
---
--- This is a convenience function that performs:
--- <pre>lua
--- vim.iter(f):totable()
--- </pre>
---
---@param f function Iterator function
---@return table
function vim.totable(f, ...)
return vim.iter(f, ...):totable()
end
--- Filter a table or iterator.
---
--- This is a convenience function that performs:
--- <pre>lua
--- vim.iter(src):filter(f):totable()
--- </pre>
---
---@see |Iter:filter()|
---
---@param f function(...):bool Filter function. Accepts the current iterator or table values as
--- arguments and returns true if those values should be kept in the
--- final table
---@param src table|function Table or iterator function to filter
---@return table
function vim.filter(f, src, ...)
return vim.iter(src, ...):filter(f):totable()
end
--- Map and filter a table or iterator.
---
--- This is a convenience function that performs:
--- <pre>lua
--- vim.iter(src):map(f):totable()
--- </pre>
---
---@see |Iter:map()|
---
---@param f function(...):?any Map function. Accepts the current iterator or table values as
--- arguments and returns one or more new values. Nil values are removed
--- from the final table.
---@param src table|function Table or iterator function to filter
---@return table
function vim.map(f, src, ...)
return vim.iter(src, ...):map(f):totable()
end
return vim

View File

@ -188,7 +188,7 @@ CONFIG = {
f'*vim.{name}()*'
if fstem.lower() == '_editor'
else f'*{name}()*'
if fstem in ('iter.lua')
if name[0].isupper()
else f'*{fstem}.{name}()*'),
'module_override': {
# `shared` functions are exposed on the `vim` module.
@ -202,6 +202,7 @@ CONFIG = {
'fs': 'vim.fs',
'secure': 'vim.secure',
'version': 'vim.version',
'iter': 'vim.iter',
},
'append_only': [
'shared.lua',