function record_undo_event(State, data)
State.history[State.next_history] = data
State.next_history = State.next_history+1
for i=State.next_history,#State.history do
State.history[i] = nil
end
end
function undo_event(State)
if State.next_history > 1 then
State.next_history = State.next_history-1
local result = State.history[State.next_history]
return result
end
end
function redo_event(State)
if State.next_history <= #State.history then
local result = State.history[State.next_history]
State.next_history = State.next_history+1
return result
end
end
function snapshot(State, s,e)
assert(s, 'failed to snapshot operation for undo history')
if e == nil then
e = s
end
assert(#State.lines > 0, 'failed to snapshot operation for undo history')
if s < 1 then s = 1 end
if s > #State.lines then s = #State.lines end
if e < 1 then e = 1 end
if e > #State.lines then e = #State.lines end
local event = {
screen_top=deepcopy(State.screen_top1),
selection=deepcopy(State.selection1),
cursor=deepcopy(State.cursor1),
lines={},
start_line=s,
end_line=e,
}
for i=s,e do
table.insert(event.lines, deepcopy(State.lines[i]))
end
return event
end
function patch(lines, from, to)
assert(from.start_line == to.start_line, 'failed to patch undo operation')
for i=from.end_line,from.start_line,-1 do
table.remove(lines, i)
end
assert(#to.lines == to.end_line-to.start_line+1, 'failed to patch undo operation')
for i=1,#to.lines do
table.insert(lines, to.start_line+i-1, to.lines[i])
end
end
function deepcopy(obj, seen)
if type(obj) ~= 'table' then return obj end
if seen and seen[obj] then return seen[obj] end
local s = seen or {}
local result = setmetatable({}, getmetatable(obj))
s[obj] = result
for k,v in pairs(obj) do
result[deepcopy(k, s)] = deepcopy(v, s)
end
return result
end
function minmax(a, b)
return math.min(a,b), math.max(a,b)
end