From d3068a44de59fe7b55a04a1fb271637670e6070a 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 | 115 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 16 deletions(-) diff --git a/plugins/bracketmatch.lua b/plugins/bracketmatch.lua index b2c3f4e..cd9fc2f 100644 --- a/plugins/bracketmatch.lua +++ b/plugins/bracketmatch.lua @@ -4,30 +4,54 @@ 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" + +-- 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 = { + highligh_both = true, -- highlight the current bracket too + style = "underline", -- can be "underline", "block", "frame", "none" + color_char = false, -- color the bracket + line_size = math.ceil(1 * SCALE), -- the size of the lines used in "underline" and "frame" +} + 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 +87,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,17 +118,76 @@ function DocView:update(...) end +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 + + +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 + + 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 + + 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 idx == state.line2 then - local color = style.bracketmatch_color or style.syntax["function"] - local x1 = x + self:get_col_x_offset(idx, state.col2) - local x2 = x + self:get_col_x_offset(idx, state.col2 + 1) - local h = math.ceil(1 * SCALE) - renderer.draw_rect(x1, y + self:get_line_height() - h, x2 - x1, h, color) + 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.highligh_both then + draw_decoration(self, x, y, idx, state.col + select_adj - 1) + end end end -- cgit v1.2.3