mirror of
				https://github.com/folke/lazy.nvim.git
				synced 2025-11-04 00:11:06 +00:00 
			
		
		
		
	## Description
<!-- Describe the big picture of your changes to communicate to the
maintainers
  why we should accept this pull request. -->
when `expr=true` the rhs function should return a string.
example
```lua
{
    keys = {
        {
            '<leader>j',
            function()
                return require('dial.map').inc_normal()
            end,
            expr = true,
            desc = 'Increment value',
        }
    }
}
```
## Related Issue(s)
<!--
  If this PR fixes any issues, please link to the issue here.
  - Fixes #<issue_number>
-->
## Screenshots
<!-- Add screenshots of the changes if applicable. -->
		
	
			
		
			
				
	
	
		
			202 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local Loader = require("lazy.core.loader")
 | 
						|
local Util = require("lazy.core.util")
 | 
						|
 | 
						|
---@class LazyKeysBase
 | 
						|
---@field desc? string
 | 
						|
---@field noremap? boolean
 | 
						|
---@field remap? boolean
 | 
						|
---@field expr? boolean
 | 
						|
---@field nowait? boolean
 | 
						|
---@field ft? string|string[]
 | 
						|
 | 
						|
---@class LazyKeysSpec: LazyKeysBase
 | 
						|
---@field [1] string lhs
 | 
						|
---@field [2]? string|fun():string?|false rhs
 | 
						|
---@field mode? string|string[]
 | 
						|
 | 
						|
---@class LazyKeys: LazyKeysBase
 | 
						|
---@field lhs string lhs
 | 
						|
---@field rhs? string|fun() rhs
 | 
						|
---@field mode? string
 | 
						|
---@field id string
 | 
						|
---@field name string
 | 
						|
 | 
						|
---@class LazyKeysHandler:LazyHandler
 | 
						|
local M = {}
 | 
						|
 | 
						|
local skip = { mode = true, id = true, ft = true, rhs = true, lhs = true }
 | 
						|
 | 
						|
---@param value string|LazyKeysSpec
 | 
						|
---@param mode? string
 | 
						|
---@return LazyKeys
 | 
						|
function M.parse(value, mode)
 | 
						|
  value = type(value) == "string" and { value } or value --[[@as LazyKeysSpec]]
 | 
						|
  local ret = vim.deepcopy(value) --[[@as LazyKeys]]
 | 
						|
  ret.lhs = ret[1] or ""
 | 
						|
  ret.rhs = ret[2]
 | 
						|
  ---@diagnostic disable-next-line: no-unknown
 | 
						|
  ret[1] = nil
 | 
						|
  ---@diagnostic disable-next-line: no-unknown
 | 
						|
  ret[2] = nil
 | 
						|
  ret.mode = mode or "n"
 | 
						|
  ret.id = vim.api.nvim_replace_termcodes(ret.lhs, true, true, true)
 | 
						|
 | 
						|
  if ret.ft then
 | 
						|
    local ft = type(ret.ft) == "string" and { ret.ft } or ret.ft --[[@as string[] ]]
 | 
						|
    ret.id = ret.id .. " (" .. table.concat(ft, ", ") .. ")"
 | 
						|
  end
 | 
						|
 | 
						|
  if ret.mode ~= "n" then
 | 
						|
    ret.id = ret.id .. " (" .. ret.mode .. ")"
 | 
						|
  end
 | 
						|
  return ret
 | 
						|
end
 | 
						|
 | 
						|
---@param keys LazyKeys
 | 
						|
function M.to_string(keys)
 | 
						|
  return keys.lhs .. (keys.mode == "n" and "" or " (" .. keys.mode .. ")")
 | 
						|
end
 | 
						|
 | 
						|
---@param lhs string
 | 
						|
---@param mode? string
 | 
						|
function M:have(lhs, mode)
 | 
						|
  local keys = M.parse(lhs, mode)
 | 
						|
  return self.managed[keys.id] ~= nil
 | 
						|
end
 | 
						|
 | 
						|
function M:_values(values)
 | 
						|
  return M.resolve(values)
 | 
						|
end
 | 
						|
 | 
						|
---@param spec? (string|LazyKeysSpec)[]
 | 
						|
function M.resolve(spec)
 | 
						|
  ---@type LazyKeys[]
 | 
						|
  local values = {}
 | 
						|
  ---@diagnostic disable-next-line: no-unknown
 | 
						|
  for _, value in ipairs(spec or {}) do
 | 
						|
    value = type(value) == "string" and { value } or value --[[@as LazyKeysSpec]]
 | 
						|
    value.mode = value.mode or "n"
 | 
						|
    local modes = (type(value.mode) == "table" and value.mode or { value.mode }) --[=[@as string[]]=]
 | 
						|
    for _, mode in ipairs(modes) do
 | 
						|
      local keys = M.parse(value, mode)
 | 
						|
      if keys.rhs == vim.NIL or keys.rhs == false then
 | 
						|
        values[keys.id] = nil
 | 
						|
      else
 | 
						|
        values[keys.id] = keys
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
  return values
 | 
						|
end
 | 
						|
 | 
						|
---@param keys LazyKeys
 | 
						|
function M.opts(keys)
 | 
						|
  local opts = {} ---@type LazyKeysBase
 | 
						|
  ---@diagnostic disable-next-line: no-unknown
 | 
						|
  for k, v in pairs(keys) do
 | 
						|
    if type(k) ~= "number" and not skip[k] then
 | 
						|
      ---@diagnostic disable-next-line: no-unknown
 | 
						|
      opts[k] = v
 | 
						|
    end
 | 
						|
  end
 | 
						|
  return opts
 | 
						|
end
 | 
						|
 | 
						|
---@param keys LazyKeys
 | 
						|
function M.is_nop(keys)
 | 
						|
  return type(keys.rhs) == "string" and (keys.rhs == "" or keys.rhs:lower() == "<nop>")
 | 
						|
end
 | 
						|
 | 
						|
---@param keys LazyKeys
 | 
						|
function M:_add(keys)
 | 
						|
  local lhs = keys.lhs
 | 
						|
  local opts = M.opts(keys)
 | 
						|
 | 
						|
  ---@param buf? number
 | 
						|
  local function add(buf)
 | 
						|
    if M.is_nop(keys) then
 | 
						|
      return self:_set(keys, buf)
 | 
						|
    end
 | 
						|
 | 
						|
    vim.keymap.set(keys.mode, lhs, function()
 | 
						|
      local plugins = self.active[keys.id]
 | 
						|
 | 
						|
      -- always delete the mapping immediately to prevent recursive mappings
 | 
						|
      self:_del(keys)
 | 
						|
      self.active[keys.id] = nil
 | 
						|
 | 
						|
      if plugins then
 | 
						|
        local name = M.to_string(keys)
 | 
						|
        Util.track({ keys = name })
 | 
						|
        Loader.load(plugins, { keys = name })
 | 
						|
        Util.track()
 | 
						|
      end
 | 
						|
 | 
						|
      if keys.mode:sub(-1) == "a" then
 | 
						|
        lhs = lhs .. "<C-]>"
 | 
						|
      end
 | 
						|
      local feed = vim.api.nvim_replace_termcodes("<Ignore>" .. lhs, true, true, true)
 | 
						|
      -- insert instead of append the lhs
 | 
						|
      vim.api.nvim_feedkeys(feed, "i", false)
 | 
						|
    end, {
 | 
						|
      desc = opts.desc,
 | 
						|
      nowait = opts.nowait,
 | 
						|
      -- we do not return anything, but this is still needed to make operator pending mappings work
 | 
						|
      expr = true,
 | 
						|
      buffer = buf,
 | 
						|
    })
 | 
						|
  end
 | 
						|
 | 
						|
  -- buffer-local mappings
 | 
						|
  if keys.ft then
 | 
						|
    vim.api.nvim_create_autocmd("FileType", {
 | 
						|
      pattern = keys.ft,
 | 
						|
      callback = function(event)
 | 
						|
        if self.active[keys.id] and not M.is_nop(keys) then
 | 
						|
          add(event.buf)
 | 
						|
        else
 | 
						|
          -- Only create the mapping if its managed by lazy
 | 
						|
          -- otherwise the plugin is supposed to manage it
 | 
						|
          self:_set(keys, event.buf)
 | 
						|
        end
 | 
						|
      end,
 | 
						|
    })
 | 
						|
  else
 | 
						|
    add()
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
-- Delete a mapping and create the real global/buffer-local
 | 
						|
-- mapping when needed
 | 
						|
---@param keys LazyKeys
 | 
						|
function M:_del(keys)
 | 
						|
  -- bufs will be all buffers of the filetype for a buffer-local mapping
 | 
						|
  -- OR `false` for a global mapping
 | 
						|
  local bufs = { false }
 | 
						|
 | 
						|
  if keys.ft then
 | 
						|
    local ft = type(keys.ft) == "string" and { keys.ft } or keys.ft --[[@as string[] ]]
 | 
						|
    bufs = vim.tbl_filter(function(buf)
 | 
						|
      return vim.tbl_contains(ft, vim.bo[buf].filetype)
 | 
						|
    end, vim.api.nvim_list_bufs())
 | 
						|
  end
 | 
						|
 | 
						|
  for _, buf in ipairs(bufs) do
 | 
						|
    pcall(vim.keymap.del, keys.mode, keys.lhs, { buffer = buf or nil })
 | 
						|
    self:_set(keys, buf or nil)
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
-- Create a mapping if it is managed by lazy
 | 
						|
---@param keys LazyKeys
 | 
						|
---@param buf number?
 | 
						|
function M:_set(keys, buf)
 | 
						|
  if keys.rhs then
 | 
						|
    local opts = M.opts(keys)
 | 
						|
    ---@diagnostic disable-next-line: inject-field
 | 
						|
    opts.buffer = buf
 | 
						|
    vim.keymap.set(keys.mode, keys.lhs, keys.rhs, opts)
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
return M
 |