refactor(vim.iter)!: rename xxback() => rxx() #28503

Problem:
vim.iter has both `rfind()` and various `*back()` methods, which work
in "reverse" or "backwards" order. It's inconsistent to have both kinds
of names, and "back" is fairly uncommon (rust) compared to python
(rfind, rstrip, rsplit, …).

Solution:
- Remove `nthback()` and let `nth()` take a negative index.
  - Because `rnth()` looks pretty obscure, and because it's intuitive
    for a function named `nth()` to take negative indexes.
- Rename `xxback()` methods to `rxx()`.
  - This informally groups the "list-iterator" functions under a common
    `r` prefix, which helps discoverability.
- Rename `peekback()` to `pop()`, in duality with the existing `peek`.
This commit is contained in:
Justin M. Keyes 2024-04-26 08:43:29 -07:00 committed by GitHub
parent b2c26a875b
commit 9b028bd64f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 146 additions and 136 deletions

View File

@ -4053,6 +4053,9 @@ Iter:last() *Iter:last()*
Return: ~ Return: ~
(`any`) (`any`)
See also: ~
• Iter.rpeek
Iter:map({f}) *Iter:map()* Iter:map({f}) *Iter:map()*
Maps the items of an iterator pipeline to the values returned by `f`. Maps the items of an iterator pipeline to the values returned by `f`.
@ -4094,53 +4097,28 @@ Iter:next() *Iter:next()*
Return: ~ Return: ~
(`any`) (`any`)
Iter:nextback() *Iter:nextback()*
"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})
it:nextback()
-- 4
it:nextback()
-- 3
<
Return: ~
(`any`)
Iter:nth({n}) *Iter:nth()* Iter:nth({n}) *Iter:nth()*
Gets the nth value of an iterator (and advances to it). Gets the nth value of an iterator (and advances to it).
Example: >lua If `n` is negative, offsets from the end of a |list-iterator|.
Example: >lua
local it = vim.iter({ 3, 6, 9, 12 }) local it = vim.iter({ 3, 6, 9, 12 })
it:nth(2) it:nth(2)
-- 6 -- 6
it:nth(2) it:nth(2)
-- 12 -- 12
<
Parameters: ~ local it2 = vim.iter({ 3, 6, 9, 12 })
• {n} (`number`) The index of the value to return. it2:nth(-2)
Return: ~
(`any`)
Iter:nthback({n}) *Iter:nthback()*
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 })
it:nthback(2)
-- 9 -- 9
it:nthback(2) it2:nth(-2)
-- 3 -- 3
< <
Parameters: ~ Parameters: ~
• {n} (`number`) The index of the value to return. • {n} (`number`) Index of the value to return. May be negative if the
source is a |list-iterator|.
Return: ~ Return: ~
(`any`) (`any`)
@ -4162,19 +4140,16 @@ Iter:peek() *Iter:peek()*
Return: ~ Return: ~
(`any`) (`any`)
Iter:peekback() *Iter:peekback()* Iter:pop() *Iter:pop()*
Gets the last value of a |list-iterator| without consuming it. "Pops" a value from a |list-iterator| (gets the last value and decrements
the tail).
See also |Iter:last()|.
Example: >lua Example: >lua
local it = vim.iter({1, 2, 3, 4}) local it = vim.iter({1, 2, 3, 4})
it:peekback() it:pop()
-- 4
it:peekback()
-- 4
it:nextback()
-- 4 -- 4
it:pop()
-- 3
< <
Return: ~ Return: ~
@ -4194,8 +4169,8 @@ Iter:rev() *Iter:rev()*
(`Iter`) (`Iter`)
Iter:rfind({f}) *Iter:rfind()* Iter:rfind({f}) *Iter:rfind()*
Gets the first value in a |list-iterator| that satisfies a predicate, Gets the first value satisfying a predicate, from the end of a
starting from the end. |list-iterator|.
Advances the iterator. Returns nil and drains the iterator if no value is Advances the iterator. Returns nil and drains the iterator if no value is
found. found.
@ -4218,6 +4193,42 @@ Iter:rfind({f}) *Iter:rfind()*
See also: ~ See also: ~
• Iter.find • Iter.find
Iter:rpeek() *Iter:rpeek()*
Gets the last value of a |list-iterator| without consuming it.
Example: >lua
local it = vim.iter({1, 2, 3, 4})
it:rpeek()
-- 4
it:rpeek()
-- 4
it:pop()
-- 4
<
Return: ~
(`any`)
See also: ~
• Iter.last
Iter:rskip({n}) *Iter:rskip()*
Discards `n` values from the end of a |list-iterator| pipeline.
Example: >lua
local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
it:next()
-- 1
it:pop()
-- 3
<
Parameters: ~
• {n} (`number`) Number of values to skip.
Return: ~
(`Iter`)
Iter:skip({n}) *Iter:skip()* Iter:skip({n}) *Iter:skip()*
Skips `n` values of an iterator pipeline. Skips `n` values of an iterator pipeline.
@ -4234,27 +4245,10 @@ Iter:skip({n}) *Iter:skip()*
Return: ~ Return: ~
(`Iter`) (`Iter`)
Iter:skipback({n}) *Iter:skipback()*
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)
it:next()
-- 1
it:nextback()
-- 3
<
Parameters: ~
• {n} (`number`) Number of values to skip.
Return: ~
(`Iter`)
Iter:slice({first}, {last}) *Iter:slice()* Iter:slice({first}, {last}) *Iter:slice()*
Sets the start and end of a |list-iterator| pipeline. Sets the start and end of a |list-iterator| pipeline.
Equivalent to `:skip(first - 1):skipback(len - last + 1)`. Equivalent to `:skip(first - 1):rskip(len - last + 1)`.
Parameters: ~ Parameters: ~
• {first} (`number`) • {first} (`number`)

