diff --git a/README.md b/README.md index 829dcbd..c60c951 100644 --- a/README.md +++ b/README.md @@ -197,8 +197,8 @@ we'd like to include the following features in future versions: - [ ] API for creating user autocommands. - [ ] Support passing mapping mode in opts. - [ ] Support specifying multiple modes as a string like 'nvt'. -- [ ] Support specifying labels on groups which become which-key group names. -- [ ] Support progressively building up maps with groups, like: +- [x] Support specifying labels on groups which become which-key group names. +- [x] Support progressively building up maps with groups, like: ```lua mapx.group({ prefix = "t" }, "LSP", function() diff --git a/lua/mapx/mapper.lua b/lua/mapx/mapper.lua index 37068d3..5877d5b 100644 --- a/lua/mapx/mapper.lua +++ b/lua/mapx/mapper.lua @@ -1,4 +1,6 @@ -local merge = require('mapx.util').merge +local util = require 'mapx.util' +local merge = util.merge +local setMerge = util.setMerge local log = require 'mapx.log' local dbgi = log.dbgi @@ -11,6 +13,7 @@ local Mapper = { script = { script = true }, expr = { expr = true }, unique = { unique = true }, + prefix = { prefix = '' }, }, } @@ -22,12 +25,12 @@ local function expandStringOpts(opts) for k, v in pairs(opts) do if type(k) == 'number' then if Mapper.mapopts[v] then - res[v] = true + res = merge(res, Mapper.mapopts[v]) goto continue end local vsub = type(v) == 'string' and vim.fn.substitute(v, [[^<\|>$]], '', 'g') if vsub and Mapper.mapopts[vsub] ~= nil then - res[vsub] = true + res = merge(res, Mapper.mapopts[vsub]) goto continue end table.insert(res, v) @@ -57,6 +60,7 @@ function Mapper.new() luaFuncs = {}, filetypeMaps = {}, groupOpts = {}, + groupMapsType = {}, groupActive = false, whichkey = nil, } @@ -179,6 +183,19 @@ function Mapper:register(config, lhss, rhs, ...) if type(lhss) ~= 'table' then lhss = { lhss } end + + if opts.prefix ~= nil then + local new_lhss = {} + for _, lhs in ipairs(lhss) do + table.insert(new_lhss, opts.prefix .. lhs) + end + lhss = new_lhss + opts.prefix = nil + end + if self.groupActive then + self.groupMapsType[config.mode] = true + end + if type(rhs) == 'function' then -- TODO: rhs gets inserted multiple times if a filetype mapping is -- triggered multiple times @@ -212,18 +229,38 @@ function Mapper:group(...) end end self.groupOpts = expandStringOpts(self.groupOpts) + self.groupOpts = self:normalizeOpts(self.groupOpts) dbgi('group', self.groupOpts) - local opts = self:normalizeOpts(self.groupOpts) - if opts.label ~= nil then - error('mapx.group: cannot set label on group: ' .. tostring(opts.label)) + local opts = self.groupOpts + if opts.label ~= nil and opts.prefix == nil then + error('mapx.group: cannot set label on group without prefix: ' .. tostring(opts.label)) end + local label = opts.label + opts.label = nil local prevGroupActive = self.groupActive + local prevGroupMapsType = self.groupMapsType self.groupActive = true + self.groupMapsType = {} fn() + if opts.prefix ~= nil and label ~= nil then + local new_opts = vim.deepcopy(opts) + new_opts.name = label + new_opts.prefix = nil + for k, v in pairs(self.groupMapsType) do + if v then + self:registerName(k, opts.prefix, new_opts) + end + end + end self.groupActive = prevGroupActive self.groupOpts = prevOpts - if self.groupActive == false and self.whichkey then - self.whichkey:flush() + self.groupMapsType = setMerge(self.groupMapsType, prevGroupMapsType) + self.groupActive = true + if self.groupActive == false then + if self.whichkey then + self.whichkey:flush() + end + self.groupMapsType = {} end end diff --git a/lua/mapx/util.lua b/lua/mapx/util.lua index f4519f1..c9b8bda 100644 --- a/lua/mapx/util.lua +++ b/lua/mapx/util.lua @@ -1,5 +1,23 @@ local M = {} +-- Flat merge of 2 or more tables, supporting a mixture of map-like tables and +-- list-list tables. +-- - Right-most arguments take precedence. +-- - Numeric indices are extended, not replaced. +-- - No side effects. +function M.setMerge(...) + local res = {} + for i = 1, select('#', ...) do + local arg = select(i, ...) + for k, v in pairs(arg) do + if v then + res[k] = true + end + end + end + return res +end + -- Flat merge of 2 or more tables, supporting a mixture of map-like tables and -- list-list tables. -- - Right-most arguments take precedence. @@ -13,6 +31,8 @@ function M.merge(...) for k, v in pairs(arg) do if type(k) == 'number' then table.insert(res, v) + elseif k == 'prefix' then + res[k] = res[k] ~= nil and res[k] .. v or v else res[k] = v end