diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2023-11-25 06:35:31 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-25 06:35:31 -0800 |
commit | fc4385ad94c0a12d2ce8b6d275d8336a740b04fd (patch) | |
tree | 8f508fca389d7cf5d8ec6fe4c62940af5ecdeda9 | |
parent | 0da62b579fbd3a21c7ab808f1bb10263d469a1e9 (diff) | |
download | rneovim-fc4385ad94c0a12d2ce8b6d275d8336a740b04fd.tar.gz rneovim-fc4385ad94c0a12d2ce8b6d275d8336a740b04fd.tar.bz2 rneovim-fc4385ad94c0a12d2ce8b6d275d8336a740b04fd.zip |
docs: vim.iter #26169
closes #24141
closes #24746
-rw-r--r-- | runtime/doc/develop.txt | 8 | ||||
-rw-r--r-- | runtime/doc/lua.txt | 145 | ||||
-rw-r--r-- | runtime/doc/news.txt | 9 | ||||
-rw-r--r-- | runtime/lua/vim/iter.lua | 117 |
4 files changed, 129 insertions, 150 deletions
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index 107915d017..f1d74326c7 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -288,7 +288,13 @@ Interface conventions ~ - When accepting a buffer id, etc., 0 means "current buffer", nil means "all buffers". Likewise for window id, tabpage id, etc. - Examples: |vim.lsp.codelens.clear()| |vim.diagnostic.enable()| - +- Any function signature that accepts a callback function should define the + callback as the LAST parameter, if possible. This improves readability of + calls by placing the less "noisy" arguments near the start. > + GOOD: + filter(table, opts, function() … end) + BAD: + filter(function() … end, table, opts) API DESIGN GUIDELINES *dev-api* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index b155e646ab..a79b26dfb0 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -70,17 +70,23 @@ https://www.lua.org/doc/cacm2018.pdf - Stackful coroutines enable cooperative multithreading, generators, and versatile control for both Lua and its host (Nvim). - *iterator* + *iterator* An iterator is just a function that can be called repeatedly to get the "next" value of a collection (or any other |iterable|). This interface is expected by |for-in| loops, produced by |pairs()|, supported by |vim.iter|, etc. https://www.lua.org/pil/7.1.html - *iterable* + *iterable* An "iterable" is anything that |vim.iter()| can consume: tables, dicts, lists, iterator functions, tables implementing the |__call()| metamethod, and |vim.iter()| objects. + *list-iterator* +Iterators on |lua-list| tables have a "middle" and "end", whereas iterators in +general may be logically infinite. Therefore some |vim.iter| operations (e.g. +|Iter:rev()|) make sense only on list-like tables (which are finite by +definition). + *lua-function-call* Lua functions can be called in multiple ways. Consider the function: >lua local foo = function(a, b) @@ -332,8 +338,8 @@ Additionally Lua does not have integer numbers. To distinguish between these cases there is the following agreement: *lua-list* 0. Empty table is empty list. -1. Table with N incrementally growing integral numbers, starting from 1 and - ending with N is considered to be a list. +1. Table with N consecutive integer indices starting from 1 and ending with + N is considered a list. See also |list-iterator|. *lua-dict* 2. Table with string keys, none of which contains NUL byte, is considered to be a dictionary. @@ -3205,22 +3211,27 @@ Lua module: vim.iter *vim.iter* *vim.iter()* is an interface for |iterable|s: it wraps a 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 (arrays) pass only the value of each element -• Non-list tables (dictionaries) pass both the key and value of each - element -• Function |iterator|s pass all of the values returned by their respective - function -• Tables with a metatable implementing |__call()| are treated as function - iterators - -The iterator pipeline terminates when the original table or function -iterator runs out of values (for function iterators, this means that the -first value returned by the function is nil). +be chained to create iterator "pipelines": the output of each pipeline +stage is input to the next stage. The first stage depends on the type +passed to `vim.iter()`: + +• List tables (arrays, |lua-list|) yield only the value of each element. + • Use |Iter:enumerate()| to also pass the index to the next stage. + • Or initialize with ipairs(): `vim.iter(ipairs(…))`. + +• Non-list tables (|lua-dict|) yield both the key and value of each + element. +• Function |iterator|s yield all values returned by the underlying + function. +• Tables with a |__call()| metamethod are treated as function iterators. + +The iterator pipeline terminates when the underlying |iterable| is +exhausted (for function iterators this means it returned nil). + +Note: `vim.iter()` scans table input to decide if it is a list or a dict; +to avoid this cost you can wrap the table with an iterator e.g. +`vim.iter(ipairs({…}))`, but that precludes the use of |list-iterator| +operations such as |Iter:rev()|). Examples: >lua local it = vim.iter({ 1, 2, 3, 4, 5 }) @@ -3266,9 +3277,8 @@ 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 + Filters a table or other |iterable|. >lua + -- Equivalent to: vim.iter(src):filter(f):totable() < @@ -3285,7 +3295,7 @@ filter({f}, {src}, {...}) *vim.iter.filter()* • |Iter:filter()| Iter:all({pred}) *Iter:all()* - Return true if all of the items in the iterator match the given predicate. + Returns true if all items in the iterator match the given predicate. Parameters: ~ • {pred} function(...):bool Predicate function. Takes all values @@ -3293,7 +3303,8 @@ Iter:all({pred}) *Iter:all()* and returns true if the predicate matches. Iter:any({pred}) *Iter:any()* - Return true if any of the items in the iterator match the given predicate. + Returns true if any of the items in the iterator match the given + predicate. Parameters: ~ • {pred} function(...):bool Predicate function. Takes all values @@ -3301,12 +3312,11 @@ Iter:any({pred}) *Iter:any()* and returns true if the predicate matches. Iter:each({f}) *Iter:each()* - Call a function once for each item in the pipeline. - - This is used for functions which have side effects. To modify the values - in the iterator, use |Iter:map()|. + Calls a function once for each item in the pipeline, draining the + iterator. - This function drains the iterator. + For functions with side effects. To modify the values in the iterator, use + |Iter:map()|. Parameters: ~ • {f} function(...) Function to execute for each item in the pipeline. @@ -3314,19 +3324,17 @@ Iter:each({f}) *Iter:each()* pipeline as arguments. Iter:enumerate() *Iter:enumerate()* - Add an iterator stage that returns the current iterator count as well as - the iterator value. + Yields the item index (count) and value for each item of an iterator + pipeline. - For list tables, prefer >lua + For list tables, this is more efficient: >lua vim.iter(ipairs(t)) < - over >lua + instead of: >lua vim.iter(t):enumerate() < - as the former is faster. - Example: >lua local it = vim.iter(vim.gsplit('abc', '')):enumerate() it:next() @@ -3341,7 +3349,7 @@ Iter:enumerate() *Iter:enumerate()* Iter Iter:filter({f}) *Iter:filter()* - Add a filter step to the iterator pipeline. + Filters an iterator pipeline. Example: >lua local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded) @@ -3379,7 +3387,7 @@ Iter:find({f}) *Iter:find()* any Iter:fold({init}, {f}) *Iter:fold()* - Fold ("reduce") an iterator or table into a single value. + Folds ("reduces") an iterator into a single value. Examples: >lua -- Create a new table with only even values @@ -3401,9 +3409,7 @@ Iter:fold({init}, {f}) *Iter:fold()* any Iter:last() *Iter:last()* - Return the last item in the iterator. - - Drains the iterator. + Drains the iterator and returns the last item. Example: >lua local it = vim.iter(vim.gsplit('abcdefg', '')) @@ -3419,7 +3425,7 @@ Iter:last() *Iter:last()* any Iter:map({f}) *Iter:map()* - Add a map step to the iterator pipeline. + Maps the items of an iterator pipeline to the values returned by `f`. If the map function returns nil, the value is filtered from the iterator. @@ -3443,7 +3449,7 @@ Iter:map({f}) *Iter:map()* Iter Iter:next() *Iter:next()* - Return the next value from the iterator. + Gets the next value from the iterator. Example: >lua local it = vim.iter(string.gmatch('1 2 3', '%d+')):map(tonumber) @@ -3459,9 +3465,8 @@ Iter:next() *Iter:next()* any Iter:nextback() *Iter:nextback()* - Return the next value from the end of the iterator. - - Only supported for iterators on list-like tables. + "Pops" a value from a |list-iterator| (gets the last value and decrements + the tail). Example: >lua local it = vim.iter({1, 2, 3, 4}) @@ -3475,9 +3480,7 @@ Iter:nextback() *Iter:nextback()* any Iter:nth({n}) *Iter:nth()* - Return the nth value in the iterator. - - This function advances the iterator. + Gets the nth value of an iterator (and advances to it). Example: >lua local it = vim.iter({ 3, 6, 9, 12 }) @@ -3494,11 +3497,7 @@ Iter:nth({n}) *Iter:nth()* any Iter:nthback({n}) *Iter:nthback()* - Return the nth value from the end of the iterator. - - This function advances the iterator. - - Only supported for iterators on list-like tables. + Gets the nth value from the end of a |list-iterator| (and advances to it). Example: >lua local it = vim.iter({ 3, 6, 9, 12 }) @@ -3515,9 +3514,7 @@ Iter:nthback({n}) *Iter:nthback()* any Iter:peek() *Iter:peek()* - Peek at the next value in the iterator without consuming it. - - Only supported for iterators on list-like tables. + Gets the next value in a |list-iterator| without consuming it. Example: >lua local it = vim.iter({ 3, 6, 9, 12 }) @@ -3533,9 +3530,9 @@ Iter:peek() *Iter:peek()* any Iter:peekback() *Iter:peekback()* - Return the next value from the end of the iterator without consuming it. + Gets the last value of a |list-iterator| without consuming it. - Only supported for iterators on list-like tables. + See also |Iter:last()|. Example: >lua local it = vim.iter({1, 2, 3, 4}) @@ -3551,9 +3548,7 @@ Iter:peekback() *Iter:peekback()* any Iter:rev() *Iter:rev()* - Reverse an iterator. - - Only supported for iterators on list-like tables. + Reverses a |list-iterator| pipeline. Example: >lua local it = vim.iter({ 3, 6, 9, 12 }):rev() @@ -3565,14 +3560,12 @@ Iter:rev() *Iter:rev()* Iter Iter:rfind({f}) *Iter:rfind()* - Find the first value in the iterator that satisfies the given predicate, + Gets the first value in a |list-iterator| that satisfies a predicate, starting from the end. Advances the iterator. Returns nil and drains the iterator if no value is found. - Only supported for iterators on list-like tables. - Examples: >lua local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate() it:rfind(1) @@ -3588,7 +3581,7 @@ Iter:rfind({f}) *Iter:rfind()* • Iter.find Iter:skip({n}) *Iter:skip()* - Skip values in the iterator. + Skips `n` values of an iterator pipeline. Example: >lua local it = vim.iter({ 3, 6, 9, 12 }):skip(2) @@ -3603,9 +3596,7 @@ Iter:skip({n}) *Iter:skip()* Iter Iter:skipback({n}) *Iter:skipback()* - Skip values in the iterator starting from the end. - - Only supported for iterators on list-like tables. + Skips `n` values backwards from the end of a |list-iterator| pipeline. Example: >lua local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2) @@ -3622,11 +3613,9 @@ Iter:skipback({n}) *Iter:skipback()* Iter Iter:slice({first}, {last}) *Iter:slice()* - Slice an iterator, changing its start and end positions. - - This is equivalent to :skip(first - 1):skipback(len - last + 1) + Sets the start and end of a |list-iterator| pipeline. - Only supported for iterators on list-like tables. + Equivalent to `:skip(first - 1):skipback(len - last + 1)`. Parameters: ~ • {first} (number) @@ -3662,9 +3651,8 @@ Iter:totable() *Iter:totable()* (table) map({f}, {src}, {...}) *vim.iter.map()* - Map and filter a table or iterator. - - This is a convenience function that performs: >lua + Maps a table or other |iterable|. >lua + -- Equivalent to: vim.iter(src):map(f):totable() < @@ -3681,9 +3669,8 @@ map({f}, {src}, {...}) *vim.iter.map()* • |Iter:map()| totable({f}, {...}) *vim.iter.totable()* - Collect an iterator into a table. - - This is a convenience function that performs: >lua + Collects an |iterable| into a table. >lua + -- Equivalent to: vim.iter(f):totable() < diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 8073a4f162..b5bef13325 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -96,6 +96,15 @@ The following changes may require adaptations in user config or plugins. line number -> priority -> sign id -> recently placed ============================================================================== +BREAKING CHANGES IN HEAD *news-breaking-dev* + +The following breaking changes were made during the development cycle to +unreleased features on Nvim HEAD. + +• ... +• ... + +============================================================================== NEW FEATURES *news-features* The following new APIs and features were added. diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index 595baa7019..874bdfb437 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -2,17 +2,23 @@ --- --- \*vim.iter()\* is an interface for |iterable|s: it wraps a 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: +--- underlying source data. These methods can be chained to create iterator "pipelines": the output +--- of each pipeline stage is input to the next stage. The first stage depends on the type passed to +--- `vim.iter()`: --- ---- - List tables (arrays) pass only the value of each element ---- - Non-list tables (dictionaries) pass both the key and value of each element ---- - Function |iterator|s pass all of the values returned by their respective function ---- - Tables with a metatable implementing |__call()| are treated as function iterators +--- - List tables (arrays, |lua-list|) yield only the value of each element. +--- - Use |Iter:enumerate()| to also pass the index to the next stage. +--- - Or initialize with ipairs(): `vim.iter(ipairs(…))`. +--- - Non-list tables (|lua-dict|) yield both the key and value of each element. +--- - Function |iterator|s yield all values returned by the underlying function. +--- - Tables with a |__call()| metamethod are treated as function iterators. --- ---- The iterator pipeline terminates when the original table or function iterator runs out of values ---- (for function iterators, this means that the first value returned by the function is nil). +--- The iterator pipeline terminates when the underlying |iterable| is exhausted (for function +--- iterators this means it returned nil). +--- +--- Note: `vim.iter()` scans table input to decide if it is a list or a dict; to avoid this cost you +--- can wrap the table with an iterator e.g. `vim.iter(ipairs({…}))`, but that precludes the use of +--- |list-iterator| operations such as |Iter:rev()|). --- --- Examples: --- @@ -138,7 +144,7 @@ local function apply(f, ...) return false end ---- Add a filter step to the iterator pipeline. +--- Filters an iterator pipeline. --- --- Example: --- @@ -173,7 +179,7 @@ function ListIter.filter(self, f) return self end ---- Add a map step to the iterator pipeline. +--- Maps the items of an iterator pipeline to the values returned by `f`. --- --- If the map function returns nil, the value is filtered from the iterator. --- @@ -253,12 +259,9 @@ function ListIter.map(self, f) return self end ---- Call a function once for each item in the pipeline. ---- ---- This is used for functions which have side effects. To modify the values in ---- the iterator, use |Iter:map()|. +--- Calls a function once for each item in the pipeline, draining the iterator. --- ---- This function drains the iterator. +--- For functions with side effects. To modify the values in the iterator, use |Iter:map()|. --- ---@param f function(...) Function to execute for each item in the pipeline. --- Takes all of the values returned by the previous stage @@ -353,7 +356,7 @@ function ListIter.totable(self) return self._table end ---- Fold ("reduce") an iterator or table into a single value. +--- Folds ("reduces") an iterator into a single value. --- --- Examples: --- @@ -400,7 +403,7 @@ function ListIter.fold(self, init, f) return acc end ---- Return the next value from the iterator. +--- Gets the next value from the iterator. --- --- Example: --- @@ -432,9 +435,7 @@ function ListIter.next(self) end end ---- Reverse an iterator. ---- ---- Only supported for iterators on list-like tables. +--- Reverses a |list-iterator| pipeline. --- --- Example: --- @@ -459,9 +460,7 @@ function ListIter.rev(self) return self end ---- Peek at the next value in the iterator without consuming it. ---- ---- Only supported for iterators on list-like tables. +--- Gets the next value in a |list-iterator| without consuming it. --- --- Example: --- @@ -538,12 +537,10 @@ function Iter.find(self, f) return unpack(result) end ---- Find the first value in the iterator that satisfies the given predicate, starting from the end. +--- Gets the first value in a |list-iterator| that satisfies a predicate, starting from the end. --- --- Advances the iterator. Returns nil and drains the iterator if no value is found. --- ---- Only supported for iterators on list-like tables. ---- --- Examples: --- --- ```lua @@ -583,9 +580,7 @@ function ListIter.rfind(self, f) -- luacheck: no unused args self._head = self._tail end ---- Return the next value from the end of the iterator. ---- ---- Only supported for iterators on list-like tables. +--- "Pops" a value from a |list-iterator| (gets the last value and decrements the tail). --- --- Example: --- @@ -610,9 +605,9 @@ function ListIter.nextback(self) end end ---- Return the next value from the end of the iterator without consuming it. +--- Gets the last value of a |list-iterator| without consuming it. --- ---- Only supported for iterators on list-like tables. +--- See also |Iter:last()|. --- --- Example: --- @@ -638,7 +633,7 @@ function ListIter.peekback(self) end end ---- Skip values in the iterator. +--- Skips `n` values of an iterator pipeline. --- --- Example: --- @@ -669,9 +664,7 @@ function ListIter.skip(self, n) return self end ---- Skip values in the iterator starting from the end. ---- ---- Only supported for iterators on list-like tables. +--- Skips `n` values backwards from the end of a |list-iterator| pipeline. --- --- Example: --- @@ -700,9 +693,7 @@ function ListIter.skipback(self, n) return self end ---- Return the nth value in the iterator. ---- ---- This function advances the iterator. +--- Gets the nth value of an iterator (and advances to it). --- --- Example: --- @@ -724,11 +715,7 @@ function Iter.nth(self, n) end end ---- Return the nth value from the end of the iterator. ---- ---- This function advances the iterator. ---- ---- Only supported for iterators on list-like tables. +--- Gets the nth value from the end of a |list-iterator| (and advances to it). --- --- Example: --- @@ -750,11 +737,9 @@ function Iter.nthback(self, n) end end ---- Slice an iterator, changing its start and end positions. +--- Sets the start and end of a |list-iterator| pipeline. --- ---- This is equivalent to :skip(first - 1):skipback(len - last + 1) ---- ---- Only supported for iterators on list-like tables. +--- Equivalent to `:skip(first - 1):skipback(len - last + 1)`. --- ---@param first number ---@param last number @@ -769,7 +754,7 @@ function ListIter.slice(self, first, last) return self:skip(math.max(0, first - 1)):skipback(math.max(0, self._tail - last - 1)) end ---- Return true if any of the items in the iterator match the given predicate. +--- Returns true if any of the items in the iterator match the given predicate. --- ---@param pred function(...):bool Predicate function. Takes all values returned from the previous --- stage in the pipeline as arguments and returns true if the @@ -793,7 +778,7 @@ function Iter.any(self, pred) return any end ---- Return true if all of the items in the iterator match the given predicate. +--- Returns true if all items in the iterator match the given predicate. --- ---@param pred function(...):bool Predicate function. Takes all values returned from the previous --- stage in the pipeline as arguments and returns true if the @@ -816,9 +801,7 @@ function Iter.all(self, pred) return all end ---- Return the last item in the iterator. ---- ---- Drains the iterator. +--- Drains the iterator and returns the last item. --- --- Example: --- @@ -853,22 +836,20 @@ function ListIter.last(self) return v end ---- Add an iterator stage that returns the current iterator count as well as the iterator value. +--- Yields the item index (count) and value for each item of an iterator pipeline. --- ---- For list tables, prefer +--- For list tables, this is more efficient: --- --- ```lua --- vim.iter(ipairs(t)) --- ``` --- ---- over +--- instead of: --- --- ```lua --- vim.iter(t):enumerate() --- ``` --- ---- as the former is faster. ---- --- Example: --- --- ```lua @@ -902,7 +883,7 @@ function ListIter.enumerate(self) return self end ---- Create a new Iter object from a table or iterator. +--- Creates a new Iter object from a table or other |iterable|. --- ---@param src table|function Table or iterator to drain values from ---@return Iter @@ -923,8 +904,7 @@ function Iter.new(src, ...) local t = {} - -- Check if source table can be treated like a list (indices are consecutive integers - -- starting from 1) + -- O(n): scan the source table to decide if it is a list (consecutive integer indices 1…n). local count = 0 for _ in pairs(src) do count = count + 1 @@ -976,11 +956,10 @@ function ListIter.new(t) return it end ---- Collect an iterator into a table. ---- ---- This is a convenience function that performs: +--- Collects an |iterable| into a table. --- --- ```lua +--- -- Equivalent to: --- vim.iter(f):totable() --- ``` --- @@ -990,11 +969,10 @@ function M.totable(f, ...) return Iter.new(f, ...):totable() end ---- Filter a table or iterator. ---- ---- This is a convenience function that performs: +--- Filters a table or other |iterable|. --- --- ```lua +--- -- Equivalent to: --- vim.iter(src):filter(f):totable() --- ``` --- @@ -1009,11 +987,10 @@ 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: +--- Maps a table or other |iterable|. --- --- ```lua +--- -- Equivalent to: --- vim.iter(src):map(f):totable() --- ``` --- |