mirror of
https://github.com/NotAShelf/nvf.git
synced 2025-09-06 02:11:33 +00:00
refactor!: use a new keymaps configuration format
This commit is contained in:
parent
f5b1844d2e
commit
0649f710be
11 changed files with 343 additions and 182 deletions
|
@ -19,6 +19,107 @@ with builtins; let
|
|||
type = with types; attrsOf (nullOr str);
|
||||
}
|
||||
// it);
|
||||
|
||||
mkBool = value: description:
|
||||
mkOption {
|
||||
type = types.bool;
|
||||
default = value;
|
||||
description = description;
|
||||
};
|
||||
|
||||
# Most of the keybindings code is highly inspired by pta2002/nixvim. Thank you!
|
||||
mapConfigOptions = {
|
||||
silent =
|
||||
mkBool false
|
||||
"Whether this mapping should be silent. Equivalent to adding <silent> to a map.";
|
||||
|
||||
nowait =
|
||||
mkBool false
|
||||
"Whether to wait for extra input on ambiguous mappings. Equivalent to adding <nowait> to a map.";
|
||||
|
||||
script =
|
||||
mkBool false
|
||||
"Equivalent to adding <script> to a map.";
|
||||
|
||||
expr =
|
||||
mkBool false
|
||||
"Means that the action is actually an expression. Equivalent to adding <expr> to a map.";
|
||||
|
||||
unique =
|
||||
mkBool false
|
||||
"Whether to fail if the map is already defined. Equivalent to adding <unique> to a map.";
|
||||
|
||||
noremap =
|
||||
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.";
|
||||
|
||||
desc = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "A description of this keybind, to be shown in which-key, if you have it enabled.";
|
||||
};
|
||||
};
|
||||
|
||||
genMaps = mode: maps: let
|
||||
/*
|
||||
Take a user-defined action (string or attrs) and return the following attribute set:
|
||||
{
|
||||
action = (string) the actual action to map to this key
|
||||
config = (attrs) the configuration options for this mapping (noremap, silent...)
|
||||
}
|
||||
*/
|
||||
normalizeAction = action: let
|
||||
# Extract the values of the config options that have been explicitly set by the user
|
||||
config =
|
||||
filterAttrs (n: v: v != null)
|
||||
(getAttrs (attrNames mapConfigOptions) action);
|
||||
in {
|
||||
config =
|
||||
if config == {}
|
||||
then {"__empty" = null;}
|
||||
else config;
|
||||
action =
|
||||
if action.lua
|
||||
then {"__raw" = action.action;}
|
||||
else action.action;
|
||||
};
|
||||
in
|
||||
builtins.attrValues (builtins.mapAttrs
|
||||
(key: action: let
|
||||
normalizedAction = normalizeAction action;
|
||||
in {
|
||||
inherit (normalizedAction) action config;
|
||||
key = key;
|
||||
mode = mode;
|
||||
})
|
||||
maps);
|
||||
|
||||
mapOption = types.submodule {
|
||||
options =
|
||||
mapConfigOptions
|
||||
// {
|
||||
action = mkOption {
|
||||
type = types.str;
|
||||
description = "The action to execute.";
|
||||
};
|
||||
|
||||
lua = mkOption {
|
||||
type = types.bool;
|
||||
description = ''
|
||||
If true, `action` is considered to be lua code.
|
||||
Thus, it will not be wrapped in `""`.
|
||||
'';
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mapOptions = mode:
|
||||
mkOption {
|
||||
description = "Mappings for ${mode} mode";
|
||||
type = types.attrsOf mapOption;
|
||||
default = {};
|
||||
};
|
||||
in {
|
||||
options.vim = {
|
||||
viAlias = mkOption {
|
||||
|
@ -67,64 +168,39 @@ in {
|
|||
type = types.attrs;
|
||||
};
|
||||
|
||||
nnoremap =
|
||||
mkMappingOption {description = "Defines 'Normal mode' mappings";};
|
||||
maps = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
normal = mapOptions "normal";
|
||||
insert = mapOptions "insert";
|
||||
select = mapOptions "select";
|
||||
visual = mapOptions "visual and select";
|
||||
terminal = mapOptions "terminal";
|
||||
normalVisualOp = mapOptions "normal, visual, select and operator-pending (same as plain 'map')";
|
||||
|
||||
inoremap = mkMappingOption {
|
||||
description = "Defines 'Insert and Replace mode' mappings";
|
||||
};
|
||||
visualOnly = mapOptions "visual only";
|
||||
operator = mapOptions "operator-pending";
|
||||
insertCommand = mapOptions "insert and command-line";
|
||||
lang = mapOptions "insert, command-line and lang-arg";
|
||||
command = mapOptions "command-line";
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Custom keybindings for any mode.
|
||||
|
||||
vnoremap = mkMappingOption {
|
||||
description = "Defines 'Visual and Select mode' mappings";
|
||||
};
|
||||
For plain maps (e.g. just 'map' or 'remap') use maps.normalVisualOp.
|
||||
'';
|
||||
|
||||
xnoremap =
|
||||
mkMappingOption {description = "Defines 'Visual mode' mappings";};
|
||||
|
||||
snoremap =
|
||||
mkMappingOption {description = "Defines 'Select mode' mappings";};
|
||||
|
||||
cnoremap =
|
||||
mkMappingOption {description = "Defines 'Command-line mode' mappings";};
|
||||
|
||||
onoremap = mkMappingOption {
|
||||
description = "Defines 'Operator pending mode' mappings";
|
||||
};
|
||||
|
||||
tnoremap = mkMappingOption {
|
||||
description = "Defines 'Terminal mode' mappings";
|
||||
};
|
||||
|
||||
nmap = mkMappingOption {
|
||||
description = "Defines 'Normal mode' mappings";
|
||||
};
|
||||
|
||||
imap = mkMappingOption {
|
||||
description = "Defines 'Insert and Replace mode' mappings";
|
||||
};
|
||||
|
||||
vmap = mkMappingOption {
|
||||
description = "Defines 'Visual and Select mode' mappings";
|
||||
};
|
||||
|
||||
xmap = mkMappingOption {
|
||||
description = "Defines 'Visual mode' mappings";
|
||||
};
|
||||
|
||||
smap = mkMappingOption {
|
||||
description = "Defines 'Select mode' mappings";
|
||||
};
|
||||
|
||||
cmap = mkMappingOption {
|
||||
description = "Defines 'Command-line mode' mappings";
|
||||
};
|
||||
|
||||
omap = mkMappingOption {
|
||||
description = "Defines 'Operator pending mode' mappings";
|
||||
};
|
||||
|
||||
tmap = mkMappingOption {
|
||||
description = "Defines 'Terminal mode' mappings";
|
||||
example = ''
|
||||
maps = {
|
||||
normalVisualOp.";" = ":"; # Same as noremap ; :
|
||||
normal."<leader>m" = {
|
||||
silent = true;
|
||||
action = "<cmd>make<CR>";
|
||||
}; # Same as nnoremap <leader>m <silent> <cmd>make<CR>
|
||||
};
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -148,34 +224,66 @@ in {
|
|||
mapAttrsFlatten (name: value: "let g:${name}=${valToVim value}")
|
||||
(filterNonNull cfg.globals);
|
||||
|
||||
matchCtrl = it: match "Ctrl-(.)(.*)" it;
|
||||
mapKeyBinding = it: let
|
||||
groups = matchCtrl it;
|
||||
in
|
||||
if groups == null
|
||||
then it
|
||||
else "<C-${toUpper (head groups)}>${head (tail groups)}";
|
||||
mapVimBinding = prefix: mappings:
|
||||
mapAttrsFlatten (name: value: "${prefix} ${mapKeyBinding name} ${value}")
|
||||
(filterNonNull mappings);
|
||||
toLuaObject = args:
|
||||
if builtins.isAttrs args
|
||||
then
|
||||
if hasAttr "__raw" args
|
||||
then args.__raw
|
||||
else if hasAttr "__empty" args
|
||||
then "{ }"
|
||||
else
|
||||
"{"
|
||||
+ (concatStringsSep ","
|
||||
(mapAttrsToList
|
||||
(n: v:
|
||||
if head (stringToCharacters n) == "@"
|
||||
then toLuaObject v
|
||||
else "[${toLuaObject n}] = " + (toLuaObject v))
|
||||
(filterAttrs
|
||||
(
|
||||
n: v:
|
||||
!isNull v && (toLuaObject v != "{}")
|
||||
)
|
||||
args)))
|
||||
+ "}"
|
||||
else if builtins.isList args
|
||||
then "{" + concatMapStringsSep "," toLuaObject args + "}"
|
||||
else if builtins.isString args
|
||||
then
|
||||
# This should be enough!
|
||||
builtins.toJSON args
|
||||
else if builtins.isPath args
|
||||
then builtins.toJSON (toString args)
|
||||
else if builtins.isBool args
|
||||
then "${boolToString args}"
|
||||
else if builtins.isFloat args
|
||||
then "${toString args}"
|
||||
else if builtins.isInt args
|
||||
then "${toString args}"
|
||||
else if isNull args
|
||||
then "nil"
|
||||
else "";
|
||||
|
||||
nmap = mapVimBinding "nmap" config.vim.nmap;
|
||||
imap = mapVimBinding "imap" config.vim.imap;
|
||||
vmap = mapVimBinding "vmap" config.vim.vmap;
|
||||
xmap = mapVimBinding "xmap" config.vim.xmap;
|
||||
smap = mapVimBinding "smap" config.vim.smap;
|
||||
cmap = mapVimBinding "cmap" config.vim.cmap;
|
||||
omap = mapVimBinding "omap" config.vim.omap;
|
||||
tmap = mapVimBinding "tmap" config.vim.tmap;
|
||||
toLuaBindings = mode: maps:
|
||||
builtins.map (value: ''
|
||||
map("${mode}", "${value.key}", ${
|
||||
if value.action ? "__raw"
|
||||
then value.action."__raw"
|
||||
else "\"${value.action}\""
|
||||
}, ${toLuaObject value.config})'') (genMaps mode maps);
|
||||
|
||||
nnoremap = mapVimBinding "nnoremap" config.vim.nnoremap;
|
||||
inoremap = mapVimBinding "inoremap" config.vim.inoremap;
|
||||
vnoremap = mapVimBinding "vnoremap" config.vim.vnoremap;
|
||||
xnoremap = mapVimBinding "xnoremap" config.vim.xnoremap;
|
||||
snoremap = mapVimBinding "snoremap" config.vim.snoremap;
|
||||
cnoremap = mapVimBinding "cnoremap" config.vim.cnoremap;
|
||||
onoremap = mapVimBinding "onoremap" config.vim.onoremap;
|
||||
tnoremap = mapVimBinding "tnoremap" config.vim.tnoremap;
|
||||
# I'm not sure if every one of these will work.
|
||||
allmap = toLuaBindings "" config.vim.maps.normalVisualOp;
|
||||
nmap = toLuaBindings "n" config.vim.maps.normal;
|
||||
vmap = toLuaBindings "v" config.vim.maps.visual;
|
||||
xmap = toLuaBindings "x" config.vim.maps.visualOnly;
|
||||
smap = toLuaBindings "s" config.vim.maps.select;
|
||||
imap = toLuaBindings "u" config.vim.maps.insert;
|
||||
cmap = toLuaBindings "c" config.vim.maps.command;
|
||||
tmap = toLuaBindings "t" config.vim.maps.terminal;
|
||||
lmap = toLuaBindings "l" config.vim.maps.lang;
|
||||
omap = toLuaBindings "o" config.vim.maps.operator;
|
||||
icmap = toLuaBindings "ic" config.vim.maps.insertCommand;
|
||||
|
||||
resolveDag = {
|
||||
name,
|
||||
|
@ -209,8 +317,31 @@ in {
|
|||
nvim.dag.entryAfter ["globalsScript"] luaConfig;
|
||||
|
||||
mappings = let
|
||||
maps = [nmap imap vmap xmap smap cmap omap tmap nnoremap inoremap vnoremap xnoremap snoremap cnoremap onoremap tnoremap];
|
||||
mapConfig = concatStringsSep "\n" (map (v: concatStringsSep "\n" v) maps);
|
||||
maps = [
|
||||
(splitString
|
||||
"\n"
|
||||
''
|
||||
local function map(mode, lhs, rhs, opts)
|
||||
local options = { noremap=true, silent=true }
|
||||
if opts then
|
||||
options = vim.tbl_extend('force', options, opts)
|
||||
end
|
||||
vim.api.nvim_set_keymap(mode, lhs, rhs, options)
|
||||
end
|
||||
'')
|
||||
nmap
|
||||
imap
|
||||
vmap
|
||||
xmap
|
||||
smap
|
||||
cmap
|
||||
omap
|
||||
tmap
|
||||
lmap
|
||||
icmap
|
||||
allmap
|
||||
];
|
||||
mapConfig = wrapLuaConfig (concatStringsSep "\n" (map (v: concatStringsSep "\n" v) maps));
|
||||
in
|
||||
nvim.dag.entryAfter ["globalsScript"] mapConfig;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue