From 6d41f65aa45f10a93ad476db01413abaac21f27d Mon Sep 17 00:00:00 2001 From: shadmansaleh <13149513+shadmansaleh@users.noreply.github.com> Date: Thu, 30 Dec 2021 13:30:49 +0600 Subject: feat(lua): add vim.keymap This introduces two new functions `vim.keymap.set` & `vim.keymap.del` differences compared to regular set_keymap: - remap is used as opposite of noremap. By default it's true for keymaps and false for others. - rhs can be lua function. - mode can be a list of modes. - replace_keycodes option for lua function expr maps. (Default: true) - handles buffer specific keymaps Examples: ```lua vim.keymap.set('n', 'asdf', function() print("real lua function") end) vim.keymap.set({'n', 'v'}, 'lr', vim.lsp.buf.references, {buffer=true}) vim.keymap.set('n', 'w', "w", {silent = true, buffer = 5 }) vim.keymap.set('i', '', function() return vim.fn.pumvisible() == 1 and "" or "" end, {expr = true}) vim.keymap.set('n', '[%', '(MatchitNormalMultiBackward)') vim.keymap.del('n', 'asdf') vim.keymap.del({'n', 'i', 'v'}, 'w', {buffer = 5 }) ``` --- runtime/lua/vim/keymap.lua | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 runtime/lua/vim/keymap.lua (limited to 'runtime/lua/vim/keymap.lua') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua new file mode 100644 index 0000000000..d53b790746 --- /dev/null +++ b/runtime/lua/vim/keymap.lua @@ -0,0 +1,135 @@ +local keymap = {} + +--- Add a new |mapping|. +--- Examples: +---
+---   -- Can add mapping to Lua functions
+---   vim.keymap.set('n', 'lhs', function() print("real lua function") end)
+---
+---   -- Can use it to map multiple modes
+---   vim.keymap.set({'n', 'v'}, 'lr', vim.lsp.buf.references, { buffer=true })
+---
+---   -- Can add mapping for specific buffer
+---   vim.keymap.set('n', 'w', "w", { silent = true, buffer = 5 })
+---
+---   -- Expr mappings
+---   vim.keymap.set('i', '', function()
+---     return vim.fn.pumvisible() == 1 and "" or ""
+---   end, { expr = true })
+---   --  mappings
+---   vim.keymap.set('n', '[%%', '(MatchitNormalMultiBackward)')
+--- 
+--- +--- Note that in a mapping like: +---
+---    vim.keymap.set('n', 'asdf', require('jkl').my_fun)
+--- 
+--- +--- the require('jkl') gets evaluated during this call in order to access the function. If you want to +--- avoid this cost at startup you can wrap it in a function, for example: +---
+---    vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end)
+--- 
+--- +---@param mode string|table Same mode short names as |nvim_set_keymap()|. +--- Can also be list of modes to create mapping on multiple modes. +---@param lhs string Left-hand side |{lhs}| of the mapping. +---@param rhs string|function Right-hand side |{rhs}| of the mapping. Can also be a Lua function. +-- +---@param opts table A table of |:map-arguments| such as "silent". In addition to the options +--- listed in |nvim_set_keymap()|, this table also accepts the following keys: +--- - replace_keycodes: (boolean, default true) When both this and expr is "true", +--- |nvim_replace_termcodes()| is applied to the result of Lua expr maps. +--- - remap: (boolean) Make the mapping recursive. This is the +--- inverse of the "noremap" option from |nvim_set_keymap()|. +--- Default `true` if `lhs` is a string starting with `` (case-insensitive), `false` otherwise. +---@see |nvim_set_keymap()| +function keymap.set(mode, lhs, rhs, opts) + vim.validate { + mode = {mode, {'s', 't'}}, + lhs = {lhs, 's'}, + rhs = {rhs, {'s', 'f'}}, + opts = {opts, 't', true} + } + + opts = vim.deepcopy(opts) or {} + local is_rhs_luaref = type(rhs) == "function" + mode = type(mode) == 'string' and {mode} or mode + + if is_rhs_luaref and opts.expr and opts.replace_keycodes ~= false then + local user_rhs = rhs + rhs = function () + return vim.api.nvim_replace_termcodes(user_rhs(), true, true, true) + end + end + -- clear replace_keycodes from opts table + opts.replace_keycodes = nil + + if opts.remap == nil then + -- remap by default on mappings and don't otherwise. + opts.noremap = is_rhs_luaref or rhs:lower():match("^") == nil + else + -- remaps behavior is opposite of noremap option. + opts.noremap = not opts.remap + opts.remap = nil + end + + if is_rhs_luaref then + opts.callback = rhs + rhs = '' + end + + if opts.buffer then + local bufnr = opts.buffer == true and 0 or opts.buffer + opts.buffer = nil + for _, m in ipairs(mode) do + vim.api.nvim_buf_set_keymap(bufnr, m, lhs, rhs, opts) + end + else + opts.buffer = nil + for _, m in ipairs(mode) do + vim.api.nvim_set_keymap(m, lhs, rhs, opts) + end + end +end + +--- Remove an existing mapping. +--- Examples: +---
+---   vim.keymap.del('n', 'lhs')
+---
+---   vim.keymap.del({'n', 'i', 'v'}, 'w', { buffer = 5 })
+--- 
+---@param opts table A table of optional arguments: +--- - buffer: (number or boolean) Remove a mapping from the given buffer. +--- When "true" or 0, use the current buffer. +---@see |vim.keymap.set()| +--- +function keymap.del(modes, lhs, opts) + vim.validate { + mode = {modes, {'s', 't'}}, + lhs = {lhs, 's'}, + opts = {opts, 't', true} + } + + opts = opts or {} + modes = type(modes) == 'string' and {modes} or modes + + local buffer = false + if opts.buffer ~= nil then + buffer = opts.buffer == true and 0 or opts.buffer + opts.buffer = nil + end + + if buffer == false then + for _, mode in ipairs(modes) do + vim.api.nvim_del_keymap(mode, lhs) + end + else + for _, mode in ipairs(modes) do + vim.api.nvim_buf_del_keymap(buffer, mode, lhs) + end + end +end + +return keymap -- cgit