View File

@ -159,6 +159,14 @@ unreleased features on Nvim HEAD.
• Changed |vim.ui.open()| return-signature to match pcall() convention. • Changed |vim.ui.open()| return-signature to match pcall() convention.
• Renamed Iter:nextback() to Iter:pop()
• Renamed Iter:peekback() to Iter:rpeek()
• Renamed Iter:skipback() to Iter:rskip()
• Removed Iter:nthback(), use Iter:nth() with negative index instead.
============================================================================== ==============================================================================
NEW FEATURES *news-features* NEW FEATURES *news-features*

View File

@ -630,7 +630,7 @@ function Iter:find(f)
return unpack(result) return unpack(result)
end end
--- Gets the first value in a |list-iterator| that satisfies a predicate, starting from the end. --- Gets the first value satisfying a predicate, from the end of a |list-iterator|.
--- ---
--- Advances the iterator. Returns nil and drains the iterator if no value is found. --- Advances the iterator. Returns nil and drains the iterator if no value is found.
--- ---
@ -717,19 +717,19 @@ end
--- ---
--- ```lua --- ```lua
--- local it = vim.iter({1, 2, 3, 4}) --- local it = vim.iter({1, 2, 3, 4})
--- it:nextback() --- it:pop()
--- -- 4 --- -- 4
--- it:nextback() --- it:pop()
--- -- 3 --- -- 3
--- ``` --- ```
--- ---
---@return any ---@return any
function Iter:nextback() function Iter:pop()
error('nextback() requires a list-like table') error('pop() requires a list-like table')
end end
--- @nodoc --- @nodoc
function ListIter:nextback() function ListIter:pop()
if self._head ~= self._tail then if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1 local inc = self._head < self._tail and 1 or -1
self._tail = self._tail - inc self._tail = self._tail - inc
@ -739,27 +739,27 @@ end
--- Gets the last value of a |list-iterator| without consuming it. --- Gets the last value of a |list-iterator| without consuming it.
--- ---
--- See also |Iter:last()|.
---
--- Example: --- Example:
--- ---
--- ```lua --- ```lua
--- local it = vim.iter({1, 2, 3, 4}) --- local it = vim.iter({1, 2, 3, 4})
--- it:peekback() --- it:rpeek()
--- -- 4 --- -- 4
--- it:peekback() --- it:rpeek()
--- -- 4 --- -- 4
--- it:nextback() --- it:pop()
--- -- 4 --- -- 4
--- ``` --- ```
--- ---
---@see Iter.last
---
---@return any ---@return any
function Iter:peekback() function Iter:rpeek()
error('peekback() requires a list-like table') error('rpeek() requires a list-like table')
end end
---@nodoc ---@nodoc
function ListIter:peekback() function ListIter:rpeek()
if self._head ~= self._tail then if self._head ~= self._tail then
local inc = self._head < self._tail and 1 or -1 local inc = self._head < self._tail and 1 or -1
return self._table[self._tail - inc] return self._table[self._tail - inc]
@ -797,27 +797,27 @@ function ListIter:skip(n)
return self return self
end end
--- Skips `n` values backwards from the end of a |list-iterator| pipeline. --- Discards `n` values from the end of a |list-iterator| pipeline.
--- ---
--- Example: --- Example:
--- ---
--- ```lua --- ```lua
--- local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2) --- local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
--- it:next() --- it:next()
--- -- 1 --- -- 1
--- it:nextback() --- it:pop()
--- -- 3 --- -- 3
--- ``` --- ```
--- ---
---@param n number Number of values to skip. ---@param n number Number of values to skip.
---@return Iter ---@return Iter
---@diagnostic disable-next-line: unused-local ---@diagnostic disable-next-line: unused-local
function Iter:skipback(n) -- luacheck: no unused args function Iter:rskip(n) -- luacheck: no unused args
error('skipback() requires a list-like table') error('rskip() requires a list-like table')
end end
---@private ---@private
function ListIter:skipback(n) function ListIter:rskip(n)
local inc = self._head < self._tail and n or -n local inc = self._head < self._tail and n or -n
self._tail = self._tail - inc self._tail = self._tail - inc
if (inc > 0 and self._head > self._tail) or (inc < 0 and self._head < self._tail) then if (inc > 0 and self._head > self._tail) or (inc < 0 and self._head < self._tail) then
@ -828,51 +828,37 @@ end
--- Gets the nth value of an iterator (and advances to it). --- Gets the nth value of an iterator (and advances to it).
--- ---
--- If `n` is negative, offsets from the end of a |list-iterator|.
---
--- Example: --- Example:
--- ---
--- ```lua --- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 }) --- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nth(2) --- it:nth(2)
--- -- 6 --- -- 6
--- it:nth(2) --- it:nth(2)
--- -- 12 --- -- 12
--- ---
--- local it2 = vim.iter({ 3, 6, 9, 12 })
--- it2:nth(-2)
--- -- 9
--- it2:nth(-2)
--- -- 3
--- ``` --- ```
--- ---
---@param n number The index of the value to return. ---@param n number Index of the value to return. May be negative if the source is a |list-iterator|.
---@return any ---@return any
function Iter:nth(n) function Iter:nth(n)
if n > 0 then if n > 0 then
return self:skip(n - 1):next() return self:skip(n - 1):next()
end elseif n < 0 then
end return self:rskip(math.abs(n) - 1):pop()
--- 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 })
--- it:nthback(2)
--- -- 9
--- it:nthback(2)
--- -- 3
---
--- ```
---
---@param n number The index of the value to return.
---@return any
function Iter:nthback(n)
if n > 0 then
return self:skipback(n - 1):nextback()
end end
end end
--- Sets the start and end of a |list-iterator| pipeline. --- Sets the start and end of a |list-iterator| pipeline.
--- ---
--- Equivalent to `:skip(first - 1):skipback(len - last + 1)`. --- Equivalent to `:skip(first - 1):rskip(len - last + 1)`.
--- ---
---@param first number ---@param first number
---@param last number ---@param last number
@ -884,7 +870,7 @@ end
---@private ---@private
function ListIter:slice(first, last) function ListIter:slice(first, last)
return self:skip(math.max(0, first - 1)):skipback(math.max(0, self._tail - last - 1)) return self:skip(math.max(0, first - 1)):rskip(math.max(0, self._tail - last - 1))
end end
--- Returns 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.
@ -950,6 +936,8 @@ end
--- ---
--- ``` --- ```
--- ---
---@see Iter.rpeek
---
---@return any ---@return any
function Iter:last() function Iter:last()
local last = self:next() local last = self:next()
@ -1016,6 +1004,26 @@ function ListIter:enumerate()
return self return self
end end
---@deprecated
function Iter:nextback()
error('Iter:nextback() was renamed to Iter:pop()')
end
---@deprecated
function Iter:peekback()
error('Iter:peekback() was renamed to Iter:rpeek()')
end
---@deprecated
function Iter:skipback()
error('Iter:skipback() was renamed to Iter:rskip()')
end
---@deprecated
function Iter:nthback()
error('Iter:nthback() was removed, use Iter:nth() with negative index')
end
--- Creates a new Iter object from a table or other |iterable|. --- Creates a new Iter object from a table or other |iterable|.
--- ---
---@param src table|function Table or iterator to drain values from ---@param src table|function Table or iterator to drain values from

