diff --git a/docs/release-notes/rl-0.7.md b/docs/release-notes/rl-0.7.md index bfd08b1..1a2a089 100644 --- a/docs/release-notes/rl-0.7.md +++ b/docs/release-notes/rl-0.7.md @@ -185,6 +185,7 @@ To migrate to `nixfmt`, simply change `vim.languages.nix.format.type` to default. - Refactor of `nvim-cmp` and completion related modules + - Remove `autocomplete.type` in favor of per-plugin enable options such as [](#opt-vim.autocomplete.nvim-cmp.enable). - Deprecate legacy Vimsnip in favor of Luasnip, and integrate @@ -277,9 +278,13 @@ To migrate to `nixfmt`, simply change `vim.languages.nix.format.type` to configuration for [dashboard.nvim](https://github.com/nvimdev/dashboard-nvim) - Update `lualine.nvim` input and add missing themes: + - Adds `ayu`, `gruvbox_dark`, `iceberg`, `moonfly`, `onedark`, `powerline_dark` and `solarized_light` themes. +- Add [](#opt-vim.spellcheck.extraSpellWords) to allow adding arbitrary + spellfiles to Neovim's runtime with ease. + [ppenguin](https://github.com/ppenguin): - Telescope: diff --git a/modules/neovim/init/spellcheck.nix b/modules/neovim/init/spellcheck.nix index d8957ef..5d6f5be 100644 --- a/modules/neovim/init/spellcheck.nix +++ b/modules/neovim/init/spellcheck.nix @@ -1,11 +1,14 @@ { config, + pkgs, lib, ... }: let inherit (lib.modules) mkIf mkRenamedOptionModule; inherit (lib.options) mkOption mkEnableOption literalExpression; - inherit (lib.types) listOf str; + inherit (lib.strings) concatLines; + inherit (lib.attrsets) mapAttrsToList; + inherit (lib.types) listOf str attrsOf; inherit (lib.nvim.lua) listToLuaTable; inherit (lib.nvim.dag) entryAfter; @@ -24,10 +27,48 @@ in { description = '' A list of languages that should be used for spellchecking. - To add your own language files, you may place your `spell` - directory in either `~/.config/nvim` or the - [additionalRuntimePaths](#opt-vim.additionalRuntimePaths) - directory provided by **nvf**. + To add your own language files, you may place your `spell` directory in either + {file}`$XDG_CONFIG_HOME/nvf` or in a path that is included in the + [additionalRuntimePaths](#opt-vim.additionalRuntimePaths) list provided by nvf. + ''; + }; + + extraSpellWords = mkOption { + type = attrsOf (listOf str); + default = {}; + example = literalExpression ''{"en.utf-8" = ["nvf" "word_you_want_to_add"];}''; + description = '' + Additional words to be used for spellchecking. The names of each key will be + used as the language code for the spell file. For example + + ```nix + "en.utf-8" = [ ... ]; + ``` + + will result in `en.utf-8.add.spl` being added to Neovim's runtime in the + {file}`spell` directory. + + ::: {.warning} + The attribute keys must be in `"."` format for Neovim to + compile your spellfiles without mangling the resulting file names. Please + make sure that you enter the correct value, as nvf does not do any kind of + internal checking. Please see {command}`:help mkspell` for more details. + + Example: + + ```nix + # "en" is the name, and "utf-8" is the encoding. For most use cases, utf-8 + # will be enough, however, you may change it to any encoding format Neovim + # accepts, e.g., utf-16. + "en.utf-8" = ["nvf" "word_you_want_to_add"]; + => $out/spell/en-utf-8.add.spl + ``` + ::: + + Note that while adding a new language, you will still need to add the name of + the language (e.g. "en") to the {option}`vim.spellcheck.languages` list by name + in order to enable spellchecking for the language. By default only `"en"` is in + the list. ''; }; @@ -38,38 +79,75 @@ in { description = '' A list of filetypes for which spellchecking will be disabled. - You may use `echo &filetype` in Neovim to find out the + ::: {.tip} + You may use {command}`:echo &filetype` in Neovim to find out the filetype for a specific buffer. + ::: ''; }; - /* - # FIXME: This needs to be revisited. It tries to install - # the spellfile to an user directory, but it cannot do so - # as we sanitize runtime paths. programmingWordlist.enable = mkEnableOption '' vim-dirtytalk, a wordlist for programmers containing common programming terms. - Setting this value as `true` has the same effect - as setting {option}`vim.spellCheck.enable` + ::: {.note} + Enabling this option will unconditionally set + {option}`vim.spellcheck.enable` to true as vim-dirtytalk + depends on spellchecking having been set up. + ::: ''; - */ }; config = mkIf cfg.enable { - vim.luaConfigRC.spellcheck = entryAfter ["basic"] '' - vim.opt.spell = true - vim.opt.spelllang = ${listToLuaTable cfg.languages} + vim = { + additionalRuntimePaths = let + compileJoinedSpellfiles = + pkgs.runCommandLocal "nvf-compile-spellfiles" { + # Use the same version of Neovim as the user's configuration + nativeBuildInputs = [config.vim.package]; - -- Disable spellchecking for certain filetypes - -- as configured by `vim.spellcheck.ignoredFiletypes` - vim.api.nvim_create_autocmd({ "FileType" }, { - pattern = ${listToLuaTable cfg.ignoredFiletypes}, - callback = function() - vim.opt_local.spell = false - end, - }) - ''; + spellfilesJoined = pkgs.symlinkJoin { + name = "nvf-spellfiles-joined"; + paths = mapAttrsToList (name: value: pkgs.writeTextDir "spell/${name}.add" (concatLines value)) cfg.extraSpellWords; + postBuild = "echo Spellfiles joined"; + }; + } '' + # Fail on unset variables and non-zero exit codes + # this might be the only way to trace when `nvim --headless` + # fails in batch mode + set -eu + + mkdir -p "$out/spell" + for spellfile in "$spellfilesJoined"/spell/*.add; do + name="$(basename "$spellfile" ".add")" + echo "Compiling spellfile: $spellfile" + nvim --headless --clean \ + --cmd "mkspell $out/spell/$name.add.spl $spellfile" -Es -n + done + + ''; + in + mkIf (cfg.extraSpellWords != {}) [ + # If .outPath is missing, additionalRuntimePaths receives the *function* + # instead of a path, causing errors. + compileJoinedSpellfiles.outPath + ]; + + luaConfigRC.spellcheck = entryAfter ["basic"] '' + vim.opt.spell = true + vim.opt.spelllang = ${listToLuaTable cfg.languages} + + -- Disable spellchecking for certain filetypes + -- as configured by `vim.spellcheck.ignoredFiletypes` + vim.api.nvim_create_augroup("nvf_autocmds", {clear = false}) + vim.api.nvim_create_autocmd({ "FileType" }, { + group = "nvf_autocmds", + pattern = ${listToLuaTable cfg.ignoredFiletypes}, + callback = function() + vim.opt_local.spell = false + end, + }) + ''; + }; }; } diff --git a/modules/plugins/spellcheck/vim-dirtytalk/config.nix b/modules/plugins/spellcheck/vim-dirtytalk/config.nix index 08426d1..51ccfb8 100644 --- a/modules/plugins/spellcheck/vim-dirtytalk/config.nix +++ b/modules/plugins/spellcheck/vim-dirtytalk/config.nix @@ -7,16 +7,26 @@ inherit (lib.nvim.dag) entryAfter; cfg = config.vim.spellcheck; in { - config = mkIf (cfg.enable && cfg.programmingWordlist.enable) { + config = mkIf cfg.programmingWordlist.enable { vim = { startPlugins = ["vim-dirtytalk"]; - # vim-dirtytalk doesn't have any setup - # but we would like to append programming to spelllang - # as soon as possible while the plugin is enabled - pluginRC.vim-dirtytalk = entryAfter ["basic"] '' - -- append programming to spelllang - vim.opt.spelllang:append("programming") + spellcheck.enable = true; + + # vim-dirtytalk doesn't have any setup but we would + # like to append programming to spelllangs as soon as + # possible while the plugin is enabled and the state + # directory can be found. + pluginRC.vim-dirtytalk = entryAfter ["spellcheck"] '' + -- If Neovim can find (or access) the state directory + -- then append "programming" wordlist from vim-dirtytalk + -- to spelllang table. If path cannot be found, display + -- an error and avoid appending the programming words + if vim.fn.isdirectory(vim.fn.stdpath('state')) == 1 then + vim.opt.spelllang:append("programming") + else + vim.notify("State path does not exist: " .. state_path, vim.log.levels.ERROR) + end ''; }; };