feat(keys): more advanced options for setting lazy key mappings

This commit is contained in:
Folke Lemaitre 2022-12-22 10:32:21 +01:00
parent 28f1511e0a
commit 1c07ea15a3
No known key found for this signature in database
GPG Key ID: 41F8B1FBACAE2040
4 changed files with 111 additions and 46 deletions

View File

@ -78,29 +78,29 @@ require("lazy").setup({
## 🔌 Plugin Spec ## 🔌 Plugin Spec
| Property | Type | Description | | Property | Type | Description |
| ---------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ---------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `[1]` | `string?` | Short plugin url. Will be expanded using `config.git.url_format` | | `[1]` | `string?` | Short plugin url. Will be expanded using `config.git.url_format` |
| **dir** | `string?` | A directory pointing to a local plugin | | **dir** | `string?` | A directory pointing to a local plugin |
| **url** | `string?` | A custom git url where the plugin is hosted | | **url** | `string?` | A custom git url where the plugin is hosted |
| **name** | `string?` | A custom name for the plugin used for the local plugin directory and as the display name | | **name** | `string?` | A custom name for the plugin used for the local plugin directory and as the display name |
| **dev** | `boolean?` | When `true`, a local plugin directory will be used instead. See `config.dev` | | **dev** | `boolean?` | When `true`, a local plugin directory will be used instead. See `config.dev` |
| **lazy** | `boolean?` | When `true`, the plugin will only be loaded when needed. Lazy-loaded plugins are automatically loaded when their lua modules are `required`, or when one of the laz-loading handlers triggers | | **lazy** | `boolean?` | When `true`, the plugin will only be loaded when needed. Lazy-loaded plugins are automatically loaded when their lua modules are `required`, or when one of the laz-loading handlers triggers |
| **enabled** | `boolean?` or `fun():boolean` | When `false`, or if the `function` returns false, then this plugin will not be used | | **enabled** | `boolean?` or `fun():boolean` | When `false`, or if the `function` returns false, then this plugin will not be used |
| **dependencies** | `LazySpec[]` | A list of plugin specs that should be loaded when the plugin loads. Dependencies are always lazy-loaded unless specified otherwise | | **dependencies** | `LazySpec[]` | A list of plugin specs that should be loaded when the plugin loads. Dependencies are always lazy-loaded unless specified otherwise |
| **init** | `fun(LazyPlugin)` | `init` functions are always executed during startup | | **init** | `fun(LazyPlugin)` | `init` functions are always executed during startup |
| **config** | `fun(LazyPlugin)` | `config` is executed when the plugin loads | | **config** | `fun(LazyPlugin)` | `config` is executed when the plugin loads |
| **build** | `fun(LazyPlugin)` | `build` is executed when a plugin is installed or updated | | **build** | `fun(LazyPlugin)` | `build` is executed when a plugin is installed or updated |
| **branch** | `string?` | Branch of the repository | | **branch** | `string?` | Branch of the repository |
| **tag** | `string?` | Tag of the repository | | **tag** | `string?` | Tag of the repository |
| **commit** | `string?` | Commit of the repository | | **commit** | `string?` | Commit of the repository |
| **version** | `string?` | Version to use from the repository. Full [Semver](https://devhints.io/semver) ranges are supported | | **version** | `string?` | Version to use from the repository. Full [Semver](https://devhints.io/semver) ranges are supported |
| **pin** | `boolean?` | When `true`, this plugin will not be included in updates | | **pin** | `boolean?` | When `true`, this plugin will not be included in updates |
| **event** | `string?` or `string[]` | Lazy-load on event | | **event** | `string?` or `string[]` | Lazy-load on event |
| **cmd** | `string?` or `string[]` | Lazy-load on command | | **cmd** | `string?` or `string[]` | Lazy-load on command |
| **ft** | `string?` or `string[]` | Lazy-load on filetype | | **ft** | `string?` or `string[]` | Lazy-load on filetype |
| **keys** | `string?` or `string[]` | Lazy-load on key mapping | | **keys** | `string?` or `string[]` or `LazyKeys[]` | Lazy-load on key mapping |
| **module** | `false?` | Do not automatically load this lua module when it's required somewhere | | **module** | `false?` | Do not automatically load this lua module when it's required somewhere |
### Lazy Loading ### Lazy Loading
@ -124,6 +124,33 @@ Plugins will be lazy-loaded when one of the following is `true`:
- it defines an `init` method - it defines an `init` method
- `config.defaults.lazy == true` - `config.defaults.lazy == true`
#### ⌨️ Lazy Key Mappings
The `keys` property can be a `string` or `string[]` for simple normal-mode mappings, or it
can be a `LazyKeys` table with the following key-value pairs:
- **[1]**: (`string`) lhs **_(required)_**
- **[2]**: (`string|fun()`) rhs **_(optional)_**
- **mode**: (`string|string[]`) mode **_(optional, defaults to `"n"`)_**
- any other option valid for `vim.keymap.set`
Key mappings will load the plugin the first time they get executed.
When `[2]` is `nil`, then the real mapping has to be created by the `config()` function.
```lua
-- Example for neo-tree.nvim
{
"nvim-neo-tree/neo-tree.nvim",
keys = {
{ "<leader>ft", "<cmd>Neotree toggle<cr>", desc = "NeoTree" },
},
config = function()
require("neo-tree").setup()
end,
}
```
### Versioning ### Versioning
If you want to install a specific revision of a plugin, you can use `commit`, If you want to install a specific revision of a plugin, you can use `commit`,

View File

@ -1,32 +1,66 @@
local Util = require("lazy.core.util") local Util = require("lazy.core.util")
local Loader = require("lazy.core.loader") local Loader = require("lazy.core.loader")
---@class LazyKeys
---@field [1] string lhs
---@field [2]? string|fun() rhs
---@field desc? string
---@field mode? string|string[]
---@field noremap? boolean
---@field remap? boolean
---@field expr? boolean
---@class LazyKeysHandler:LazyHandler ---@class LazyKeysHandler:LazyHandler
local M = {} local M = {}
---@param keys string function M.retrigger(keys)
function M:_add(keys) local pending = ""
vim.keymap.set("n", keys, function() while true do
vim.keymap.del("n", keys) local c = vim.fn.getchar(0)
Util.track({ keys = keys }) if c == 0 then
Loader.load(self.active[keys], { keys = keys }) break
local extra = ""
while true do
local c = vim.fn.getchar(0)
if c == 0 then
break
end
extra = extra .. vim.fn.nr2char(c)
end end
local feed = vim.api.nvim_replace_termcodes(keys .. extra, true, true, true) pending = pending .. vim.fn.nr2char(c)
vim.api.nvim_feedkeys(feed, "m", false) end
Util.track() local feed = vim.api.nvim_replace_termcodes(keys .. pending, true, true, true)
end, { silent = true }) vim.api.nvim_feedkeys(feed, "m", false)
end end
---@param keys string ---@param value string|LazyKeys
function M:_del(keys) function M.parse(value)
pcall(vim.keymap.del, "n", keys) return (type(value) == "string" and { value } or value) --[[@as LazyKeys]]
end
function M.opts(keys)
local opts = {}
for k, v in pairs(keys) do
if type(k) ~= "number" and k ~= "mode" then
opts[k] = v
end
end
return opts
end
---@param value string|LazyKeys
function M:_add(value)
local keys = M.parse(value)
local lhs = keys[1]
vim.keymap.set(keys.mode or "n", lhs, function()
Util.track({ keys = lhs })
self:_del(value)
Loader.load(self.active[value], { keys = lhs })
M.retrigger(lhs)
Util.track()
end, M.opts(keys))
end
---@param value string|LazyKeys
function M:_del(value)
local keys = M.parse(value)
pcall(vim.keymap.del, "n", keys[1])
if keys[2] then
vim.keymap.set(keys.mode or "n", keys[1], keys[2], M.opts(keys))
end
end end
return M return M

View File

@ -156,7 +156,7 @@ end
function M.foreach(t, fn) function M.foreach(t, fn)
---@type string[] ---@type string[]
local keys = vim.tbl_keys(t) local keys = vim.tbl_keys(t)
table.sort(keys) pcall(table.sort, keys)
for _, key in ipairs(keys) do for _, key in ipairs(keys) do
fn(key, t[key]) fn(key, t[key])
end end

View File

@ -272,6 +272,9 @@ function M:reason(reason, opts)
if key == "event" then if key == "event" then
value = value:match("User (.*)") or value value = value:match("User (.*)") or value
end end
if key == "keys" then
value = type(value) == "string" and value or value[1]
end
local hl = "LazyHandler" .. key:sub(1, 1):upper() .. key:sub(2) local hl = "LazyHandler" .. key:sub(1, 1):upper() .. key:sub(2)
local icon = Config.options.ui.icons[key] local icon = Config.options.ui.icons[key]
if icon then if icon then
@ -493,13 +496,14 @@ function M:debug()
) )
:nl() :nl()
Util.foreach(require("lazy.core.handler").handlers, function(type, handler) Util.foreach(require("lazy.core.handler").handlers, function(handler_type, handler)
Util.foreach(handler.active, function(value, plugins) Util.foreach(handler.active, function(value, plugins)
value = type(value) == "table" and value[1] or value
if not vim.tbl_isempty(plugins) then if not vim.tbl_isempty(plugins) then
plugins = vim.tbl_values(plugins) plugins = vim.tbl_values(plugins)
table.sort(plugins) table.sort(plugins)
self:append("", "LazySpecial", { indent = 2 }) self:append("", "LazySpecial", { indent = 2 })
self:reason({ [type] = value }) self:reason({ [handler_type] = value })
for _, plugin in pairs(plugins) do for _, plugin in pairs(plugins) do
self:append(" ") self:append(" ")
self:reason({ plugin = plugin }) self:reason({ plugin = plugin })