From 508e8d162e67774a7658097943741ce2691cf0c7 Mon Sep 17 00:00:00 2001 From: Georgi Kirilov <> Date: Sun, 22 Nov 2020 15:10:50 +0200 Subject: Prevent conflicts with external key mappings The global single-letter mappings were shadowed by longer window-local mappings outside the plugin. Add help field for the built-in and any custom global mappings. (Had to make vis-surround ignore it, too.) --- pairs.lua | 84 ++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 28 deletions(-) (limited to 'pairs.lua') diff --git a/pairs.lua b/pairs.lua index 8ad1ea2..93808f3 100644 --- a/pairs.lua +++ b/pairs.lua @@ -9,13 +9,13 @@ local l = require("lpeg") local M local builtin_textobjects = { - ["["] = { "[" , "]" }, - ["{"] = { "{" , "}" }, - ["<"] = { "<" , ">" }, - ["("] = { "(" , ")" }, - ['"'] = { '"' , '"' }, - ["'"] = { "'" , "'" }, - ["`"] = { "`" , "`" }, + ["["] = { "[" , "]", "[] block" }, + ["{"] = { "{" , "}", "{} block" }, + ["<"] = { "<" , ">", "<> block" }, + ["("] = { "(" , ")", "() block" }, + ['"'] = { '"' , '"', "A quoted string" }, + ["'"] = { "'" , "'", "A single quoted string" }, + ["`"] = { "`" , "`", "A backtick delimited string" }, } local builtin_motions = { @@ -250,6 +250,23 @@ local function bail_early() return false end +local function win_map(textobject, prefix, binding, help) + return function(win) + if not textobject then + win:map(vis.modes.NORMAL, prefix, binding, help) + end + win:map(vis.modes.VISUAL, prefix, binding, help) + win:map(vis.modes.OPERATOR_PENDING, prefix, binding, help) + end +end + +local function bind_builtin(key, execute, id) + return function() + M.key = key + execute(vis, id) + end +end + local function prep(func) return function(win, pos) if bail_early() then return pos end @@ -258,6 +275,8 @@ local function prep(func) end end +local mappings = {} + local function new(execute, register, prefix, handler, help) local id = register(vis, prep(handler)) if id < 0 then @@ -272,42 +291,37 @@ local function new(execute, register, prefix, handler, help) end return #keys end - if execute ~= vis.textobject then - vis:map(vis.modes.NORMAL, prefix, binding, help) - end - vis:map(vis.modes.VISUAL, prefix, binding, help) - vis:map(vis.modes.OPERATOR_PENDING, prefix, binding, help) + table.insert(mappings, win_map(execute == vis.textobject, prefix, binding, help)) local builtin = execute == vis.motion and builtin_motions[prefix] or builtin_textobjects for key, _ in pairs(builtin) do + local hlp = (execute == vis.motion and help or "") .. builtin_textobjects[key][3] if execute ~= vis.textobject then - vis:unmap(vis.modes.NORMAL, prefix..key) + vis:map(vis.modes.NORMAL, prefix..key, bind_builtin(key, execute, id), hlp) end - vis:unmap(vis.modes.VISUAL, prefix..key) - vis:unmap(vis.modes.OPERATOR_PENDING, prefix..key) + local variant = prefix == M.prefix.outer and " (outer variant)" or prefix == M.prefix.inner and " (inner variant)" or "" + vis:map(vis.modes.VISUAL, prefix..key, bind_builtin(key, execute, id), hlp and hlp .. variant or help) + vis:map(vis.modes.OPERATOR_PENDING, prefix..key, bind_builtin(key, execute, id), hlp and hlp .. variant or help) end end return id 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"), - } - 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)"), - } +vis.events.subscribe(vis.events.WIN_OPEN, function(win) + for _, map_keys in ipairs(mappings) do + map_keys(win) + end +end) +vis.events.subscribe(vis.events.INIT, function() local function cmp(_, _, c1, c2) return c1 == c2 end local function casecmp(_, _, c1, c2) return c1:lower() == c2:lower() end - local function closing(s1, s2, cmpfunc) return l.Cmt(s1 * l.Cb("t") * l.C((1 - l.P(s2))^1) * s2, cmpfunc) end - local tex_environment = {"\\begin{" * l.Cg(l.R("az", "AZ")^1, "t") * "}", closing("\\end{", "}", cmp), {"\\begin{\xef\xbf\xbd}", "\\end{\xef\xbf\xbd}"}, "environment name"} + local function end_tag(s1, s2, cmpfunc) return l.Cmt(s1 * l.Cb("t") * l.C((1 - l.P(s2))^1) * s2, cmpfunc) end + local tex_environment = {"\\begin{" * l.Cg(l.R("az", "AZ")^1, "t") * "}", end_tag("\\end{", "}", cmp), {"\\begin{\xef\xbf\xbd}", "\\end{\xef\xbf\xbd}"}, "environment name"} local tag_name = (l.S"_:" + l.R("az", "AZ")) * (l.R("az", "AZ", "09") + l.S"_:.-")^0 local noslash = {--[[implicit:]] p=1, dt=1, dd=1, li=1, --[[void:]] area=1, base=1, br=1, col=1, embed=1, hr=1, img=1, input=1, link=1, meta=1, param=1, source=1, track=1, wbr=1} local function is_not(_, _, v) return v ~= 1 end - local html_tag = {"<" * l.Cg(l.Cmt(tag_name / string.lower / noslash, is_not), "t") * (1 - l.S"><")^0 * (">" - l.B"/"), closing("", casecmp), {"<\xef\xbf\xbd>", ""}, "tag name"} - local xml_tag = {"<" * l.Cg(tag_name, "t") * (1 - l.S"><")^0 * (">" - l.B"/"), closing("", cmp), {"<\xef\xbf\xbd>", ""}, "tag name"} + local html_tag = {"<" * l.Cg(l.Cmt(tag_name / string.lower / noslash, is_not), "t") * (1 - l.S"><")^0 * (">" - l.B"/"), end_tag("", casecmp), {"<\xef\xbf\xbd>", ""}, "tag name"} + local xml_tag = {"<" * l.Cg(tag_name, "t") * (1 - l.S"><")^0 * (">" - l.B"/"), end_tag("", cmp), {"<\xef\xbf\xbd>", ""}, "tag name", " block"} local function any_pair(set, default) return {l.Cg(l.S(set), "s"), l.Cmt(l.Cb("s") * l.C(1), function(_, _, c1, c2) return builtin_textobjects[c1][2] == c2 end), builtin_textobjects[default]} end local any_bracket = any_pair("({[", "(") local presets = { @@ -333,6 +347,20 @@ vis.events.subscribe(vis.events.INIT, function() end end end + for key, d in pairs(M.map[1]) do + builtin_textobjects[key] = {d[1], d[2], d[#d]} + builtin_motions[M.prefix.opening][key] = true + builtin_motions[M.prefix.closing][key] = true + end + + M.motion = { + opening = new(vis.motion, vis.motion_register, M.prefix.opening, opening, "Move cursor to the beginning of a "), + closing = new(vis.motion, vis.motion_register, M.prefix.closing, closing, "Move cursor to the end of a "), + } + 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)"), + } end) -- cgit