summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorgi Kirilov <>2020-11-22 15:10:49 +0200
committerGeorgi Kirilov <>2023-10-04 18:24:59 +0800
commit1425300e56e500d0cc61b4dfb14e10d59822686b (patch)
tree80f3ed18c14d0f4fce97ac661c1d6e30f14b5aeb
parent03fae0a577f4e105aad95744ef1f519386724e40 (diff)
downloadvis-pairs-1425300e56e500d0cc61b4dfb14e10d59822686b.tar.gz
Load the whole file only once per action
-rw-r--r--pairs.lua93
1 files changed, 49 insertions, 44 deletions
diff --git a/pairs.lua b/pairs.lua
index db32665..16b53c4 100644
--- a/pairs.lua
+++ b/pairs.lua
@@ -110,7 +110,7 @@ local function match_at(str, pattern, pos)
end
end
-local function escaping_context(file, range)
+local function escaping_context(data, range)
if not vis.win.syntax then return {} end
local rules = vis.lexers.lexers[vis.win.syntax]._RULES
local p
@@ -121,16 +121,16 @@ local function escaping_context(file, range)
end
if not p then return {} end
if not range then return {escape = p} end -- means we are retrying with a "fake" pos
- local data = file:content(0, file.size)
local e1 = {match_at(data, p, range.start)}
local e2 = range.finish - range.start > 1 and {match_at(data, p, range.finish - 1)} or e1
if #e1 == 0 and #e2 == 0 then return {escape = p} end
if #e1 == 0 and #e2 > 0 then return {escape = p, newpos = range.start} end
if #e2 == 0 and #e1 > 0 then return {escape = p, newpos = range.finish - 1} end
p = nil
- local escaped_range = {start = e1[1], finish = e1[2]}
+ local escaped_range = {e1[1] + 1, e1[2]}
+ local escaped_data = data:sub(e1[1] + 1, e1[2])
for _, level in ipairs({vis.lexers.COMMENT, vis.lexers.STRING}) do
- if l.match(rules[level] / 0 * -1, file:content(escaped_range)) then
+ if l.match(rules[level] / 0 * -1, escaped_data) then
for _, name in ipairs(precedence[level]) do
if rules[name] then
p = p and p + rules[name] / 0 or rules[name] / 0
@@ -141,23 +141,23 @@ local function escaping_context(file, range)
end
end
-local function get_range(key, file, pos)
+local function get_range(key, file_data, pos)
local d = get_pair(key)
if not d then return end
local offsets, correction
repeat
local sel_range = selection_range(pos)
- local c = escaping_context(file, sel_range)
- local range = c.range or {start = 0, finish = file.size}
+ local c = escaping_context(file_data, sel_range)
+ local range = c.range or {1, #file_data}
if c.newpos then
pos = c.newpos
else
- pos = pos - range.start
+ pos = pos - (range[1] - 1)
end
- correction = range.start
+ correction = range[1] - 1
local p = d[1] ~= d[2] and symmetric(d[1], d[2], c.escape, pos + 1) or asymmetric(d[1], pos + 1)
local skip = c.escape and c.escape + 1 or 1
- local data = file:content(range)
+ local data = c.range and file_data:sub(unpack(c.range)) or file_data
local pattern = l.P{p + skip * (l.V(1) - l.Cmt(l.Cc(pos + 1), past))}
local result
local start = 1
@@ -167,7 +167,7 @@ local function get_range(key, file, pos)
start = result
until type(result) == "table"
if not result then
- pos = range.start - 1
+ pos = correction - 1
else
offsets = {nth(result)}
offsets[3] = nil
@@ -185,7 +185,8 @@ end
local function get_delimiters(key, pos)
local d = get_pair(key)
if not d or type(d[1]) == "string" and type(d[2]) == "string" then return d end
- local start, finish = get_range(key, vis.win.file, pos)
+ local content = vis.win.file:content(0, vis.win.file.size)
+ local start, finish = get_range(key, content, pos)
if start and finish then
return {vis.win.file:content(start[1], start[2] - start[1]), vis.win.file:content(finish[1], finish[2] - finish[1]), d[3], d[4]}
elseif #d > 2 then
@@ -193,40 +194,23 @@ local function get_delimiters(key, pos)
end
end
-local done_once
-
-local function bail_early()
- if vis.count and vis.count > 1 then
- if done_once then
- done_once = nil
- return true
- else
- done_once = true
- end
- end
- return false
-end
-
-local function outer(win, pos)
- if bail_early() then return end
- local start, finish = get_range(M.key, win.file, pos)
+local function outer(content, pos)
+ local start, finish = get_range(M.key, content, pos)
if not (start and finish) then return end
return start[1], finish[2]
end
-local function inner(win, pos)
- if bail_early() then return end
- local start, finish = get_range(M.key, win.file, pos)
+local function inner(content, pos)
+ local start, finish = get_range(M.key, content, pos)
if not (start and finish) then return end
return start[2], finish[1]
end
-local function opening(win, pos)
- if bail_early() then return pos end
- local start, _ = get_range(M.key, win.file, pos)
+local function opening(content, pos)
+ local start, _ = get_range(M.key, content, pos)
if start then
if pos == start[2] - 1 then
- start, _ = get_range(M.key, win.file, start[1] - 1)
+ start, _ = get_range(M.key, content, start[1] - 1)
end
if start then
local exclusive = (vis.mode == vis.modes.OPERATOR_PENDING or vis.mode == vis.modes.VISUAL and pos < start[2] - 1) and 1 or 0
@@ -236,12 +220,11 @@ local function opening(win, pos)
return pos
end
-local function closing(win, pos)
- if bail_early() then return pos end
- local _, finish = get_range(M.key, win.file, pos)
+local function closing(content, pos)
+ local _, finish = get_range(M.key, content, pos)
if finish then
if pos == finish[1] then
- _, finish = get_range(M.key, win.file, finish[2])
+ _, finish = get_range(M.key, content, finish[2])
end
if finish then
local exclusive = (vis.mode == vis.modes.VISUAL and pos > finish[1]) and 1 or 0
@@ -251,6 +234,28 @@ local function closing(win, pos)
return pos
end
+local done_once
+
+local function bail_early()
+ if vis.count and vis.count > 1 then
+ if done_once then
+ done_once = nil
+ return true
+ else
+ done_once = true
+ end
+ end
+ return false
+end
+
+local function handler(func)
+ return function(win, pos)
+ if bail_early() then return pos end
+ local content = win.file:content(0, win.file.size)
+ return func(content, pos)
+ end
+end
+
local function new(execute, register, prefix, handler, help)
local id = register(vis, handler)
if id < 0 then
@@ -284,12 +289,12 @@ end
vis.events.subscribe(vis.events.INIT, function()
M.motion = {
- opening = new(vis.motion, vis.motion_register, M.prefix.opening, opening, "Move cursor to the beginning of a delimited block"),
- closing = new(vis.motion, vis.motion_register, M.prefix.closing, closing, "Move cursor to the end of a delimited block"),
+ opening = new(vis.motion, vis.motion_register, M.prefix.opening, handler(opening), "Move cursor to the beginning of a delimited block"),
+ closing = new(vis.motion, vis.motion_register, M.prefix.closing, handler(closing), "Move cursor to the end of a delimited block"),
}
M.textobject = {
- inner = new(vis.textobject, vis.textobject_register, M.prefix.inner, inner, "Delimited block (inner variant)"),
- outer = new(vis.textobject, vis.textobject_register, M.prefix.outer, outer, "Delimited block (outer variant)"),
+ inner = new(vis.textobject, vis.textobject_register, M.prefix.inner, handler(inner), "Delimited block (inner variant)"),
+ outer = new(vis.textobject, vis.textobject_register, M.prefix.outer, handler(outer), "Delimited block (outer variant)"),
}
local tex_environment = {"\\begin{" * l.Cg(l.R("az", "AZ")^1, "t") * "}", l.Cmt("\\end{" * l.Cb("t") * l.C((1 - l.P"}")^1) * "}", function(_, _, c1, c2) return c1 == c2 end), {"\\begin{\xef\xbf\xbd}", "\\end{\xef\xbf\xbd}"}, "environment name"}