From 675a319d1ecfa43ceac8f7e4b8eb956e38e39105 Mon Sep 17 00:00:00 2001 From: Guldoman Date: Fri, 3 Jun 2022 07:02:31 +0200 Subject: Add more `bracketmatch` styles (#81) * `bracketmatch`: Don't consider comments * `bracketmatch`: Add new styles * `bracketmatch`: Add "frame" style --- plugins/bracketmatch.lua | 172 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 152 insertions(+), 20 deletions(-) (limited to 'plugins/bracketmatch.lua') 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 -- cgit v1.2.3