mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
feat(lua): add ringbuffer (#22894)
https://en.wikipedia.org/wiki/Circular_buffer
This commit is contained in:
parent
38b0bb3c93
commit
7c661207cc
@ -1847,6 +1847,60 @@ pesc({s}) *vim.pesc()*
|
||||
See also: ~
|
||||
• https://github.com/rxi/lume
|
||||
|
||||
ringbuf({size}) *vim.ringbuf()*
|
||||
Create a ring buffer limited to a maximal number of items. Once the buffer
|
||||
is full, adding a new entry overrides the oldest entry.
|
||||
>
|
||||
|
||||
local ringbuf = vim.ringbuf(4)
|
||||
ringbuf:push("a")
|
||||
ringbuf:push("b")
|
||||
ringbuf:push("c")
|
||||
ringbuf:push("d")
|
||||
ringbuf:push("e") -- overrides "a"
|
||||
print(ringbuf:pop()) -- returns "b"
|
||||
print(ringbuf:pop()) -- returns "c"
|
||||
|
||||
-- Can be used as iterator. Pops remaining items:
|
||||
for val in ringbuf do
|
||||
print(val)
|
||||
end
|
||||
<
|
||||
|
||||
Returns a Ringbuf instance with the following methods:
|
||||
|
||||
• |Ringbuf:push()|
|
||||
• |Ringbuf:pop()|
|
||||
• |Ringbuf:peek()|
|
||||
• |Ringbuf:clear()|
|
||||
|
||||
Parameters: ~
|
||||
• {size} (integer)
|
||||
|
||||
Return: ~
|
||||
(table)
|
||||
|
||||
Ringbuf:clear({self}) *Ringbuf:clear()*
|
||||
Clear all items.
|
||||
|
||||
Ringbuf:peek({self}) *Ringbuf:peek()*
|
||||
Returns the first unread item without removing it
|
||||
|
||||
Return: ~
|
||||
any?|ni
|
||||
|
||||
Ringbuf:pop({self}) *Ringbuf:pop()*
|
||||
Removes and returns the first unread item
|
||||
|
||||
Return: ~
|
||||
any?|ni
|
||||
|
||||
Ringbuf:push({self}, {item}) *Ringbuf:push()*
|
||||
Adds an item, overriding the oldest item if the buffer is full.
|
||||
|
||||
Parameters: ~
|
||||
• {item} any
|
||||
|
||||
spairs({t}) *vim.spairs()*
|
||||
Enumerate a table sorted by its keys.
|
||||
|
||||
|
@ -59,6 +59,8 @@ The following new APIs or features were added.
|
||||
• |vim.iter()| provides a generic iterator interface for tables and Lua
|
||||
iterators |luaref-in|.
|
||||
|
||||
• Added |vim.ringbuf()| to create ring buffers.
|
||||
|
||||
• Added |vim.keycode()| for translating keycodes in a string.
|
||||
|
||||
• Added |vim.treesitter.query.omnifunc()| for treesitter query files (set by
|
||||
|
@ -881,4 +881,98 @@ function vim.defaulttable(create)
|
||||
})
|
||||
end
|
||||
|
||||
do
|
||||
---@class vim.Ringbuf<T>
|
||||
---@field private _items table[]
|
||||
---@field private _idx_read integer
|
||||
---@field private _idx_write integer
|
||||
---@field private _size integer
|
||||
local Ringbuf = {}
|
||||
|
||||
--- Clear all items
|
||||
function Ringbuf.clear(self)
|
||||
self._items = {}
|
||||
self._idx_read = 0
|
||||
self._idx_write = 0
|
||||
end
|
||||
|
||||
--- Adds an item, overriding the oldest item if the buffer is full.
|
||||
---@generic T
|
||||
---@param item T
|
||||
function Ringbuf.push(self, item)
|
||||
self._items[self._idx_write] = item
|
||||
self._idx_write = (self._idx_write + 1) % self._size
|
||||
if self._idx_write == self._idx_read then
|
||||
self._idx_read = (self._idx_read + 1) % self._size
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes and returns the first unread item
|
||||
---@generic T
|
||||
---@return T?
|
||||
function Ringbuf.pop(self)
|
||||
local idx_read = self._idx_read
|
||||
if idx_read == self._idx_write then
|
||||
return nil
|
||||
end
|
||||
local item = self._items[idx_read]
|
||||
self._items[idx_read] = nil
|
||||
self._idx_read = (idx_read + 1) % self._size
|
||||
return item
|
||||
end
|
||||
|
||||
--- Returns the first unread item without removing it
|
||||
---@generic T
|
||||
---@return T?
|
||||
function Ringbuf.peek(self)
|
||||
if self._idx_read == self._idx_write then
|
||||
return nil
|
||||
end
|
||||
return self._items[self._idx_read]
|
||||
end
|
||||
|
||||
--- Create a ring buffer limited to a maximal number of items.
|
||||
--- Once the buffer is full, adding a new entry overrides the oldest entry.
|
||||
---
|
||||
--- <pre>
|
||||
--- local ringbuf = vim.ringbuf(4)
|
||||
--- ringbuf:push("a")
|
||||
--- ringbuf:push("b")
|
||||
--- ringbuf:push("c")
|
||||
--- ringbuf:push("d")
|
||||
--- ringbuf:push("e") -- overrides "a"
|
||||
--- print(ringbuf:pop()) -- returns "b"
|
||||
--- print(ringbuf:pop()) -- returns "c"
|
||||
---
|
||||
--- -- Can be used as iterator. Pops remaining items:
|
||||
--- for val in ringbuf do
|
||||
--- print(val)
|
||||
--- end
|
||||
--- </pre>
|
||||
---
|
||||
--- Returns a Ringbuf instance with the following methods:
|
||||
---
|
||||
--- - |Ringbuf:push()|
|
||||
--- - |Ringbuf:pop()|
|
||||
--- - |Ringbuf:peek()|
|
||||
--- - |Ringbuf:clear()|
|
||||
---
|
||||
---@param size integer
|
||||
---@return vim.Ringbuf ringbuf (table)
|
||||
function vim.ringbuf(size)
|
||||
local ringbuf = {
|
||||
_items = {},
|
||||
_size = size + 1,
|
||||
_idx_read = 0,
|
||||
_idx_write = 0,
|
||||
}
|
||||
return setmetatable(ringbuf, {
|
||||
__index = Ringbuf,
|
||||
__call = function(self)
|
||||
return self:pop()
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return vim
|
||||
|
@ -3040,6 +3040,46 @@ describe('lua stdlib', function()
|
||||
|
||||
eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]])
|
||||
end)
|
||||
|
||||
it("vim.ringbuf", function()
|
||||
local results = exec_lua([[
|
||||
local ringbuf = vim.ringbuf(3)
|
||||
ringbuf:push("a") -- idx: 0
|
||||
local peeka1 = ringbuf:peek()
|
||||
local peeka2 = ringbuf:peek()
|
||||
local popa = ringbuf:pop()
|
||||
local popnil = ringbuf:pop()
|
||||
ringbuf:push("a") -- idx: 1
|
||||
ringbuf:push("b") -- idx: 2
|
||||
|
||||
-- doesn't read last added item, but uses separate read index
|
||||
local pop_after_add_b = ringbuf:pop()
|
||||
|
||||
ringbuf:push("c") -- idx: 3 wraps around, overrides idx: 0 "a"
|
||||
ringbuf:push("d") -- idx: 4 wraps around, overrides idx: 1 "a"
|
||||
return {
|
||||
peeka1 = peeka1,
|
||||
peeka2 = peeka2,
|
||||
pop1 = popa,
|
||||
pop2 = popnil,
|
||||
pop3 = ringbuf:pop(),
|
||||
pop4 = ringbuf:pop(),
|
||||
pop5 = ringbuf:pop(),
|
||||
pop_after_add_b = pop_after_add_b,
|
||||
}
|
||||
]])
|
||||
local expected = {
|
||||
peeka1 = "a",
|
||||
peeka2 = "a",
|
||||
pop1 = "a",
|
||||
pop2 = nil,
|
||||
pop3 = "b",
|
||||
pop4 = "c",
|
||||
pop5 = "d",
|
||||
pop_after_add_b = "a",
|
||||
}
|
||||
eq(expected, results)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('lua: builtin modules', function()
|
||||
|
Loading…
Reference in New Issue
Block a user