diff options
author | Guldoman <giulio.lettieri@gmail.com> | 2024-10-20 20:29:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-20 14:29:59 -0400 |
commit | 79443641242361c9f73c34f8a9287cb638e1b553 (patch) | |
tree | 4c1cd9d66205cbb8bb8a5fa789699a6c773f2fce /plugins | |
parent | 146b41bbbe524f578f190f47794a2571cc439ac0 (diff) | |
download | lite-xl-plugins-79443641242361c9f73c34f8a9287cb638e1b553.tar.gz lite-xl-plugins-79443641242361c9f73c34f8a9287cb638e1b553.zip |
Simplify `minimap` (#284)
* Simplify `minimap`
* Remove `MiniMap:_get_thumb_rect_normal` workaround
* Fix `minimap` drawing float precision
* Improve `minimap` highlight drawing location
* Fixed `minimap` toggling
* Remove `minimap` workaround to keep caret visible
This is now handled in `DocView` directly.
* Use `common.splice` to manage `minimap` cache
* Add `docview` param to `MiniMap:line_highlight_color`
This will allow overrides to target a specific `DocView`.
The parameter is added last to keep compatibility with the previous
system.
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/minimap.lua | 214 |
1 files changed, 95 insertions, 119 deletions
diff --git a/plugins/minimap.lua b/plugins/minimap.lua index ac94849..6dd2a1c 100644 --- a/plugins/minimap.lua +++ b/plugins/minimap.lua @@ -228,8 +228,6 @@ local function reset_cache_if_needed() end - - -- Move cache to make space for new lines local prev_insert_notify = Highlighter.insert_notify function Highlighter:insert_notify(line, n, ...) @@ -238,13 +236,11 @@ function Highlighter:insert_notify(line, n, ...) if not highlighter_cache[self] then highlighter_cache[self] = {} else - local to = math.min(line + n, #self.doc.lines) - for i=#self.doc.lines+n,to,-1 do - highlighter_cache[self][i] = highlighter_cache[self][i - n] - end - for i=line,to do - highlighter_cache[self][i] = nil + local blanks = { } + for i = 1, n do + blanks[i] = false end + common.splice(highlighter_cache[self], line, 0, blanks) end end @@ -256,10 +252,7 @@ function Highlighter:remove_notify(line, n, ...) if not highlighter_cache[self] then highlighter_cache[self] = {} else - local to = math.max(line + n, #self.doc.lines) - for i=line,to do - highlighter_cache[self][i] = highlighter_cache[self][i + n] - end + common.splice(highlighter_cache[self], line, n) end end @@ -271,7 +264,7 @@ function Highlighter:tokenize_line(idx, state, ...) if not highlighter_cache[self] then highlighter_cache[self] = {} end - highlighter_cache[self][idx] = nil + highlighter_cache[self][idx] = false return res end @@ -297,14 +290,50 @@ end local MiniMap = Scrollbar:extend() -function MiniMap:new(dv) - MiniMap.super.new(self, { direction = "v", alignment = "e" }) +function MiniMap:new(dv, original_v_scrollbar) + MiniMap.super.new(self, { direction = "v", alignment = "e", + force_status = "expanded", + expanded_size = cached_settings.width, + expanded_margin = 0 }) + self.original_force_status = original_v_scrollbar.force_status + self.original_expanded_size = original_v_scrollbar.expanded_size + self.original_expanded_margin = original_v_scrollbar.expanded_margin self.dv = dv self.enabled = nil + self.was_enabled = true +end + + +function MiniMap:swap_to_status() + local enabled = self:is_minimap_enabled() + if not enabled and self.was_enabled then + self.force_status = self.original_force_status + self.expanded_size = self.original_expanded_size + self.expanded_margin = self.original_expanded_margin + self.was_enabled = false + elseif enabled and not self.was_enabled then + self.force_status = "expanded" + self.expanded_size = cached_settings.width + self.expanded_margin = 0 + self.was_enabled = true + end +end + + +function MiniMap:update() + self:swap_to_status() + if self:is_minimap_enabled() then + reset_cache_if_needed() + self.expanded_size = cached_settings.width + local lh = self.dv:get_line_height() + local nlines = self.dv.size.y / lh + self.minimum_thumb_size = nlines * line_spacing + end + MiniMap.super.update(self) end -function MiniMap:line_highlight_color(line_index) +function MiniMap:line_highlight_color(line_index, docview) -- other plugins can override this, and return a color end @@ -327,96 +356,56 @@ function MiniMap:is_minimap_enabled() end -function MiniMap:get_minimap_dimensions() - local x, y, w, h = self:get_track_rect() - local _, cy, _, cy2 = self.dv:get_content_bounds() - local lh = self.dv:get_line_height() - - local visible_lines_start = math.max(1, math.floor(cy / lh)) - local visible_lines_count = math.max(1, (cy2 - cy) / lh) - local minimap_lines_start = 1 - local minimap_lines_count = math.floor(h / line_spacing) - local line_count = #self.dv.doc.lines - - local is_file_too_large = line_count > 1 and line_count > minimap_lines_count - if is_file_too_large then - local scroll_pos = (visible_lines_start - 1) / - (line_count - visible_lines_count - 1) - scroll_pos = math.min(1.0, scroll_pos) -- 0..1, procent of visual area scrolled - - local thumb_height = visible_lines_count * line_spacing - local scroll_pos_pixels = scroll_pos * (h - thumb_height) - - minimap_lines_start = visible_lines_start - - math.floor(scroll_pos_pixels / line_spacing) - minimap_lines_start = math.max(1, minimap_lines_start) +function MiniMap:_on_mouse_pressed_normal(button, x, y, clicks) + local overlaps = self:_overlaps_normal(x, y) + local percent = MiniMap.super._on_mouse_pressed_normal(self, button, x, y, clicks) + if overlaps == "track" then + -- We need to adjust the percentage to scroll to the line in the minimap + -- that was "clicked" + local minimap_line, _ = self:get_minimap_lines() + local _, track_y, _, _ = self:_get_track_rect_normal() + local line = minimap_line + (y - track_y) // line_spacing + local _, y = self.dv:get_line_screen_position(line) + local _, oy = self.dv:get_content_offset() + local nr = self.normal_rect + percent = common.clamp((y - oy - (self.dv.size.y) / 2) / (nr.scrollable - self.dv.size.y), 0, 1) end - return visible_lines_start, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large + return percent end -function MiniMap:_get_track_rect_normal() - if not self:is_minimap_enabled() then return MiniMap.super._get_track_rect_normal(self) end - return self.dv.size.x + self.dv.position.x - config.plugins.minimap.width, self.dv.position.y, config.plugins.minimap.width, self.dv.size.y +local function get_visible_minline(dv) + local _, y, _, _ = dv:get_content_bounds() + local lh = dv:get_line_height() + local minline = math.max(0, y / lh + 1) + return minline end -function MiniMap:get_active_margin() if self:is_minimap_enabled() then return 0 else return MiniMap.super.get_active_margin(self) end end - +function MiniMap:get_minimap_lines() + local _, track_y, _, h = self:_get_track_rect_normal() + local _, thumb_y, _, _ = self:_get_thumb_rect_normal() -function MiniMap:_get_thumb_rect_normal() - if not self:is_minimap_enabled() then return MiniMap.super._get_thumb_rect_normal(self) end - local visible_lines_start, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large = self:get_minimap_dimensions() - local visible_y = self.dv.position.y + (visible_lines_start - 1) * line_spacing - if is_file_too_large then - local line_count = #self.dv.doc.lines - local scroll_pos = (visible_lines_start - 1) / - (line_count - visible_lines_count - 1) - scroll_pos = math.min(1.0, scroll_pos) -- 0..1, procent of visual area scrolled + local nlines = h // line_spacing - local thumb_height = visible_lines_count * line_spacing - local scroll_pos_pixels = scroll_pos * (self.dv.size.y - thumb_height) - visible_y = self.dv.position.y + scroll_pos_pixels + local minline = get_visible_minline(self.dv) + local top_lines = (thumb_y - track_y) / line_spacing + local lines_start, offset = math.modf(minline - top_lines) + if lines_start <= 1 and nlines >= #self.dv.doc.lines then + offset = 0 end - return self.dv.size.x + self.dv.position.x - config.plugins.minimap.width, visible_y, config.plugins.minimap.width, visible_lines_count * line_spacing -end - - -function MiniMap:on_mouse_pressed(button, x, y, clicks) - local percent = MiniMap.super.on_mouse_pressed(self, button, x, y, clicks) - if not self:is_minimap_enabled() or not percent then return percent end - local _, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large = self:get_minimap_dimensions() - local _, _, w, h = self:get_track_rect() - local tx, ty, tw, th = self:get_thumb_rect() - if y >= ty and y < ty + th then self.drag_start_offset = (y - ty) - th / 2 return self.percent end - self.drag_start_offset = 0 - self.hovering.thumb = x >= tx and x < tx + tw and y >= ty and y < ty + th - self.dragging = self.hovering.thumb - local lh = self.dv:get_line_height() - percent = math.max(0.0, math.min((y - self.dv.position.y) / h, 1.0)) - return (((percent * minimap_lines_count) + minimap_lines_start) * lh / self.dv:get_scrollable_size()) - (visible_lines_count / #self.dv.doc.lines / 2) + return common.clamp(lines_start, 1, #self.dv.doc.lines), common.clamp(nlines, 1, #self.dv.doc.lines), offset * line_spacing end -function MiniMap:on_mouse_moved(x, y, dx, dy) - local percent = MiniMap.super.on_mouse_moved(self, x, y, dx, dy) - if not self:is_minimap_enabled() or type(percent) ~= "number" then return percent end - local _, visible_lines_count, minimap_lines_start, minimap_lines_count, is_file_too_large = self:get_minimap_dimensions() - local lh = self.dv:get_line_height() - local _, _, w, h = self:get_track_rect() - local tx, ty, tw, th = self:get_thumb_rect() - if x >= tx and x < tx + tw and y >= ty and y < ty + th then self.hovering.thumb = true end - if not self.hovering.thumb then return self.percent end - y = y - self.drag_start_offset - percent = math.max(0.0, math.min((y - self.dv.position.y) / h, 1.0)) - return (((percent * minimap_lines_count) + minimap_lines_start) * lh / self.dv:get_scrollable_size()) - (visible_lines_count / #self.dv.doc.lines / 2) +function MiniMap:set_size(x, y, w, h, scrollable) + if not self:is_minimap_enabled() then return MiniMap.super.set_size(self, x, y, w, h, scrollable) end + -- If possible, use the size needed to only manage the visible minimap lines. + -- This allows us to let Scrollbar manage the thumb. + h = math.min(h, line_spacing * (scrollable // self.dv:get_line_height())) + MiniMap.super.set_size(self, x, y, w, h, scrollable) end -function MiniMap:draw_thumb() - local color = self.hovering.thumb and style.scrollbar2 or style.scrollbar - local x, y, w, h = self:get_thumb_rect() - renderer.draw_rect(x, y, w, h, color) -end function MiniMap:draw() if not self:is_minimap_enabled() then return MiniMap.super.draw(self) end @@ -426,25 +415,27 @@ function MiniMap:draw() local highlight = dv.hovered_scrollbar or dv.dragging_scrollbar local visual_color = highlight and style.scrollbar2 or style.scrollbar - local visible_lines_start, visible_lines_count, - minimap_lines_start, minimap_lines_count = self:get_minimap_dimensions() if config.plugins.minimap.draw_background then - renderer.draw_rect(x, y, w, h, style.minimap_background or style.background) + renderer.draw_rect(x, y, w, self.dv.size.y, style.minimap_background or style.background) end self:draw_thumb() + local minimap_lines_start, minimap_lines_count, y_offset = self:get_minimap_lines() + local line_selection_offset = line_spacing - char_height + y = y - y_offset + line_selection_offset + -- highlight the selected lines, and the line with the caret on it local selection_color = config.plugins.minimap.selection_color or style.dim local caret_color = config.plugins.minimap.caret_color or style.caret - for i, line1, col1, line2, col2 in dv.doc:get_selections() do - local selection1_y = y + (line1 - minimap_lines_start) * line_spacing - local selection2_y = y + (line2 - minimap_lines_start) * line_spacing + for _, line1, _, line2, _ in dv.doc:get_selections() do + local selection1_y = y + (line1 - minimap_lines_start) * line_spacing - line_selection_offset + local selection2_y = y + (line2 - minimap_lines_start) * line_spacing - line_selection_offset local selection_min_y = math.min(selection1_y, selection2_y) - local selection_h = math.abs(selection2_y - selection1_y)+1 + local selection_h = math.abs(selection2_y - selection1_y) + 1 + line_selection_offset renderer.draw_rect(x, selection_min_y, w, selection_h, selection_color) - renderer.draw_rect(x, selection1_y, w, line_spacing, caret_color) + renderer.draw_rect(x, selection1_y, w, line_spacing + line_selection_offset, caret_color) end local highlight_align = config.plugins.minimap.highlight_align @@ -511,16 +502,15 @@ function MiniMap:draw() highlight_x = x + w - highlight_width end local function render_highlight(idx, line_y) - local highlight_color = self:line_highlight_color(idx) + local highlight_color = self:line_highlight_color(idx, self.dv) if highlight_color then - renderer.draw_rect(highlight_x, line_y, highlight_width, line_spacing, highlight_color) + renderer.draw_rect(highlight_x, line_y - line_selection_offset, + highlight_width, line_spacing + line_selection_offset, highlight_color) end end local endidx = math.min(minimap_lines_start + minimap_lines_count, #self.dv.doc.lines) - reset_cache_if_needed() - if not highlighter_cache[dv.doc.highlighter] then highlighter_cache[dv.doc.highlighter] = {} end @@ -595,23 +585,9 @@ end local old_docview_new = DocView.new function DocView:new(doc) old_docview_new(self, doc) - if self:is(DocView) then self.v_scrollbar = MiniMap(self) end -end - -local old_docview_scroll_to_make_visible = DocView.scroll_to_make_visible -function DocView:scroll_to_make_visible(line, col, ...) - if - not self:is(DocView) or not self.v_scrollbar:is(MiniMap) - or - not self.v_scrollbar:is_minimap_enabled() - then - return old_docview_scroll_to_make_visible(self, line, col, ...) + if self:is(DocView) then + self.v_scrollbar = MiniMap(self, self.v_scrollbar) end - local old_size = self.size.x - self.size.x = math.max(0, self.size.x - config.plugins.minimap.width) - local result = old_docview_scroll_to_make_visible(self, line, col, ...) - self.size.x = old_size - return result end |