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: ~
|
See also: ~
|
||||||
• https://github.com/rxi/lume
|
• 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()*
|
spairs({t}) *vim.spairs()*
|
||||||
Enumerate a table sorted by its keys.
|
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
|
• |vim.iter()| provides a generic iterator interface for tables and Lua
|
||||||
iterators |luaref-in|.
|
iterators |luaref-in|.
|
||||||
|
|
||||||
|
• Added |vim.ringbuf()| to create ring buffers.
|
||||||
|
|
||||||
• Added |vim.keycode()| for translating keycodes in a string.
|
• Added |vim.keycode()| for translating keycodes in a string.
|
||||||
|
|
||||||
• Added |vim.treesitter.query.omnifunc()| for treesitter query files (set by
|
• Added |vim.treesitter.query.omnifunc()| for treesitter query files (set by
|
||||||
|
@ -881,4 +881,98 @@ function vim.defaulttable(create)
|
|||||||
})
|
})
|
||||||
end
|
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
|
return vim
|
||||||
|
@ -3040,6 +3040,46 @@ describe('lua stdlib', function()
|
|||||||
|
|
||||||
eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]])
|
eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]])
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
describe('lua: builtin modules', function()
|
describe('lua: builtin modules', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user