From 91269c56c5c81778234e69240e424b9bdc069b07 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Tue, 27 Jan 2026 12:13:25 +0300 Subject: [PATCH 1/2] neovim/init: add module option for registering custom filetypes Signed-off-by: NotAShelf Change-Id: I5f5f576642884c09a8e4afc18499ed606a6a6964 --- modules/neovim/init/default.nix | 1 + modules/neovim/init/filetype.nix | 121 +++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 modules/neovim/init/filetype.nix diff --git a/modules/neovim/init/default.nix b/modules/neovim/init/default.nix index 3f195085..641cc0e1 100644 --- a/modules/neovim/init/default.nix +++ b/modules/neovim/init/default.nix @@ -5,6 +5,7 @@ ./clipboard.nix ./debug.nix ./diagnostics.nix + ./filetype.nix ./highlight.nix ./lsp.nix ./spellcheck.nix diff --git a/modules/neovim/init/filetype.nix b/modules/neovim/init/filetype.nix new file mode 100644 index 00000000..6f098c54 --- /dev/null +++ b/modules/neovim/init/filetype.nix @@ -0,0 +1,121 @@ +{ + config, + lib, + ... +}: let + inherit (lib.options) mkOption; + inherit (lib.types) nullOr either oneOf attrsOf str listOf submodule ints; + inherit (lib.nvim.types) luaInline; + inherit (lib.nvim.dag) entryBefore; + inherit (lib.nvim.lua) toLuaObject; + + cfg = config.vim; + + # vim.filetype.add() is quite robust, but this makes for a very + # complex type that we have to handle. It takes a string, a Lua function + # or a dictionary with the priority of the extension. + ftOptionType = attrsOf (oneOf [ + str # "filetype" + luaInline # `function(path, bufnr) ... end` + + # { 'dosini', { priority = 10 } }, + (listOf (either str (submodule { + options = { + priority = mkOption { + type = ints.unsigned; + description = '' + `vim.filetype.add()` can take an optional priority value to resolve + conflicts where a filetype is registered by multiple patterns. When + priority is specified, file with the higher priority value will be + matched first on conflict. + ''; + }; + }; + }))) + ]); +in { + options.vim.filetype = mkOption { + type = submodule { + options = { + extension = mkOption { + type = nullOr ftOptionType; + default = null; + description = "register a new filetype by extension"; + }; + + filename = mkOption { + type = nullOr ftOptionType; + default = null; + description = "register a new filetype by file name"; + }; + + pattern = mkOption { + type = nullOr ftOptionType; + default = null; + description = "register a new filetype by pattern"; + }; + }; + }; + + default = {}; + example = { + filename = { + ".foorc" = "toml"; + "/etc/foo/config" = "toml"; + "todo.txt" = "todotxt"; + }; + + pattern = { + ".*%.scm" = "query"; + ".*README.(%a+)" = '' + function(path, bufnr, ext) + if ext == 'md' then + return 'markdown' + elseif ext == 'rst' then + return 'rst' + end + end, + ''; + }; + + extension = { + mdx = "markdown"; + bar = lib.mkLuaInline '' + bar = function(path, bufnr) + if some_condition() then + return 'barscript', function(bufnr) + -- Set a buffer variable + vim.b[bufnr].barscript_version = 2 + end + end + return 'bar' + end, + ''; + }; + }; + + description = '' + Additional filetypes to be registered through `vim.filetype.add()` + + Filetype mappings can be added either by extension or by filename. The + key can be either the "tail" or the full file path. The full file path + is checked first, followed by the file name. If a match is not found + using the filename, then the filename is matched against the list of + Lua patterns (sorted by priority) until a match is found. + + If a pattern matching does not find a filetype, then the file extension + is used. + + See `:h vim.filetype.add()` for more details. + ''; + }; + + config = { + # XXX: some plugins can be loaded on filetype, and unless the filetypes + # are registered first, chances are custom filetypes will not be usable + # for lazy-loading on ft. + vim.luaConfigRC.filetype = entryBefore ["lazyConfigs"] '' + vim.filetype.add(${toLuaObject cfg.filetype}) + ''; + }; +} From f8f1017411c677cde35d0c28397209510fcc36c3 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Tue, 27 Jan 2026 12:54:02 +0300 Subject: [PATCH 2/2] modules: move mappings to `neovim/init` Signed-off-by: NotAShelf Change-Id: I9b04107496df27dcda1a24ce000da3f46a6a6964 --- modules/modules.nix | 1 - modules/neovim/init/default.nix | 1 + .../options.nix => init/mappings.nix} | 55 ++++++++++++++++++- modules/neovim/mappings/config.nix | 27 --------- modules/neovim/mappings/default.nix | 6 -- 5 files changed, 54 insertions(+), 36 deletions(-) rename modules/neovim/{mappings/options.nix => init/mappings.nix} (74%) delete mode 100644 modules/neovim/mappings/default.nix diff --git a/modules/modules.nix b/modules/modules.nix index 1eca042a..9c3bba1f 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -10,7 +10,6 @@ # such as spellchecking, mappings, and the init script (init.vim). neovim = map (p: ./neovim + "/${p}") [ "init" - "mappings" ]; # Individual plugin modules, separated by the type of plugin. diff --git a/modules/neovim/init/default.nix b/modules/neovim/init/default.nix index 641cc0e1..e831fab6 100644 --- a/modules/neovim/init/default.nix +++ b/modules/neovim/init/default.nix @@ -8,6 +8,7 @@ ./filetype.nix ./highlight.nix ./lsp.nix + ./mappings.nix ./spellcheck.nix ./util.nix ]; diff --git a/modules/neovim/mappings/options.nix b/modules/neovim/init/mappings.nix similarity index 74% rename from modules/neovim/mappings/options.nix rename to modules/neovim/init/mappings.nix index 98e04a65..54db0768 100644 --- a/modules/neovim/mappings/options.nix +++ b/modules/neovim/init/mappings.nix @@ -1,19 +1,31 @@ -{lib, ...}: let +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkMerge; inherit (lib.options) mkOption literalMD; inherit (lib.types) either str listOf attrsOf nullOr submodule; + inherit (lib.attrsets) mapAttrsToList; + inherit (lib.lists) flatten; + inherit (lib.trivial) pipe; inherit (lib.nvim.config) mkBool; mapConfigOptions = { desc = mkOption { type = nullOr str; default = null; - description = "A description of this keybind, to be shown in which-key, if you have it enabled."; + description = '' + Description for the keybind, to be shown in which-key, if you have enabled + in the module system. + ''; }; action = mkOption { type = str; description = "The command to execute."; }; + lua = mkBool false '' If true, `action` is considered to be lua code. Thus, it will not be wrapped in `""`. @@ -55,6 +67,22 @@ }); default = {}; }; + + legacyMapModes = { + normal = ["n"]; + insert = ["i"]; + select = ["s"]; + visual = ["v"]; + terminal = ["t"]; + normalVisualOp = ["n" "v" "o"]; + visualOnly = ["n" "x"]; + operator = ["o"]; + insertCommand = ["i" "c"]; + lang = ["l"]; + command = ["c"]; + }; + + cfg = config.vim; in { options.vim = { keymaps = mkOption { @@ -94,4 +122,27 @@ in { command = legacyMapOption "command-line"; }; }; + + config = { + vim.keymaps = mkMerge [ + ( + pipe cfg.maps + [ + (mapAttrsToList ( + oldMode: keybinds: + mapAttrsToList ( + key: bind: + bind + // { + inherit key; + mode = legacyMapModes.${oldMode}; + } + ) + keybinds + )) + flatten + ] + ) + ]; + }; } diff --git a/modules/neovim/mappings/config.nix b/modules/neovim/mappings/config.nix index a62a6ca2..11ddb0fd 100644 --- a/modules/neovim/mappings/config.nix +++ b/modules/neovim/mappings/config.nix @@ -3,11 +3,6 @@ lib, ... }: let - inherit (lib.modules) mkMerge; - inherit (lib.trivial) pipe; - inherit (lib.attrsets) mapAttrsToList; - inherit (lib.lists) flatten; - legacyMapModes = { normal = ["n"]; insert = ["i"]; @@ -24,26 +19,4 @@ cfg = config.vim; in { - config = { - vim.keymaps = mkMerge [ - ( - pipe cfg.maps - [ - (mapAttrsToList ( - oldMode: keybinds: - mapAttrsToList ( - key: bind: - bind - // { - inherit key; - mode = legacyMapModes.${oldMode}; - } - ) - keybinds - )) - flatten - ] - ) - ]; - }; } diff --git a/modules/neovim/mappings/default.nix b/modules/neovim/mappings/default.nix deleted file mode 100644 index fe9e1b8e..00000000 --- a/modules/neovim/mappings/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ - imports = [ - ./config.nix - ./options.nix - ]; -}