From b8d28055028c8aa33cbfc4435acbd900b74efb8e Mon Sep 17 00:00:00 2001 From: rxi Date: Thu, 14 May 2020 16:10:48 +0100 Subject: [PATCH] Exposed doc's internal insert/remove: Doc:raw_insert|remove --- data/core/doc/init.lua | 110 ++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/data/core/doc/init.lua b/data/core/doc/init.lua index 9d4d2c0..bb09ce2 100644 --- a/data/core/doc/init.lua +++ b/data/core/doc/init.lua @@ -225,11 +225,43 @@ function Doc:get_char(line, col) end -local push_undo +local function push_undo(undo_stack, time, type, ...) + undo_stack[undo_stack.idx] = { type = type, time = time, ... } + undo_stack[undo_stack.idx - config.max_undos] = nil + undo_stack.idx = undo_stack.idx + 1 +end -local function insert(self, undo_stack, time, line, col, text) - line, col = self:sanitize_position(line, col) +local function pop_undo(self, undo_stack, redo_stack) + -- pop command + local cmd = undo_stack[undo_stack.idx - 1] + if not cmd then return end + undo_stack.idx = undo_stack.idx - 1 + + -- handle command + if cmd.type == "insert" then + local line, col, text = table.unpack(cmd) + self:raw_insert(line, col, text, redo_stack, cmd.time) + + elseif cmd.type == "remove" then + local line1, col1, line2, col2 = table.unpack(cmd) + self:raw_remove(line1, col1, line2, col2, redo_stack, cmd.time) + + elseif cmd.type == "selection" then + self.selection.a.line, self.selection.a.col = cmd[1], cmd[2] + self.selection.b.line, self.selection.b.col = cmd[3], cmd[4] + end + + -- if next undo command is within the merge timeout then treat as a single + -- command and continue to execute it + local next = undo_stack[undo_stack.idx - 1] + if next and math.abs(cmd.time - next.time) < config.undo_merge_timeout then + return pop_undo(self, undo_stack, redo_stack) + end +end + + +function Doc:raw_insert(line, col, text, undo_stack, time) -- split text into lines and merge with line at insertion point local lines = split_lines(text) local before = self.lines[line]:sub(1, col - 1) @@ -245,23 +277,20 @@ local function insert(self, undo_stack, time, line, col, text) -- push undo local line2, col2 = self:position_offset(line, col, #text) - push_undo(self, undo_stack, time, "selection", self:get_selection()) - push_undo(self, undo_stack, time, "remove", line, col, line2, col2) + push_undo(undo_stack, time, "selection", self:get_selection()) + push_undo(undo_stack, time, "remove", line, col, line2, col2) - -- update highlighter + -- update highlighter and assure selection is in bounds self.highlighter:invalidate(line) + self:sanitize_selection() end -local function remove(self, undo_stack, time, line1, col1, line2, col2) - line1, col1 = self:sanitize_position(line1, col1) - line2, col2 = self:sanitize_position(line2, col2) - line1, col1, line2, col2 = sort_positions(line1, col1, line2, col2) - +function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time) -- push undo local text = self:get_text(line1, col1, line2, col2) - push_undo(self, undo_stack, time, "selection", self:get_selection()) - push_undo(self, undo_stack, time, "insert", line1, col1, text) + push_undo(undo_stack, time, "selection", self:get_selection()) + push_undo(undo_stack, time, "insert", line1, col1, text) -- get line content before/after removed text local before = self.lines[line1]:sub(1, col1 - 1) @@ -270,56 +299,25 @@ local function remove(self, undo_stack, time, line1, col1, line2, col2) -- splice line into line array splice(self.lines, line1, line2 - line1 + 1, { before .. after }) - -- update highlighter + -- update highlighter and assure selection is in bounds self.highlighter:invalidate(line1) -end - - -function Doc:insert(...) - insert(self, self.undo_stack, system.get_time(), ...) self:sanitize_selection() +end + + +function Doc:insert(line, col, text) self.redo_stack = { idx = 1 } + line, col = self:sanitize_position(line, col) + self:raw_insert(line, col, text, self.undo_stack, system.get_time()) end -function Doc:remove(...) - remove(self, self.undo_stack, system.get_time(), ...) - self:sanitize_selection() +function Doc:remove(line1, col1, line2, col2) self.redo_stack = { idx = 1 } -end - - -function push_undo(self, undo_stack, time, type, ...) - undo_stack[undo_stack.idx] = { type = type, time = time, ... } - undo_stack[undo_stack.idx - config.max_undos] = nil - undo_stack.idx = undo_stack.idx + 1 -end - - -local function pop_undo(self, undo_stack, redo_stack) - -- pop command - local cmd = undo_stack[undo_stack.idx - 1] - if not cmd then return end - undo_stack.idx = undo_stack.idx - 1 - - -- handle command - if cmd.type == "insert" then - insert(self, redo_stack, cmd.time, table.unpack(cmd)) - - elseif cmd.type == "remove" then - remove(self, redo_stack, cmd.time, table.unpack(cmd)) - - elseif cmd.type == "selection" then - self.selection.a.line, self.selection.a.col = cmd[1], cmd[2] - self.selection.b.line, self.selection.b.col = cmd[3], cmd[4] - end - - -- if next undo command is within the merge timeout then treat as a single - -- command and continue to execute it - local next = undo_stack[undo_stack.idx - 1] - if next and math.abs(cmd.time - next.time) < config.undo_merge_timeout then - return pop_undo(self, undo_stack, redo_stack) - end + line1, col1 = self:sanitize_position(line1, col1) + line2, col2 = self:sanitize_position(line2, col2) + line1, col1, line2, col2 = sort_positions(line1, col1, line2, col2) + self:raw_remove(line1, col1, line2, col2, self.undo_stack, system.get_time()) end