From 8e321f68aba76da51f1ea2de7fef3588ddc763ad Mon Sep 17 00:00:00 2001 From: rxi Date: Thu, 23 Apr 2020 18:57:15 +0100 Subject: Added plugin `bracketmatch` --- README.md | 1 + bracketmatch.lua | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 bracketmatch.lua diff --git a/README.md b/README.md index 92bd2e3..2215849 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ otherwise the plugin file itself can be submitted.* Plugin | Description -------|----------------------------------------- [`autowrap`](autowrap.lua?raw=1) | Automatically hardwraps lines when typing +[`bracketmatch`](bracketmatch.lua?raw=1) | [Underlines](https://user-images.githubusercontent.com/3920290/80132745-0c863f00-8594-11ea-8875-c455c6fd7eae.png) matching right-bracket of left-bracket under caret [`gofmt`](gofmt.lua?raw=1) | Auto-formats the current go file, adds the missing imports and the missing return cases [`indentguide`](indentguide.lua?raw=1) | Adds [indent guides](https://user-images.githubusercontent.com/3920290/79640716-f9860000-818a-11ea-9c3b-26d10dd0e0c0.png) [`language_fe`](language_fe.lua?raw=1) | Syntax for the [fe](https://github.com/rxi/fe) programming language diff --git a/bracketmatch.lua b/bracketmatch.lua new file mode 100644 index 0000000..b05e8ab --- /dev/null +++ b/bracketmatch.lua @@ -0,0 +1,103 @@ +local core = require "core" +local style = require "core.style" +local config = require "core.config" +local command = require "core.command" +local keymap = require "core.keymap" +local DocView = require "core.docview" + +local bracket_map = { ["["] = "]", ["("] = ")", ["{"] = "}" } + + +local state = {} + +local function update_state(line_limit) + line_limit = line_limit or math.huge + + -- reset if we don't have a document (eg. DocView isn't focused) + local doc = core.active_view.doc + if not doc then + state = {} + return + end + + -- early exit if nothing has changed since the last call + local line, col = doc:get_selection() + if state.doc == doc and state.line == line and state.col == col + and state.limit == line_limit then + return + end + + -- find matching rbracket if we have an lbracket + local line2, col2 + local chr = doc:get_text(line, col - 1, line, col) + local rbracket = bracket_map[chr] + + if rbracket then + local ptn = "[%" .. chr .. "%" .. rbracket .. "]" + local offset = col - 1 + local depth = 1 + + for i = line, math.min(#doc.lines, line + line_limit) do + while offset do + local n = doc.lines[i]:find(ptn, offset + 1) + if n then + local match = doc.lines[i]:sub(n, n) + if match == chr then + depth = depth + 1 + elseif match == rbracket then + depth = depth - 1 + if depth == 0 then line2, col2 = i, n end + end + end + offset = n + end + if line2 then break end + offset = 0 + end + end + + -- update + state = { + doc = doc, + line = line, + col = col, + line2 = line2, + col2 = col2, + limit = line_limit, + } +end + + +local update = DocView.update + +function DocView:update(...) + update(self, ...) + update_state(100) +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 = style.divider_size + renderer.draw_rect(x1, y + self:get_line_height() - h, x2 - x1, h, color) + end +end + + +command.add("core.docview", { + ["bracket-match:move-to-matching"] = function() + update_state() + if state.line2 then + core.active_view.doc:set_selection(state.line2, state.col2) + end + end, +}) + +keymap.add { ["ctrl+m"] = "bracket-match:move-to-matching" } -- cgit v1.2.3