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: ~ Return: ~
(boolean) `true` if `suffix` is a suffix of `s` (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()* gsplit({s}, {sep}, {opts}) *vim.gsplit()*
Splits a string at each instance of a separator. Splits a string at each instance of a separator.
@@ -1718,64 +1698,6 @@ is_callable({f}) *vim.is_callable()*
Return: ~ Return: ~
(boolean) `true` if `f` is callable, else `false` (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()* list_contains({t}, {value}) *vim.list_contains()*
Checks if a list-like table (integer keys without gaps) contains `value`. 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: ~ Return: ~
(list) Copy of table sliced from start to finish (inclusive) (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()* pesc({s}) *vim.pesc()*
Escapes magic chars in |lua-patterns|. Escapes magic chars in |lua-patterns|.
@@ -2099,20 +2001,6 @@ tbl_values({t}) *vim.tbl_values()*
Return: ~ Return: ~
(list) List of values (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({s}) *vim.trim()*
Trim whitespace (Lua pattern "%s") from both sides of a string. 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* 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()* Iter:all({self}, {pred}) *Iter:all()*
Return true if all of the items in the iterator match the given predicate. 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)) vim.iter(ipairs(t))
< <
over over >lua
>lua
vim.iter(t):enumerate() vim.iter(t):enumerate()
< <
@@ -3331,16 +3290,38 @@ Iter:totable({self}) *Iter:totable()*
Return: ~ Return: ~
(table) (table)
new({src}, {...}) *new()* map({f}, {src}, {...}) *vim.iter.map()*
Create a new Iter object from a table or iterator. Map and filter a table or iterator.
This is a convenience function that performs: >lua
vim.iter(src):map(f):totable()
<
Parameters: ~ 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: ~ Return: ~
Iter (table)
next() *next()* See also: ~
TODO: Documentation • |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: vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:

View File

@@ -55,6 +55,7 @@ vim._submodules = {
inspect = true, inspect = true,
version = true, version = true,
fs = true, fs = true,
iter = true,
} }
-- These are for loading runtime modules in the vim namespace lazily. -- 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 ---@class Iter
local Iter = {} local Iter = {}
@@ -733,7 +785,6 @@ end
--- </pre> --- </pre>
--- ---
--- over --- over
---
--- <pre>lua --- <pre>lua
--- vim.iter(t):enumerate() --- vim.iter(t):enumerate()
--- </pre> --- </pre>
@@ -776,6 +827,7 @@ end
--- ---
---@param src table|function Table or iterator to drain values from ---@param src table|function Table or iterator to drain values from
---@return Iter ---@return Iter
---@private
function Iter.new(src, ...) function Iter.new(src, ...)
local it = {} local it = {}
if type(src) == 'table' then if type(src) == 'table' then
@@ -807,6 +859,7 @@ function Iter.new(src, ...)
end end
end end
---@private
function it.next() function it.next()
return fn(src(s, var)) return fn(src(s, var))
end end
@@ -832,4 +885,57 @@ function ListIter.new(t)
return it return it
end 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 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 return vim

View File

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