diff --git a/README.md b/README.md index ff2d3bd..65acfc7 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,19 @@ A [neovim] plugin and configuration management plugin, highly inspired by [lazy] - [Features](#features) - [SemVer](#semver) - [Installation](#installation) - - [Flake installation](#flake-installation) + - [Flake installation](#flake-installation) - [Usage](#usage) - [Documentation](#documentation) - - [nix](#nix) - - [`mkNeovimPkg`](#mkneovimpkg) - - [neovim (lua)](#neovim-lua) - - [Using default `init.lua`](#using-default-initlua) - - [Using your own `init.lua`](#using-your-own-initlua) - - [`:Sloth` command](#sloth-command) - - [`list` subcommand](#list-subcommand) - - [`load` subcommand](#load-subcommand) - - [`version` subcommand](#version-subcommand) - - [API](#api) + - [nix](#nix) + - [`mkNeovimPkg`](#mkneovimpkg) + - [neovim (lua)](#neovim-lua) + - [Using default `init.lua`](#using-default-initlua) + - [Using your own `init.lua`](#using-your-own-initlua) + - [`:Sloth` command](#sloth-command) + - [`list` subcommand](#list-subcommand) + - [`load` subcommand](#load-subcommand) + - [`version` subcommand](#version-subcommand) + - [API](#api) @@ -45,7 +45,7 @@ A [neovim] plugin and configuration management plugin, highly inspired by [lazy] - [X] on command - [X] on filetype - [X] on event - - [ ] on keybinding + - [X] on keybinding - [X] load plugins in order (via plugin `dependencies` property) - [X] Have a `:Sloth` command to load or query your plugins - [ ] Generate spell files on build (maybe) @@ -167,6 +167,7 @@ The Plugin configuration object accepts the following properties: | `cmd` | `[]` | Command to put as place_holder to load the lazy plugin⁴ | | `ft` | `[]` | Filetype to watch to load the lazy plugin⁴ | | `events` | `[]` | Events to watch to load the lazy plugin⁴⁵ | +| `keymaps` | `[]` | Keymaps that when press will load the lazy plugin⁴⁶ | > ² The plugin can be either a nix package or an object with only `name` and > `src` as properties. The latter will be used to create a nix package of your @@ -183,6 +184,8 @@ The Plugin configuration object accepts the following properties: > represent a simple event name and pattern with the following string format : > "BufRead *.md". +> ⁶ Keymaps can be a string, an Keymap object or a list of either. + The Event configuration object accepts the following properties: | name | default | description | @@ -190,6 +193,13 @@ The Event configuration object accepts the following properties: | `name` | N/A | The name of the event as string or list of string **REQUIRED** | | `pattern` | `null` | Pattern (as string or list of string) associated to the event | +The Keymap configuration object accepts the following properties: + +| name | default | description | +|-----------|---------|----------------------------------------------------| +| `mode` | `"n"` | The mode of the keymap as string or list of string | +| `mapping` | N/A | The actual mapping **REQUIRED** | + ### neovim (lua) #### Using default `init.lua` diff --git a/lib/deps.nix b/lib/deps.nix index 33bda61..b72253e 100644 --- a/lib/deps.nix +++ b/lib/deps.nix @@ -28,6 +28,7 @@ cmd = []; ft = []; events = []; + keymaps = []; }; remotePluginToNeovimPlugin = p: @@ -36,19 +37,32 @@ pname = name; }; + defaultKeymap = {mode = "n";}; + normalizeKeymap = keymap: let + value = ( + if isString keymap + then {mapping = keymap;} + else keymap + ); + in + mapAttrs (_: wrapArray) (defaultKeymap // value); + normalizeKeymaps = keymaps: + if isList keymaps + then map normalizeKeymap keymaps + else [(normalizeKeymap keymaps)]; + normalizeEvent = event: let value = if ! isString event then event - else - if ! hasMatch ".* .*" event - then {name = event;} - else let - part = elemAt (splitString " " event); - in { - name = part 0; - pattern = part 1; - }; + else if ! hasMatch ".* .*" event + then {name = event;} + else let + part = elemAt (splitString " " event); + in { + name = part 0; + pattern = part 1; + }; in mapAttrs (_: wrapArray) value; normalizeEvents = events: @@ -74,9 +88,11 @@ // rec { hasCommands = p.cmd != []; hasFileTypes = p.ft != []; + keymaps = normalizeKeymaps p.keymaps; + hasKeymaps = p.keymaps != []; events = normalizeEvents p.events; hasEvents = p.events != []; - lazy = p.lazy || hasCommands || hasFileTypes || hasEvents; + lazy = p.lazy || hasCommands || hasFileTypes || hasEvents || hasKeymaps; optional = lazy || p.init != null; }; @@ -135,7 +151,6 @@ else content; pluginLuaDef = memo: plugin: let - # plugin = builtins.removeAttrs plugin ["dependencies" "plugin"]; mkTypeFn = type: let content = textOrContent plugin.${type}; in @@ -168,6 +183,9 @@ }) // (optionalAttrs plugin.hasEvents { inherit (plugin) events; + }) + // (optionalAttrs plugin.hasKeymaps { + inherit (plugin) keymaps; }); }; pluginsLuaDef = plugins: diff --git a/lib/types.nix b/lib/types.nix index de8bd55..e0d262c 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -1,4 +1,10 @@ -{yants, ...}: rec { +{yants, ...}: let + stringList = with yants; list string; + stringOrStringList = with yants; either string stringList; + stringOrStringListOr = type: + with yants; + option (eitherN [string type (list (either string type))]); +in rec { # The runtime object runtimeType = with yants; struct "runtime" { @@ -24,14 +30,22 @@ eventType = with yants; struct "event" { - name = either string stringList; - pattern = either string stringList; + # The name of the event + name = stringOrStringList; + # The pattern of the event + pattern = stringOrStringList; + }; + + keymapType = with yants; + struct "keymap" { + # The mode of the keymap + mode = option stringOrStringList; + # The mapping of the keymap + mapping = stringOrStringList; }; # The plugin type of dependencies - pluginType = with yants; let - stringList = list string; - in + pluginType = with yants; struct "plugin" { # Whether this plugin should be enabled. This option allows specific # plugins to be disabled. @@ -55,7 +69,7 @@ lazy = option bool; # List of events on which the plugin should be loaded - events = option (eitherN [string eventType (list (either string eventType))]); + events = option (stringOrStringListOr eventType); # List of commands on which the plugin should be loaded cmd = option stringList; @@ -64,7 +78,7 @@ ft = option stringList; # List of keystrokes on which the plugin should be loaded - # keys = option stringList; + keymaps = option (stringOrStringListOr keymapType); # Priority of the module. Influence the order of loading plugins. # Highest values get loaded before. diff --git a/lua/sloth-flake/dep.lua b/lua/sloth-flake/dep.lua index d3a12ee..0864f7f 100644 --- a/lua/sloth-flake/dep.lua +++ b/lua/sloth-flake/dep.lua @@ -18,40 +18,7 @@ function M.new(values) self.sm = state_machine.build(State, { enter = { [State.Shimed] = function() - if self.cmd then - for _, cmd in ipairs(self.cmd) do - vim.api.nvim_create_user_command(cmd, self:lazy_load_cmd(cmd), { - desc = "Sloth-flake placeholder for plugin " .. self.name, - nargs = '*', - bang = true, - }) - end - end - - if self.has_events then - local group_id = vim.api.nvim_create_augroup(self.augroup_name, { - clear = true, - }) - - if self.ft then - vim.api.nvim_create_autocmd('FileType', { - group = group_id, - pattern = self.ft, - callback = self:lazy_load_event('FileType') - }) - end - - if self.events then - for _, event in ipairs(self.events) do - -- print("register event", event.name, "for pattern", event.pattern) - vim.api.nvim_create_autocmd(event.name, { - group = group_id, - pattern = event.pattern, - callback = self:lazy_load_event(event.name) - }) - end - end - end + return self:_shim() end, [State.Inited] = function() for _, dep in ipairs(self.dependencies) do @@ -81,15 +48,7 @@ function M.new(values) }, exit = { [State.Shimed] = function() - if self.cmd then - for _, cmd in ipairs(self.cmd) do - vim.api.nvim_del_user_command(cmd) - end - end - - if self.has_events then - vim.api.nvim_del_augroup_by_name(self.augroup_name) - end + self:_unshim() end, }, events = { @@ -152,6 +111,10 @@ function M:get_events() return self.values.events end +function M:get_keymaps() + return self.values.keymaps +end + function M:get_is_lazy() return self.values.lazy or false end @@ -180,6 +143,70 @@ function M:shim() return self.sm:shim() end +function M:_shim() + if self.cmd then + for _, cmd in ipairs(self.cmd) do + vim.api.nvim_create_user_command(cmd, self:lazy_load_cmd(cmd), { + desc = "Sloth-flake placeholder for plugin " .. self.name, + nargs = '*', + bang = true, + }) + end + end + + if self.has_events then + local group_id = vim.api.nvim_create_augroup(self.augroup_name, { + clear = true, + }) + + if self.ft then + vim.api.nvim_create_autocmd('FileType', { + group = group_id, + pattern = self.ft, + callback = self:lazy_load_event('FileType') + }) + end + + if self.events then + for _, event in ipairs(self.events) do + vim.api.nvim_create_autocmd(event.name, { + group = group_id, + pattern = event.pattern, + callback = self:lazy_load_event(event.name) + }) + end + end + end + + if self.keymaps then + for _, keymap in ipairs(self.keymaps) do + for _, mapping in ipairs(keymap.mapping) do + vim.keymap.set(keymap.mode, mapping, self:lazy_load_mapping(mapping)) + end + end + end +end + +function M:_unshim() + if self.cmd then + for _, cmd in ipairs(self.cmd) do + vim.api.nvim_del_user_command(cmd) + end + end + + if self.has_events then + vim.api.nvim_del_augroup_by_name(self.augroup_name) + end + + if self.keymaps then + for _, keymap in ipairs(self.keymaps) do + for _, mapping in ipairs(keymap.mapping) do + vim.keymap.del(keymap.mode, mapping) + end + end + end +end + function M:init() return self.sm:init() end @@ -218,6 +245,13 @@ function M:lazy_load_event(name) end end +function M:lazy_load_mapping(mapping) + return function(param) + self:load() + vim.cmd.normal(mapping) + end +end + local deps = {} for k, v in pairs(raw_deps) do deps[k] = M.new(v) diff --git a/lua/sloth-flake/state_machine.lua b/lua/sloth-flake/state_machine.lua index 3c9c98b..dc87ac0 100644 --- a/lua/sloth-flake/state_machine.lua +++ b/lua/sloth-flake/state_machine.lua @@ -50,8 +50,8 @@ function SM:run_enter_state(state) end function SM:run_exit_state(state) - local enter_fn = self.defs.exit and self.defs.exit[state] or empty_fn - enter_fn(self.state) + local exit_fn = self.defs.exit and self.defs.exit[state] or empty_fn + exit_fn(self.state) end local function wrap_state_array(val)