1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2025-11-23 22:35:38 +02:00
Files
RedMew/utils/history.lua
RedRafe 00f60ea7db Add calculator/technology feature (#1500)
* Add calculator/technology feature

* Update file header

* Updates

* Updates
2025-09-17 10:24:59 +02:00

158 lines
4.6 KiB
Lua

---@class History
--- A class that manages a history buffer with undo/redo capabilities.
local History = {}
History.__index = History
script.register_metatable('RedMew_HistoryClass', History)
local DEFAULT_SIZE = 100
local math_min = math.min
local math_max = math.max
local insert = table.insert
local remove = table.remove
--- Creates a new History instance.
---@param size number? Optional maximum size of the history buffer. Defaults to 100 if not provided or invalid.
---@return History
function History.new(size)
return setmetatable({
buffer = {}, -- Table storing the history elements
index = 0, -- Current position in the history buffer
max_size = (size and size > 0 or DEFAULT_SIZE) -- Max number of items to store
}, History)
end
--- Keeps only the elements within the specified range [left, right].
---@param self History The history object.
---@param left number The starting index of the range (1-based).
---@param right number The ending index of the range (1-based).
local function range(self, left, right)
local result = {}
local len = #self.buffer
left = math_max(1, left)
right = math_min(right, len)
for i = left, right do
insert(result, self.buffer[i])
end
self.buffer = result
if self.index > #self.buffer then
self.index = #self.buffer
end
end
--- Returns the current size of the history buffer.
---@param self History The history object.
---@return number
function History:size()
return #self.buffer
end
--- ADD a new element to the history buffer.
--- If the current position is not at the end, discards all "redo" states.
--- Ensures the buffer does not exceed max_size by trimming oldest entries.
---@param self History The history object.
---@param element any The element to add. Nil elements are ignored.
function History:add(element)
if element == nil then
return
end
if self.index ~= #self.buffer then
range(self, 1, self.index)
end
insert(self.buffer, element)
self.index = #self.buffer
if #self.buffer > self.max_size then
range(self, 1 + #self.buffer - self.max_size, #self.buffer)
end
end
--- REMOVE the element at the specified index.
---@param self History The history object.
---@param index number? Optional index to remove; defaults to current index.
function History:remove(index)
if index == nil then
index = self.index
end
if not self.buffer[index] then
return
end
-- Adjust index if removing current or previous
if self.index >= index then
self.index = self.index - 1
end
remove(self.buffer, index)
end
--- GET the element at the specified index.
--- If no index is provided, returns the current element.
---@param self History The history object.
---@param index number? Optional index to retrieve; defaults to current index.
---@return any
function History:get(index)
if index == nil then
index = self.index
end
return self.buffer[index]
end
--- GET the current position index in the history buffer.
---@param self History The history object.
---@return number The current index.
function History:get_index()
return self.index
end
--- GET the previous element in the history without changing the current index.
---@param self History The history object.
---@return any|nil The previous element or nil if none exists.
function History:peek_previous()
return self.buffer[self.index - 1]
end
--- GET the next element in the history without changing the current index.
---@param self History The history object.
---@return any|nil The next element or nil if none exists.
function History:peek_next()
return self.buffer[self.index + 1]
end
--- MOVE to the previous history element, if possible.
--- Updates the current index and returns the element.
---@param self History The history object.
---@return any|nil The previous element, or nil if at the beginning.
function History:previous()
if not self.buffer[self.index - 1] then
return nil
end
self.index = self.index - 1
return self.buffer[self.index]
end
--- MOVE to the next history element, if possible.
--- Updates the current index and returns the element.
---@param self History The history object.
---@return any|nil The next element, or nil if at the latest.
function History:next()
if not self.buffer[self.index + 1] then
return nil
end
self.index = self.index + 1
return self.buffer[self.index]
end
--- CLEAR the entire history buffer and resets the current index.
---@param self History The history object.
function History:clear()
self.buffer = {}
self.index = 0
end
return History