{ lib, nixvimOptions, nixvimTypes, }: with lib; rec { # These are the configuration options that change the behavior of each mapping. mapConfigOptions = { silent = nixvimOptions.defaultNullOpts.mkBool false "Whether this mapping should be silent. Equivalent to adding `<silent>` to a map."; nowait = nixvimOptions.defaultNullOpts.mkBool false "Whether to wait for extra input on ambiguous mappings. Equivalent to adding `<nowait>` to a map."; script = nixvimOptions.defaultNullOpts.mkBool false "Equivalent to adding `<script>` to a map."; expr = nixvimOptions.defaultNullOpts.mkBool false "Means that the action is actually an expression. Equivalent to adding `<expr>` to a map."; unique = nixvimOptions.defaultNullOpts.mkBool false "Whether to fail if the map is already defined. Equivalent to adding `<unique>` to a map."; noremap = nixvimOptions.defaultNullOpts.mkBool true "Whether to use the `noremap` variant of the command, ignoring any custom mappings on the defined action. It is highly advised to keep this on, which is the default."; remap = nixvimOptions.defaultNullOpts.mkBool false "Make the mapping recursive. Inverses `noremap`."; desc = nixvimOptions.mkNullOrOption types.str "A textual description of this keybind, to be shown in which-key, if you have it."; buffer = nixvimOptions.defaultNullOpts.mkBool false "Make the mapping buffer-local. Equivalent to adding `<buffer>` to a map."; }; modes = { normal.short = "n"; insert.short = "i"; visual = { desc = "visual and select"; short = "v"; }; visualOnly = { desc = "visual only"; short = "x"; }; select.short = "s"; terminal.short = "t"; normalVisualOp = { desc = "normal, visual, select and operator-pending (same as plain 'map')"; short = ""; }; operator.short = "o"; lang = { desc = "normal, visual, select and operator-pending (same as plain 'map')"; short = "l"; }; insertCommand = { desc = "insert and command-line"; short = "!"; }; command.short = "c"; }; modeEnum = types.enum # ["" "n" "v" ...] (map ({ short, ... }: short) (attrValues modes)); mapOptionSubmodule = mkMapOptionSubmodule { }; mkModeOption = default: mkOption { type = with types; either modeEnum (listOf modeEnum); description = '' One or several modes. Use the short-names (`"n"`, `"v"`, ...). See `:h map-modes` to learn more. ''; inherit default; example = [ "n" "v" ]; }; mkMapOptionSubmodule = { defaults ? { }, # key and action can be true/false to enable/disable adding the option, # or an attrset to enable the option and add/override mkOption args. key ? true, action ? true, }: # TODO remove assert once `lua` option is gone # This is here to ensure no uses of `mkMapOptionSubmodule` set a `lua` default assert !(defaults ? lua); ( with types; submodule { options = (optionalAttrs (isAttrs key || key) { key = mkOption ( { type = str; description = "The key to map."; example = "<C-m>"; } // (optionalAttrs (isAttrs key) key) // (optionalAttrs (defaults ? key) { default = defaults.key; }) ); }) // (optionalAttrs (isAttrs action || action) { action = mkOption ( { type = nixvimTypes.maybeRaw str; description = "The action to execute."; } // (optionalAttrs (isAttrs action) action) // (optionalAttrs (defaults ? action) { default = defaults.action; }) ); }) // { mode = mkModeOption defaults.mode or ""; options = mapConfigOptions; lua = mkOption { type = nullOr bool; description = '' If true, `action` is considered to be lua code. Thus, it will not be wrapped in `""`. This option is deprecated and will be removed in 24.11. You should use a "raw" action instead, e.g. `action.__raw = ""`. ''; default = null; visible = false; }; }; } ); # Correctly merge two attrs (partially) representing a mapping. mergeKeymap = defaults: keymap: let # First, merge the `options` attrs of both options. mergedOpts = (defaults.options or { }) // (keymap.options or { }); in # Then, merge the root attrs together and add the previously merged `options` attrs. (defaults // keymap) // { options = mergedOpts; }; mkKeymaps = defaults: map (mergeKeymap defaults); }