aboutsummaryrefslogtreecommitdiff
path: root/bracketmatch.lua
diff options
context:
space:
mode:
Diffstat (limited to 'bracketmatch.lua')
-rw-r--r--bracketmatch.lua103
1 files changed, 103 insertions, 0 deletions
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" }