aboutsummaryrefslogtreecommitdiff
path: root/plugins/bracketmatch.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/bracketmatch.lua')
-rw-r--r--plugins/bracketmatch.lua172
1 files changed, 152 insertions, 20 deletions
diff --git a/plugins/bracketmatch.lua b/plugins/bracketmatch.lua
index a58c1af..6963224 100644
--- a/plugins/bracketmatch.lua
+++ b/plugins/bracketmatch.lua
@@ -1,33 +1,108 @@
--- mod-version:3
+--- mod-version:3
local core = require "core"
local style = require "core.style"
local command = require "core.command"
local keymap = require "core.keymap"
local DocView = require "core.docview"
+local config = require "core.config"
+local common = require "core.common"
+
+-- Colors can be configured as follows:
+-- underline color = `style.bracketmatch_color`
+-- bracket color = `style.bracketmatch_char_color`
+-- background color = `style.bracketmatch_block_color`
+-- frame color = `style.bracketmatch_frame_color`
+
+config.plugins.bracketmatch = common.merge({
+ -- highlight the current bracket too
+ highlight_both = true,
+ -- can be "underline", "block", "frame", "none"
+ style = "underline",
+ -- color the bracket
+ color_char = false,
+ -- the size of the lines used in "underline" and "frame"
+ line_size = math.ceil(1 * SCALE),
+ -- The config specification used by the settings gui
+ config_spec = {
+ name = "Bracket Match",
+ {
+ label = "Highlight Both",
+ description = "Highlight the current bracket too.",
+ path = "highlight_both",
+ type = "toggle",
+ default = true
+ },
+ {
+ label = "Style",
+ description = "The visual indicator for pair brackets.",
+ path = "style",
+ type = "selection",
+ default = "underline",
+ values = {
+ {"Underline", "underline"},
+ {"Block", "block"},
+ {"Frame", "frame"},
+ {"None", "none"}
+ }
+ },
+ {
+ label = "Colorize Bracket",
+ description = "Change the color of the matching brackets.",
+ path = "color_char",
+ type = "toggle",
+ default = false
+ },
+ {
+ label = "Line Size",
+ description = "Height of the underline on matching brackets.",
+ path = "line_size",
+ type = "number",
+ default = 1,
+ min = 1,
+ step = 1,
+ get_value = function(value)
+ return math.floor(value / SCALE)
+ end,
+ set_value = function(value)
+ return math.ceil(value * SCALE)
+ end
+ }
+ }
+}, config.plugins.bracketmatch)
+
local bracket_maps = {
-- [ ] ( ) { }
- { [91] = 93, [40] = 41, [123] = 125, step = 1 },
+ { [91] = 93, [40] = 41, [123] = 125, direction = 1 },
-- ] [ ) ( } {
- { [93] = 91, [41] = 40, [125] = 123, step = -1 },
+ { [93] = 91, [41] = 40, [125] = 123, direction = -1 },
}
-local function get_matching_bracket(doc, line, col, line_limit, open_byte, close_byte, step)
- local end_line = line + line_limit * step
+local function get_token_at(doc, line, col)
+ local column = 0
+ for _,type,text in doc.highlighter:each_token(line) do
+ column = column + #text
+ if column >= col then return type, text end
+ end
+end
+
+
+local function get_matching_bracket(doc, line, col, line_limit, open_byte, close_byte, direction)
+ local end_line = line + line_limit * direction
local depth = 0
while line ~= end_line do
local byte = doc.lines[line]:byte(col)
- if byte == open_byte then
+ if byte == open_byte and get_token_at(doc, line, col) ~= "comment" then
depth = depth + 1
- elseif byte == close_byte then
+ elseif byte == close_byte and get_token_at(doc, line, col) ~= "comment" then
depth = depth - 1
if depth == 0 then return line, col end
end
local prev_line, prev_col = line, col
- line, col = doc:position_offset(line, col, step)
+ line, col = doc:position_offset(line, col, direction)
if line == prev_line and col == prev_col then
break
end
@@ -63,10 +138,10 @@ local function update_state(line_limit)
local line, col = doc:position_offset(line, col, i)
local open = doc.lines[line]:byte(col)
local close = map[open]
- if close then
+ if close and get_token_at(doc, line, col) ~= "comment" then
-- i == 0 if the cursor is on the left side of a bracket (or -1 when on right)
select_adj = i + 1 -- if i == 0 then select_adj = 1 else select_adj = 0 end
- line2, col2 = get_matching_bracket(doc, line, col, line_limit, open, close, map.step)
+ line2, col2 = get_matching_bracket(doc, line, col, line_limit, open, close, map.direction)
goto found
end
end
@@ -94,20 +169,77 @@ function DocView:update(...)
end
-local draw_line_text = DocView.draw_line_text
+local function redraw_char(dv, x, y, line, col, bg_color, char_color)
+ local x1 = x + dv:get_col_x_offset(line, col)
+ local x2 = x + dv:get_col_x_offset(line, col + 1)
+ local lh = dv:get_line_height()
+ local token = get_token_at(dv.doc, line, col)
+ if not char_color then
+ char_color = style.syntax[token]
+ end
+ local font = style.syntax_fonts[token] or dv:get_font()
+ local char = string.sub(dv.doc.lines[line], col, col)
+
+ if not bg_color then
+ -- redraw background
+ core.push_clip_rect(x1, y, x2 - x1, lh)
+ local dlt = DocView.draw_line_text
+ DocView.draw_line_text = function() end
+ dv:draw_line_body(line, x, y)
+ DocView.draw_line_text = dlt
+ core.pop_clip_rect()
+ else
+ renderer.draw_rect(x1, y, x2 - x1, lh, bg_color)
+ end
+ renderer.draw_text(font, char, x1, y + dv:get_line_text_y_offset(), char_color)
+end
+
-function DocView:draw_line_text(line, x, y)
- local lh = draw_line_text(self, line, x, y)
+local function draw_decoration(dv, x, y, line, col)
+ local conf = config.plugins.bracketmatch
+ local color = style.bracketmatch_color or style.syntax["function"]
+ local char_color = style.bracketmatch_char_color
+ or (conf.style == "block" and style.background or style.syntax["keyword"])
+ local block_color = style.bracketmatch_block_color or style.line_number2
+ local frame_color = style.bracketmatch_frame_color or style.line_number2
- if self.doc == state.doc and line == state.line2 then
- local color = style.bracketmatch_color or style.syntax["function"]
- local x1 = x + self:get_col_x_offset(line, state.col2)
- local x2 = x + self:get_col_x_offset(line, state.col2 + 1)
- local h = math.ceil(1 * SCALE)
- renderer.draw_rect(x1, y + self:get_line_height() - h, x2 - x1, h, color)
+ local h = conf.line_size
+
+ if conf.color_char or conf.style == "block" then
+ redraw_char(dv, x, y, line, col,
+ conf.style == "block" and block_color, conf.color_char and char_color)
end
+ if conf.style == "underline" then
+ local x1 = x + dv:get_col_x_offset(line, col)
+ local x2 = x + dv:get_col_x_offset(line, col + 1)
+ local lh = dv:get_line_height()
+
+ renderer.draw_rect(x1, y + lh - h, x2 - x1, h, color)
+ elseif conf.style == "frame" then
+ local x1 = x + dv:get_col_x_offset(line, col)
+ local x2 = x + dv:get_col_x_offset(line, col + 1)
+ local lh = dv:get_line_height()
+
+ renderer.draw_rect(x1, y + lh - h, x2 - x1, h, frame_color)
+ renderer.draw_rect(x1, y, x2 - x1, h, frame_color)
+ renderer.draw_rect(x1, y, h, lh, frame_color)
+ renderer.draw_rect(x2, y, h, lh, frame_color)
+ end
+end
- return lh
+
+local draw_line_text = DocView.draw_line_text
+
+function DocView:draw_line_text(idx, x, y)
+ draw_line_text(self, idx, x, y)
+ if self.doc == state.doc and state.line2 then
+ if idx == state.line2 then
+ draw_decoration(self, x, y, idx, state.col2)
+ end
+ if idx == state.line and config.plugins.bracketmatch.highlight_both then
+ draw_decoration(self, x, y, idx, state.col + select_adj - 1)
+ end
+ end
end