aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/indentguide.lua94
1 files changed, 81 insertions, 13 deletions
diff --git a/plugins/indentguide.lua b/plugins/indentguide.lua
index 0513be4..1c4f8ae 100644
--- a/plugins/indentguide.lua
+++ b/plugins/indentguide.lua
@@ -4,18 +4,28 @@ local config = require "core.config"
local DocView = require "core.docview"
+-- TODO: replace with `doc:get_indent_info()` when 2.1 releases
+local function get_indent_info(doc)
+ if doc.get_indent_info then
+ return doc:get_indent_info()
+ end
+ return config.tab_type, config.indent_size
+end
+
+
local function get_line_spaces(doc, idx, dir)
+ local _, indent_size = get_indent_info(doc)
local text = doc.lines[idx]
- if not text then
- return 0
+ if not text or #text == 1 then
+ return -1
end
local s, e = text:find("^%s*")
if e == #text then
return get_line_spaces(doc, idx + dir, dir)
end
local n = 0
- for i = s, e do
- n = n + (text:byte(i) == 9 and config.indent_size or 1)
+ for _,b in pairs({text:byte(s, e)}) do
+ n = n + (b == 9 and indent_size or 1)
end
return n
end
@@ -30,21 +40,79 @@ local function get_line_indent_guide_spaces(doc, idx)
return get_line_spaces(doc, idx)
end
+local docview_update = DocView.update
+function DocView:update()
+ docview_update(self)
-local draw_line_text = DocView.draw_line_text
+ local function get_indent(idx)
+ if idx < 1 or idx > #self.doc.lines then return -1 end
+ if not self.lineguide_indents[idx] then
+ self.lineguide_indents[idx] = get_line_indent_guide_spaces(self.doc, idx)
+ end
+ return self.lineguide_indents[idx]
+ end
+
+ self.lineguide_indents = {}
+ self.lineguide_indent_active = {}
+
+ local minline, maxline = self:get_visible_line_range()
+ for i = minline, maxline do
+ self.lineguide_indents[i] = get_line_indent_guide_spaces(self.doc, i)
+ end
+
+ local line = self.doc:get_selection()
+ local lvl = get_indent(line)
+ local top, bottom
+ local _, indent_size = get_indent_info(self.doc)
+ -- check if we're the header or the footer of a block
+ if get_indent(line + 1) > lvl and get_indent(line + 1) <= lvl + indent_size then
+ top = true
+ lvl = get_indent(line + 1)
+ elseif get_indent(line - 1) > lvl and get_indent(line - 1) <= lvl + indent_size then
+ bottom = true
+ lvl = get_indent(line - 1)
+ end
+
+ self.lineguide_indent_active[line] = lvl
+
+ -- check if the lines before the current are part of the block
+ local i = line - 1
+ if i > 0 and not top then
+ repeat
+ if get_indent(i) <= lvl - indent_size then break end
+ self.lineguide_indent_active[i] = lvl
+ i = i - 1
+ until i < minline
+ end
+ -- check if the lines after the current are part of the block
+ i = line + 1
+ if i <= #self.doc.lines and not bottom then
+ repeat
+ if get_indent(i) <= lvl - indent_size then break end
+ self.lineguide_indent_active[i] = lvl
+ i = i + 1
+ until i > maxline
+ end
+end
+
+
+local draw_line_text = DocView.draw_line_text
function DocView:draw_line_text(idx, x, y)
- local spaces = get_line_indent_guide_spaces(self.doc, idx)
- local w = math.ceil(1 * SCALE)
+ local spaces = self.lineguide_indents[idx] or -1
+ local _, indent_size = get_indent_info(self.doc)
+ local w = math.max(1, SCALE)
local h = self:get_line_height()
- local sspaces = ""
local font = self:get_font()
- local ss = font:subpixel_scale()
- for _ = 0, spaces - 1, config.indent_size do
+ local space_sz = font:get_width(" ")
+ for i = 0, spaces - 1, indent_size do
local color = style.guide or style.selection
- local sw = font:get_width_subpixel(sspaces) / ss
- renderer.draw_rect(x + sw, y, w, h, color)
- sspaces = sspaces .. (' '):rep(config.indent_size)
+ local active_lvl = self.lineguide_indent_active[idx] or -1
+ if i < active_lvl and i + indent_size >= active_lvl then
+ color = style.accent
+ end
+ local sw = space_sz * i
+ renderer.draw_rect(math.ceil(x + sw), y, w, h, color)
end
draw_line_text(self, idx, x, y)
end