View File

@ -169,19 +169,19 @@ describe('vim.iter', function()
end end
end) end)
it('skipback()', function() it('rskip()', function()
do do
local q = { 4, 3, 2, 1 } local q = { 4, 3, 2, 1 }
eq(q, vim.iter(q):skipback(0):totable()) eq(q, vim.iter(q):rskip(0):totable())
eq({ 4, 3, 2 }, vim.iter(q):skipback(1):totable()) eq({ 4, 3, 2 }, vim.iter(q):rskip(1):totable())
eq({ 4, 3 }, vim.iter(q):skipback(2):totable()) eq({ 4, 3 }, vim.iter(q):rskip(2):totable())
eq({ 4 }, vim.iter(q):skipback(#q - 1):totable()) eq({ 4 }, vim.iter(q):rskip(#q - 1):totable())
eq({}, vim.iter(q):skipback(#q):totable()) eq({}, vim.iter(q):rskip(#q):totable())
eq({}, vim.iter(q):skipback(#q + 1):totable()) eq({}, vim.iter(q):rskip(#q + 1):totable())
end end
local it = vim.iter(vim.gsplit('a|b|c|d', '|')) local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0)) matches('rskip%(%) requires a list%-like table', pcall_err(it.rskip, it, 0))
end) end)
it('slice()', function() it('slice()', function()
@ -222,19 +222,19 @@ describe('vim.iter', function()
end end
end) end)
it('nthback()', function() it('nth(-x) advances in reverse order starting from end', function()
do do
local q = { 4, 3, 2, 1 } local q = { 4, 3, 2, 1 }
eq(nil, vim.iter(q):nthback(0)) eq(nil, vim.iter(q):nth(0))
eq(1, vim.iter(q):nthback(1)) eq(1, vim.iter(q):nth(-1))
eq(2, vim.iter(q):nthback(2)) eq(2, vim.iter(q):nth(-2))
eq(3, vim.iter(q):nthback(3)) eq(3, vim.iter(q):nth(-3))
eq(4, vim.iter(q):nthback(4)) eq(4, vim.iter(q):nth(-4))
eq(nil, vim.iter(q):nthback(5)) eq(nil, vim.iter(q):nth(-5))
end end
local it = vim.iter(vim.gsplit('a|b|c|d', '|')) local it = vim.iter(vim.gsplit('a|b|c|d', '|'))
matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1)) matches('rskip%(%) requires a list%-like table', pcall_err(it.nth, it, -1))
end) end)
it('take()', function() it('take()', function()
@ -421,34 +421,34 @@ describe('vim.iter', function()
end end
end) end)
it('nextback()', function() it('pop()', function()
do do
local it = vim.iter({ 1, 2, 3, 4 }) local it = vim.iter({ 1, 2, 3, 4 })
eq(4, it:nextback()) eq(4, it:pop())
eq(3, it:nextback()) eq(3, it:pop())
eq(2, it:nextback()) eq(2, it:pop())
eq(1, it:nextback()) eq(1, it:pop())
eq(nil, it:nextback()) eq(nil, it:pop())
eq(nil, it:nextback()) eq(nil, it:pop())
end end
do do
local it = vim.iter(vim.gsplit('hi', '')) local it = vim.iter(vim.gsplit('hi', ''))
matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it)) matches('pop%(%) requires a list%-like table', pcall_err(it.pop, it))
end end
end) end)
it('peekback()', function() it('rpeek()', function()
do do
local it = vim.iter({ 1, 2, 3, 4 }) local it = vim.iter({ 1, 2, 3, 4 })
eq(4, it:peekback()) eq(4, it:rpeek())
eq(4, it:peekback()) eq(4, it:rpeek())
eq(4, it:nextback()) eq(4, it:pop())
end end
do do
local it = vim.iter(vim.gsplit('hi', '')) local it = vim.iter(vim.gsplit('hi', ''))
matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it)) matches('rpeek%(%) requires a list%-like table', pcall_err(it.rpeek, it))
end end
end) end)