-- mod-version:3 local core = require "core" local config = require "core.config" local style = require "core.style" local common = require "core.common" local DocView = require "core.docview" config.plugins.smoothcaret = common.merge({ enabled = true, rate = 0.65, -- The config specification used by the settings gui config_spec = { name = "Smooth Caret", { label = "Enabled", description = "Disable or enable the smooth caret animation.", path = "enabled", type = "toggle", default = true }, { label = "Rate", description = "Speed of the animation.", path = "rate", type = "number", default = 0.65, min = 0.2, max = 1.0, step = 0.05 }, } }, config.plugins.smoothcaret) local caret_idx = 1 local docview_update = DocView.update function DocView:update() docview_update(self) if not config.plugins.smoothcaret.enabled then return end local minline, maxline = self:get_visible_line_range() -- We need to keep track of all the carets if not self.carets then self.carets = { } end -- and we need the list of visible ones that `DocView:draw_caret` will use in succession self.visible_carets = { } local idx, v_idx = 1, 1 for _, line, col in self.doc:get_selections() do local x, y = self:get_line_screen_position(line, col) -- Keep the position relative to the whole View -- This way scrolling won't animate the caret x = x + self.scroll.x y = y + self.scroll.y if not self.carets[idx] then self.carets[idx] = { current = { x = x, y = y }, target = { x = x, y = y } } end local c = self.carets[idx] c.target.x = x c.target.y = y -- Chech if the number of carets changed if self.last_n_selections ~= #self.doc.selections then -- Don't animate when there are new carets c.current.x = x c.current.y = y else self:move_towards(c.current, "x", c.target.x, config.plugins.smoothcaret.rate) self:move_towards(c.current, "y", c.target.y, config.plugins.smoothcaret.rate) end -- Keep track of visible carets if line >= minline and line <= maxline then self.visible_carets[v_idx] = self.carets[idx] v_idx = v_idx + 1 end idx = idx + 1 end self.last_n_selections = #self.doc.selections -- Remove unused carets to avoid animating new ones when they are added for i = idx, #self.carets do self.carets[i] = nil end if self.mouse_selecting ~= self.last_mouse_selecting then self.last_mouse_selecting = self.mouse_selecting -- Show the caret on click, so that it can be seen moving towards the new position if self.mouse_selecting then core.blink_timer = core.blink_timer + config.blink_period / 2 core.redraw = true end end -- This is used by `DocView:draw_caret` to keep track of the current caret caret_idx = 1 end local docview_draw_caret = DocView.draw_caret function DocView:draw_caret(x, y) if not config.plugins.smoothcaret.enabled then docview_draw_caret(self, x, y) return end local c = self.visible_carets[caret_idx] or { current = { x = x, y = y } } docview_draw_caret(self, c.current.x - self.scroll.x, c.current.y - self.scroll.y) caret_idx = caret_idx + 1 end