From 91269c56c5c81778234e69240e424b9bdc069b07 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Tue, 27 Jan 2026 12:13:25 +0300 Subject: [PATCH] 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}) + ''; + }; +}