diff --git a/flake/dev/list-plugins/list-plugins.py b/flake/dev/list-plugins/list-plugins.py index 7d9864b870..1db2b806ca 100755 --- a/flake/dev/list-plugins/list-plugins.py +++ b/flake/dev/list-plugins/list-plugins.py @@ -33,7 +33,7 @@ "plugins/by-name/rustaceanvim/renamed-options.nix", "plugins/by-name/telescope/extensions/_mk-extension.nix", "plugins/by-name/telescope/extensions/default.nix", - "plugins/cmp/auto-enable.nix", + "plugins/cmp/deprecated-auto-enable.nix", "plugins/cmp/options/", "plugins/cmp/sources/cmp-fish.nix", "plugins/cmp/sources/default.nix", diff --git a/lib/modules.nix b/lib/modules.nix index 5bcba06146..1a4b84ffae 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -14,6 +14,7 @@ let applyExtraConfig = "It has been moved to `lib.plugins.utils`"; mkConfigAt = "It has been moved to `lib.plugins.utils`"; }; + internal = lib.mkOption { internal = true; }; in { # Evaluate nixvim modules, checking warnings and assertions @@ -52,6 +53,282 @@ in helpers = self; } // extraSpecialArgs; }; + + # Create a module configuring a plugin's integration with blink.cmp + mkBlinkPluginModule = + { + # The plugin's option location-path + loc ? [ + "plugins" + pluginName + ], + # Name of the plugin, used in documentation + pluginName, + # Name of the module blink should import + # i.e. `sources.providers..module` + module ? pluginName, + # The default for `blink.settings.name` + # i.e. `sources.providers..name` + # TODO: consider doing some pre-processing to the default source name, + # e.g. removing `-cmp` or `blink-` prefix/suffix? + sourceName, + # The default for `blink.key` + # i.e. the attr name for `sources.providers.` + key ? lib.strings.toLower sourceName, + # Whether to enable the blink completion provider by default + enableProvider ? true, + # Defaults for the corresponding source options + enableDefault ? true, + enableCmdline ? false, + enabledFiletypes ? { }, + # Whether the plugin's settings should be used as the provider's `opts` + usePluginSettings ? true, + settingsExample ? { + score_offset = -7; + fallbacks = [ ]; + }, + }: + { config, options, ... }: + let + pluginCfg = lib.getAttrFromPath loc config; + cfg = pluginCfg.blink; + pluginOpts = lib.getAttrFromPath loc options; + opt = pluginOpts.blink; + in + { + options = lib.setAttrByPath loc { + blink = { + enable = lib.mkOption { + type = lib.types.bool; + default = enableProvider; + example = !enableProvider; + description = '' + Whether to integrate this plugin with blink.cmp. + ''; + }; + key = lib.mkOption { + type = lib.types.str; + default = key; + description = '' + The key to use for ${pluginName}'s blink.cmp provider. + This is the id you should use when including this provider in completion source lists. + Must be unique. + ''; + }; + default = lib.mkOption { + type = lib.types.bool; + default = enableDefault; + example = !enableDefault; + description = '' + Whether to include this plugin in the `default` completion source list. + ''; + }; + cmdline = lib.mkOption { + type = lib.types.bool; + default = enableCmdline; + example = !enableCmdline; + description = '' + Whether to include this plugin in the `cmdline` completion source list. + ''; + }; + filetypes = lib.mkOption { + type = lib.types.attrsOf lib.types.bool; + # Only include `true` attrs in the final value + apply = lib.filterAttrs (_: lib.id); + default = enabledFiletypes; + # TODO: example + description = '' + Whether to include this plugin in the specific `per_filetype` completion source lists. + ''; + }; + settings = lib.mkOption { + default = { }; + description = '' + Settings for the blink.cmp completion provider. + ''; + example = settingsExample; + type = lib.types.submodule [ + { + options.enabled = internal; + options.module = internal; + } + ../plugins/by-name/blink-cmp/provider-config.nix + ]; + }; + }; + }; + config = lib.mkMerge [ + (lib.setAttrByPath loc { + # NOTE: this could be defined within the `blink.settings` submodule, + # but that would not populate the option's `definitions` list. + # Meaning we wouldn't be able to propagate the definitions further using `mkAliasDefinitions`. + blink.settings = { + name = lib.mkDefault sourceName; + inherit module; + opts = lib.mkIf usePluginSettings (lib.modules.mkAliasDefinitions pluginOpts.settings); + }; + }) + (lib.mkIf (pluginCfg.enable && cfg.enable) { + plugins.blink-cmp.settings.sources = { + # Use mkAliasDefinitions to preserve override priorities + providers.${cfg.key} = lib.modules.mkAliasDefinitions opt.settings; + default = lib.mkIf cfg.default [ cfg.key ]; + # FIXME: the reference shows `cmdline` should/could be defined as a function + # https://cmp.saghen.dev/configuration/reference.html#sources + cmdline = lib.mkIf cfg.cmdline [ cfg.key ]; + per_filetype = lib.mkIf (cfg.filetypes != { }) ( + builtins.mapAttrs (_: _: [ cfg.key ]) cfg.filetypes + ); + }; + warnings = lib.nixvim.mkWarnings (lib.showOption loc) { + when = !config.plugins.blink-cmp.enable && options.plugins.blink-cmp.enable.highestPrio == 1500; + message = '' + You have enabled the blink.cmp provider, but `plugins.blink-cmp` is not enabled. + You can suppress this warning by explicitly setting `plugins.blink-cmp.enable = false`. + ''; + }; + }) + ]; + }; + + # Create a module configuring a plugin's integration with nvim-cmp and blink.cmp + mkCmpPluginModule = + { + # The plugin's option location-path + loc ? [ + "plugins" + pluginName + ], + # Name of the plugin, used in documentation + pluginName, + # The nvim-cmp source name + # TODO: can we compute a sane default for sourceName? + sourceName, + # Defaults for the corresponding cmp options + enableDefault ? true, + enableCmdline ? { }, + enabledFiletypes ? { }, + # Whether to include a `blink` option at all + offerBlinkCompatibility ? true, + # Defaults for the blink compatibility option + enableBlinkProvider ? false, + enableBlinkDefault ? false, + enableBlinkCmdline ? false, + enabledBlinkFiletypes ? { }, + # Whether the plugin's settings should be used as the blink provider's `opts` + usePluginSettingsForBlink ? false, + # The key to use with blink, + # i.e. the attr name for `sources.providers.` + # TODO: should this default to pluginName or sourceName? + blinkProviderKey ? lib.strings.toLower pluginName, + }: + { config, options, ... }: + let + pluginOpt = lib.getAttrFromPath loc options; + pluginCfg = lib.getAttrFromPath loc config; + blinkOpt = pluginOpt.blink; + blinkCfg = pluginCfg.blink; + cfg = pluginCfg.cmp; + toSourceDef = v: lib.optionalAttrs (builtins.isAttrs v) v // { inherit (cfg) name; }; + toSources = v: { sources = [ (toSourceDef v) ]; }; + in + { + imports = lib.optionals offerBlinkCompatibility [ + (lib.nixvim.modules.mkBlinkPluginModule { + inherit loc pluginName sourceName; + key = blinkProviderKey; + module = "blink.compat.source"; + enableProvider = enableBlinkProvider; + enableDefault = enableBlinkDefault; + enableCmdline = enableBlinkCmdline; + enabledFiletypes = enabledBlinkFiletypes; + usePluginSettings = usePluginSettingsForBlink; + }) + { + options = lib.setAttrByPath loc { + blink.settings.name = internal; + }; + config = lib.mkIf (pluginCfg.enable && blinkCfg.enable) { + # Enable blink-compat if the plugin has `blink.enable = true` + plugins.blink-compat.enable = true; + # This warning will show if someone overrides `plugins.blink-compat.enable = mkForce false` + warnings = lib.nixvim.mkWarnings (lib.showOption loc) { + when = !config.plugins.blink-compat.enable; + message = '' + `${blinkOpt.enable}` is enabled, but `${options.plugins.blink-compat.enable}` is not. + This plugin is a nvim-cmp source, so it requires blink.compat when used with blink.cmp. + ''; + }; + }; + } + ]; + options = lib.setAttrByPath loc { + cmp = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + example = false; + description = '' + Whether to integrate this plugin with nvim-cmp. + ''; + }; + name = lib.mkOption { + type = lib.types.str; + default = sourceName; + description = "${pluginName}'s nvim-cmp source name."; + internal = true; + }; + default = lib.mkOption { + type = with lib.types; either bool (attrsOf anything); + default = enableDefault; + example = !enableDefault; + description = '' + Whether to include this plugin in the `default` completion source list. + + Can be defined as attrs to pass additional config to the source. + ''; + }; + cmdline = lib.mkOption { + type = with lib.types; attrsOf (either bool (attrsOf anything)); + # Remove false attrs in the final value + apply = lib.filterAttrs (_: v: v != false); + default = enableCmdline; + # TODO: example + description = '' + Whether to include this plugin in the specific `cmdline` completion source lists. + + Elements can be defined as attrs to pass additional config to the source. + ''; + }; + filetypes = lib.mkOption { + type = with lib.types; attrsOf (either bool (attrsOf anything)); + # Remove false attrs in the final value + apply = lib.filterAttrs (_: v: v != false); + default = enabledFiletypes; + # TODO: example + description = '' + Whether to include this plugin in the specific `per_filetype` completion source lists. + + Elements can be defined as attrs to pass additional config to the source. + ''; + }; + }; + }; + config = lib.mkIf (pluginCfg.enable && cfg.enable) { + plugins.cmp = { + settings = lib.mkIf (cfg.default != false) (toSources cfg.default); + cmdline = lib.mkIf (cfg.cmdline != { }) (builtins.mapAttrs (_: toSources) cfg.cmdline); + filetype = lib.mkIf (cfg.filetypes != { }) (builtins.mapAttrs (_: toSources) cfg.filetypes); + }; + warnings = lib.nixvim.mkWarnings (lib.showOption loc) { + when = !config.plugins.cmp.enable && options.plugins.cmp.enable.highestPrio == 1500; + message = '' + You have enabled the nvim-cmp source, but `plugins.cmp` is not enabled. + You can suppress this warning by explicitly setting `plugins.cmp.enable = false`. + ''; + }; + }; + }; } // lib.mapAttrs ( name: msg: diff --git a/plugins/by-name/blink-cmp-copilot/default.nix b/plugins/by-name/blink-cmp-copilot/default.nix index 78fbce80f6..7524a1e090 100644 --- a/plugins/by-name/blink-cmp-copilot/default.nix +++ b/plugins/by-name/blink-cmp-copilot/default.nix @@ -1,48 +1,30 @@ { config, lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-cmp-copilot"; - package = "blink-cmp-copilot"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; maintainers = [ lib.maintainers.HeitorAugustoLN ]; - description = '' - This plugin should be configured through blink-cmp's source settings. - - For example: + callSetup = false; + hasLuaConfig = false; - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources = { - copilot = { - async = true; - module = "blink-cmp-copilot"; - name = "copilot"; - score_offset = 100; - }; + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default source name + sourceName = "copilot"; + settingsExample = { + async = true; + score_offset = 100; }; - }; - ``` - - And then you can add it as a source for blink-cmp: + }) + ]; - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "copilot" - ]; - }; - ``` - ''; - - callSetup = false; - hasLuaConfig = false; - hasSettings = false; + settingsExample = { + max_completions = 3; + }; extraConfig = { warnings = diff --git a/plugins/by-name/blink-cmp-dictionary/default.nix b/plugins/by-name/blink-cmp-dictionary/default.nix index ec0b523236..f15ee30a80 100644 --- a/plugins/by-name/blink-cmp-dictionary/default.nix +++ b/plugins/by-name/blink-cmp-dictionary/default.nix @@ -1,50 +1,36 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-cmp-dictionary"; - package = "blink-cmp-dictionary"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; maintainers = [ lib.maintainers.khaneliman ]; - description = '' - This plugin should be configured through blink-cmp's `sources.providers` settings. - - For example: + # Configured through blink-cmp + callSetup = false; + hasLuaConfig = false; - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.providers = { - dictionary = { - module = "blink-cmp-dictionary"; - name = "Dict"; - score_offset = 100; - min_keyword_length = 3; - # Optional configurations - opts = { + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default key + key = "dictionary"; + sourceName = "Dict"; + settingsExample = { + sources.providers = { + dictionary = { + score_offset = 100; + min_keyword_length = 3; }; }; }; - }; - ``` + }) + ]; - And then you can add it to blink-cmp's `sources.default` option: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "dictionary" - ]; - }; - ``` + settingsExample = lib.literalExpression '' + { + # Optional configurations + } ''; - - # Configured through blink-cmp - callSetup = false; - hasLuaConfig = false; - hasSettings = false; } diff --git a/plugins/by-name/blink-cmp-git/default.nix b/plugins/by-name/blink-cmp-git/default.nix index 9d87c6f1a4..5d3ce31f70 100644 --- a/plugins/by-name/blink-cmp-git/default.nix +++ b/plugins/by-name/blink-cmp-git/default.nix @@ -1,50 +1,31 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-cmp-git"; - package = "blink-cmp-git"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; maintainers = [ lib.maintainers.khaneliman ]; - description = '' - This plugin should be configured through blink-cmp's `sources.providers` settings. - - For example: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.providers = { - git = { - module = "blink-cmp-git"; - name = "git"; - score_offset = 100; - opts = { - commit = { }; - git_centers = { git_hub = { }; }; - }; - }; + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default + sourceName = "git"; + settingsExample = { + score_offset = 100; }; - }; - ``` - - And then you can add it to blink-cmp's `sources.default` option: + }) + ]; - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "git" - ]; + settingsExample = { + commit = { }; + git_centers = { + git_hub = { }; }; - ``` - ''; + }; # Configured through blink-cmp callSetup = false; hasLuaConfig = false; - hasSettings = false; } diff --git a/plugins/by-name/blink-cmp-spell/default.nix b/plugins/by-name/blink-cmp-spell/default.nix index dd29a75dbc..7dfbfe17b4 100644 --- a/plugins/by-name/blink-cmp-spell/default.nix +++ b/plugins/by-name/blink-cmp-spell/default.nix @@ -1,48 +1,25 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-cmp-spell"; - package = "blink-cmp-spell"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; maintainers = [ lib.maintainers.khaneliman ]; - description = '' - This plugin should be configured through blink-cmp's `sources.providers` settings. - - For example: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.providers = { - spell = { - module = "blink-cmp-spell"; - name = "Spell"; - score_offset = 100; - opts = { - }; - }; + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default + key = "spell"; + sourceName = "Spell"; + settingsExample = { + score_offset = 100; }; - }; - ``` - - And then you can add it to blink-cmp's `sources.default` option: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "spell" - ]; - }; - ``` - ''; + }) + ]; # Configured through blink-cmp callSetup = false; hasLuaConfig = false; - hasSettings = false; } diff --git a/plugins/by-name/blink-cmp/default.nix b/plugins/by-name/blink-cmp/default.nix index 16e9b31268..bb378c33c9 100644 --- a/plugins/by-name/blink-cmp/default.nix +++ b/plugins/by-name/blink-cmp/default.nix @@ -14,6 +14,8 @@ lib.nixvim.plugins.mkNeovimPlugin { description = '' Performant, batteries-included completion plugin for Neovim. + + ''; settingsOptions = import ./settings-options.nix lib; diff --git a/plugins/by-name/blink-cmp/provider-config.nix b/plugins/by-name/blink-cmp/provider-config.nix index 27e4250437..18d33e25f5 100644 --- a/plugins/by-name/blink-cmp/provider-config.nix +++ b/plugins/by-name/blink-cmp/provider-config.nix @@ -1,9 +1,9 @@ -lib: +{ lib, ... }: let inherit (lib) types; inherit (lib.nixvim) defaultNullOpts; in -types.submodule { +{ freeformType = with types; attrsOf anything; options = { name = defaultNullOpts.mkStr' { diff --git a/plugins/by-name/blink-cmp/settings-options.nix b/plugins/by-name/blink-cmp/settings-options.nix index 17c252e57e..10b7e8e457 100644 --- a/plugins/by-name/blink-cmp/settings-options.nix +++ b/plugins/by-name/blink-cmp/settings-options.nix @@ -525,7 +525,7 @@ in ''; providers = mkNullOrOption' { - type = with types; attrsOf (import ./provider-config.nix lib); + type = with types; attrsOf (submodule ./provider-config.nix); description = '' Definition of completion providers. ''; diff --git a/plugins/by-name/blink-copilot/default.nix b/plugins/by-name/blink-copilot/default.nix index e01b0b240e..e4424b55db 100644 --- a/plugins/by-name/blink-copilot/default.nix +++ b/plugins/by-name/blink-copilot/default.nix @@ -1,60 +1,38 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-copilot"; - package = "blink-copilot"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; maintainers = [ lib.maintainers.khaneliman ]; - description = '' - This plugin should be configured through blink-cmp's `sources.providers` settings. - - For example: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.providers = { - copilot = { - async = true; - module = "blink-copilot"; - name = "copilot"; - score_offset = 100; - # Optional configurations - opts = { - max_completions = 3; - max_attempts = 4; - kind = "Copilot"; - debounce = 750; - auto_refresh = { - backward = true; - forward = true; - }; - }; - }; + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default + sourceName = "copilot"; + settingsExample = { + async = true; + score_offset = 100; }; + }) + ]; + + settingsExample = { + max_completions = 3; + max_attempts = 4; + kind = "Copilot"; + debounce = 750; + auto_refresh = { + backward = true; + forward = true; }; - ``` - - And then you can add it to blink-cmp's `sources.default` option: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "copilot" - ]; - }; - ``` - ''; + }; # Configured through blink-cmp callSetup = false; hasLuaConfig = false; - hasSettings = false; extraConfig = { plugins.copilot-lua.enable = lib.mkDefault true; diff --git a/plugins/by-name/blink-emoji/default.nix b/plugins/by-name/blink-emoji/default.nix index 4a2c033dfc..41af585eb7 100644 --- a/plugins/by-name/blink-emoji/default.nix +++ b/plugins/by-name/blink-emoji/default.nix @@ -1,51 +1,32 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-emoji"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; packPathName = "blink-emoji.nvim"; package = "blink-emoji-nvim"; maintainers = [ lib.maintainers.khaneliman ]; - description = '' - This plugin should be configured through blink-cmp's `sources.providers` settings. - - For example: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.providers = { - emoji = { - module = "blink-emoji"; - name = "Emoji"; - score_offset = 15; - # Optional configurations - opts = { - insert = true; - }; - }; + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default + key = "emoji"; + sourceName = "Emoji"; + module = "blink-emoji"; + settingsExample = { + score_offset = 15; }; - }; - ``` - - And then you can add it to blink-cmp's `sources.default` option: + }) + ]; - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "emoji" - ]; - }; - ``` - ''; + settingsExample = { + insert = true; + }; # Configured through blink-cmp callSetup = false; hasLuaConfig = false; - hasSettings = false; } diff --git a/plugins/by-name/blink-ripgrep/default.nix b/plugins/by-name/blink-ripgrep/default.nix index a8eb71340d..1be8ed7aed 100644 --- a/plugins/by-name/blink-ripgrep/default.nix +++ b/plugins/by-name/blink-ripgrep/default.nix @@ -1,61 +1,43 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "blink-ripgrep"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; packPathName = "blink-ripgrep.nvim"; package = "blink-ripgrep-nvim"; maintainers = [ lib.maintainers.khaneliman ]; - description = '' - This plugin should be configured through blink-cmp's `sources.providers` settings. - - For example: - - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.providers = { - ripgrep = { - async = true; - module = "blink-ripgrep"; - name = "Ripgrep"; - score_offset = 100; - opts = { - prefix_min_len = 3; - context_size = 5; - max_filesize = "1M"; - project_root_marker = ".git"; - project_root_fallback = true; - search_casing = "--ignore-case"; - additional_rg_options = {}; - fallback_to_regex_highlighting = true; - ignore_paths = {}; - additional_paths = {}; - debug = false; - }; - }; + imports = [ + (lib.nixvim.modules.mkBlinkPluginModule { + pluginName = name; + # TODO: compute a sane-default + key = "ripgrep"; + sourceName = "Ripgrep"; + module = "blink-ripgrep"; + settingsExample = { + async = true; + score_offset = 100; }; - }; - ``` - - And then you can add it to blink-cmp's `sources.default` option: + }) + ]; - ```nix - plugins.blink-cmp = { - enable = true; - settings.sources.default = [ - "lsp" - "path" - "luasnip" - "buffer" - "ripgrep" - ]; - }; - ``` - ''; + settingsExample = { + prefix_min_len = 3; + context_size = 5; + max_filesize = "1M"; + project_root_marker = ".git"; + project_root_fallback = true; + search_casing = "--ignore-case"; + additional_rg_options = { }; + fallback_to_regex_highlighting = true; + ignore_paths = { }; + additional_paths = { }; + debug = false; + }; # Configured through blink-cmp callSetup = false; hasLuaConfig = false; - hasSettings = false; } diff --git a/plugins/by-name/cmp-ai/default.nix b/plugins/by-name/cmp-ai/default.nix index aee2bd058a..7200ffe4e4 100644 --- a/plugins/by-name/cmp-ai/default.nix +++ b/plugins/by-name/cmp-ai/default.nix @@ -4,14 +4,18 @@ }: let inherit (lib.nixvim) defaultNullOpts; + name = "cmp-ai"; in lib.nixvim.plugins.mkNeovimPlugin { - name = "cmp-ai"; + inherit name; maintainers = [ lib.maintainers.GaetanLepage ]; imports = [ - { cmpSourcePlugins.cmp_ai = "cmp-ai"; } + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = "cmp_ai"; + }) ]; moduleName = "cmp_ai.config"; diff --git a/plugins/by-name/cmp-git/default.nix b/plugins/by-name/cmp-git/default.nix index 1c079ce1c9..ddcc5b0114 100644 --- a/plugins/by-name/cmp-git/default.nix +++ b/plugins/by-name/cmp-git/default.nix @@ -2,12 +2,18 @@ lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "cmp-git"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; moduleName = "cmp_git"; imports = [ - { cmpSourcePlugins.git = "cmp-git"; } + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = "git"; + }) ]; maintainers = [ lib.maintainers.GaetanLepage ]; diff --git a/plugins/by-name/cmp-tabby/default.nix b/plugins/by-name/cmp-tabby/default.nix index fe5fdd8c0f..cfbc12ecde 100644 --- a/plugins/by-name/cmp-tabby/default.nix +++ b/plugins/by-name/cmp-tabby/default.nix @@ -2,14 +2,18 @@ let inherit (lib) types; inherit (lib.nixvim) defaultNullOpts; + name = "cmp-tabby"; in lib.nixvim.plugins.mkNeovimPlugin { - name = "cmp-tabby"; + inherit name; maintainers = [ lib.maintainers.GaetanLepage ]; imports = [ - { cmpSourcePlugins.cmp_tabby = "cmp-tabby"; } + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = "cmp_tabby"; + }) ]; deprecateExtraOptions = true; diff --git a/plugins/by-name/cmp-tabnine/default.nix b/plugins/by-name/cmp-tabnine/default.nix index 2f5b37d069..75c2899a07 100644 --- a/plugins/by-name/cmp-tabnine/default.nix +++ b/plugins/by-name/cmp-tabnine/default.nix @@ -2,14 +2,18 @@ let inherit (lib) types; inherit (lib.nixvim) defaultNullOpts; + name = "cmp-tabnine"; in lib.nixvim.plugins.mkNeovimPlugin { - name = "cmp-tabnine"; + inherit name; maintainers = [ lib.maintainers.GaetanLepage ]; imports = [ - { cmpSourcePlugins.cmp_tabnine = "cmp-tabnine"; } + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = "cmp_tabnine"; + }) ]; deprecateExtraOptions = true; diff --git a/plugins/by-name/codeium-nvim/default.nix b/plugins/by-name/codeium-nvim/default.nix index 01fdb96200..01c7aff0b9 100644 --- a/plugins/by-name/codeium-nvim/default.nix +++ b/plugins/by-name/codeium-nvim/default.nix @@ -4,9 +4,10 @@ }: let inherit (lib.nixvim) defaultNullOpts; + name = "codeium-nvim"; in lib.nixvim.plugins.mkNeovimPlugin { - name = "codeium-nvim"; + inherit name; packPathName = "codeium.nvim"; moduleName = "codeium"; @@ -51,9 +52,12 @@ lib.nixvim.plugins.mkNeovimPlugin { "wrapper" ]; - # Register nvim-cmp association imports = [ - { cmpSourcePlugins.codeium = "codeium-nvim"; } + # Register nvim-cmp association + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = "codeium"; + }) ]; settingsOptions = { diff --git a/plugins/by-name/copilot-cmp/default.nix b/plugins/by-name/copilot-cmp/default.nix index 56c6f19c5c..eaafe4b806 100644 --- a/plugins/by-name/copilot-cmp/default.nix +++ b/plugins/by-name/copilot-cmp/default.nix @@ -2,13 +2,17 @@ let inherit (lib) types; inherit (lib.nixvim) defaultNullOpts; + name = "copilot-cmp"; in lib.nixvim.plugins.mkNeovimPlugin { - name = "copilot-cmp"; + inherit name; moduleName = "copilot_cmp"; imports = [ - { cmpSourcePlugins.copilot = "copilot-cmp"; } + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = "copilot"; + }) ]; maintainers = [ lib.maintainers.GaetanLepage ]; diff --git a/plugins/by-name/crates/default.nix b/plugins/by-name/crates/default.nix index 17429adbe9..e574187227 100644 --- a/plugins/by-name/crates/default.nix +++ b/plugins/by-name/crates/default.nix @@ -1,13 +1,21 @@ { lib, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "crates"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; packPathName = "crates.nvim"; package = "crates-nvim"; maintainers = [ lib.maintainers.GaetanLepage ]; imports = - [ { cmpSourcePlugins.crates = "crates"; } ] + [ + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = name; + }) + ] ++ # TODO introduced 2024-12-12: remove after 25.05 lib.nixvim.mkSettingsRenamedOptionModules [ "plugins" "crates-nvim" ] diff --git a/plugins/by-name/otter/default.nix b/plugins/by-name/otter/default.nix index d2c2d3efc2..a213e8b7d1 100644 --- a/plugins/by-name/otter/default.nix +++ b/plugins/by-name/otter/default.nix @@ -25,12 +25,6 @@ lib.nixvim.plugins.mkNeovimPlugin { > If you previously used the otter nvim-cmp source, you can remove it, as the completion results now come directly via the cmp-nvim-lsp source together with other language servers. '' ) - - # Register nvim-cmp association - # TODO: Otter is no longer a cmp-source - # Deprecated 2024-09-22; remove after 24.11 - # Note: a warning is implemented in plugins/cmp/auto-enable.nix - { cmpSourcePlugins.otter = "otter"; } ]; settingsOptions = { diff --git a/plugins/by-name/papis/default.nix b/plugins/by-name/papis/default.nix index 0ef51b3025..eec072f96c 100644 --- a/plugins/by-name/papis/default.nix +++ b/plugins/by-name/papis/default.nix @@ -1,13 +1,21 @@ { lib, pkgs, ... }: -lib.nixvim.plugins.mkNeovimPlugin { +let name = "papis"; +in +lib.nixvim.plugins.mkNeovimPlugin { + inherit name; packPathName = "papis.nvim"; package = "papis-nvim"; maintainers = [ lib.maintainers.GaetanLepage ]; - # papis.nvim is an nvim-cmp source too - imports = [ { cmpSourcePlugins.papis = "papis"; } ]; + imports = [ + # papis.nvim is an nvim-cmp source too + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = name; + }) + ]; extraOptions = { yqPackage = lib.mkPackageOption pkgs "yq" { diff --git a/plugins/by-name/vim-dadbod-completion/default.nix b/plugins/by-name/vim-dadbod-completion/default.nix index ca4d249d9d..4d61ab5125 100644 --- a/plugins/by-name/vim-dadbod-completion/default.nix +++ b/plugins/by-name/vim-dadbod-completion/default.nix @@ -1,8 +1,14 @@ { lib, ... }: -lib.nixvim.plugins.mkVimPlugin { +let name = "vim-dadbod-completion"; +in +lib.nixvim.plugins.mkVimPlugin { + inherit name; maintainers = [ lib.maintainers.BoneyPatel ]; imports = [ - { cmpSourcePlugins.vim-dadbod-completion = "vim-dadbod-completion"; } + (lib.nixvim.modules.mkCmpPluginModule { + pluginName = name; + sourceName = name; + }) ]; } diff --git a/plugins/cmp/auto-enable.nix b/plugins/cmp/auto-enable.nix deleted file mode 100644 index 272635f87e..0000000000 --- a/plugins/cmp/auto-enable.nix +++ /dev/null @@ -1,102 +0,0 @@ -{ - lib, - config, - ... -}: -let - cfg = config.plugins.cmp; - - extractSources = { sources, ... }: if lib.isList sources then sources else [ ]; - - # Collect the names of the sources provided by the user - # ["foo" "bar"] - enabledSources = - lib.pipe - [ - # cfg.setup.sources - (extractSources cfg.settings) - # cfg.filetype..sources - (lib.mapAttrsToList (_: extractSources) cfg.filetype) - # cfg.cmdline..sources - (lib.mapAttrsToList (_: extractSources) cfg.cmdline) - ] - [ - lib.flatten - (map (lib.getAttr "name")) - lib.unique - ]; -in -{ - options = { - # Note: this option must be outside of `plugins` to avoid infinite recursion - cmpSourcePlugins = lib.mkOption { - type = with lib.types; attrsOf str; - default = { }; - description = '' - Internal option used to associate nvim-cmp source names with nixvim plugin module names. - - Maps ` = ` where _plugin-name_ is the module name: `plugins..enable`. - ''; - example = { - foo = "cmp-foo"; - bar = "cmp-bar"; - }; - internal = true; - visible = false; - }; - - plugins.cmp.autoEnableSources = lib.mkOption { - type = lib.types.bool; - default = true; - example = false; - description = '' - Scans the sources array and enable the corresponding plugins if they are known to nixvim. - ''; - }; - }; - - config = lib.mkIf (cfg.enable && cfg.autoEnableSources) ( - lib.mkMerge [ - { - warnings = lib.nixvim.mkWarnings "plugins.cmp" [ - # TODO: expand this warning to ft & cmd sources lists and `showDefs` the offending definitions - { - when = lib.types.isRawType cfg.settings.sources; - message = '' - You have enabled `autoEnableSources` that tells Nixvim to automatically - enable the source plugins with respect to the list of sources provided in `settings.sources`. - However, the latter is proveded as a raw lua string which is not parseable by Nixvim. - - If you want to keep using raw lua for defining your sources: - - Ensure you enable the relevant plugins manually in your configuration; - - Dismiss this warning by explicitly setting `autoEnableSources` to `false`; - ''; - } - # TODO: Added 2024-09-22; remove after 24.11 - { - when = lib.elem "otter" enabledSources; - message = '' - "otter" is listed in `settings.sources`, however it is no longer a cmp source. - Instead, you should enable `plugins.otter` and use the "cmp-nvim-lsp" completion source. - ''; - } - ]; - - # If the user has enabled the `foo` and `bar` sources, then `plugins` will look like: - # { - # cmp-foo.enable = true; - # cmp-bar.enable = true; - # } - plugins = lib.mapAttrs' (source: name: { - inherit name; - value.enable = lib.mkIf (lib.elem source enabledSources) true; - }) config.cmpSourcePlugins; - } - { - plugins.lsp.capabilities = lib.mkIf (lib.elem "nvim_lsp" enabledSources) '' - capabilities = vim.tbl_deep_extend("force", capabilities, require('cmp_nvim_lsp').default_capabilities()) - ''; - } - ] - ); -} diff --git a/plugins/cmp/default.nix b/plugins/cmp/default.nix index bf3378b4a4..1a931407c5 100644 --- a/plugins/cmp/default.nix +++ b/plugins/cmp/default.nix @@ -17,21 +17,21 @@ lib.nixvim.plugins.mkNeovimPlugin { description = '' ### Completion Source Installation - If `plugins.cmp.autoEnableSources` is `true` Nixivm will automatically enable the corresponding source - plugins. This is the default behavior, but will work only when this option is set to a list. + By default, plugins that offer a cmp source will enable the source when they are enabled. + This can be configured or disabled using the `plugins.*.cmp` options. - If you use a raw lua string or set `plugins.cmp.autoEnableSources` to `false`, you will need to explicitly enable the relevant source plugins in - your nixvim configuration. + #### With auto-enabled sources ```nix - plugins.cmp = { - autoEnableSources = true; - settings.sources = [ - { name = "nvim_lsp"; } - { name = "path"; } - { name = "buffer"; } - ]; + plugins = { + cmp.enable = true; + cmp-nvim-lsp.enable = true; + cmp-path.enable = true; + cmp-buffer.enable = true; }; ``` @@ -39,18 +39,26 @@ lib.nixvim.plugins.mkNeovimPlugin { ```nix plugins = { cmp = { - autoEnableSources = false; + enable = true; settings.sources = [ { name = "nvim_lsp"; } { name = "path"; } { name = "buffer"; } ]; }; - cmp-nvim-lsp.enable = true; - cmp-path.enable = true; - cmp-buffer.enable = true; + cmp-nvim-lsp = { + enable = true; + cmp.enable = false; + }; + cmp-path = { + enable = true; + cmp.enable = false; + }; + cmp-buffer = { + enable = true; + cmp.enable = false; + }; }; - ``` ''; @@ -58,7 +66,6 @@ lib.nixvim.plugins.mkNeovimPlugin { # Introduced on 2024 February 21 # TODO: remove ~June 2024 ./deprecations.nix - ./auto-enable.nix ./sources ]; deprecateExtraOptions = true; diff --git a/plugins/cmp/deprecated-auto-enable.nix b/plugins/cmp/deprecated-auto-enable.nix new file mode 100644 index 0000000000..901f8f76bb --- /dev/null +++ b/plugins/cmp/deprecated-auto-enable.nix @@ -0,0 +1,141 @@ +{ + lib, + config, + options, + ... +}: +let + cfg = config.plugins.cmp; + opt = options.plugins.cmp; + + cleanSrc = lib.flip builtins.removeAttrs [ + "name" + ]; + + isRaw = v: v ? __raw || v._type or null == "lua-inline"; + + getSrcDefs = + sourceName: list: + if builtins.isList list then + lib.pipe list [ + (builtins.filter (src: !isRaw src)) + (builtins.filter (src: src.name == sourceName)) + (builtins.map (lib.filterAttrs (_: v: v != null))) + lib.mergeAttrsList + ] + else + lib.throwIfNot (isRaw list) + "cmp/deprecated-auto-enable: unexpected cmp sources type: ${builtins.typeOf list}" + { }; + + getNestedSrcDefs = + sourceName: set: + lib.pipe set [ + (builtins.mapAttrs (_: settings: getSrcDefs sourceName settings.sources)) + (lib.filterAttrs (_: v: v != { })) + (builtins.mapAttrs (_: cleanSrc)) + ]; + + # Check if the source is listed in `plugins.cmp.settings.sources` without the plugin being enabled + # This is most likely to happen when a user was relying on the now removed `autoEnableSources` option + # Produce a warning with detailed migration instructions. + mkWarningDef = + name: + let + pluginOpt = options.plugins.${name}; + pluginCfg = config.plugins.${name}; + pluginLoc = lib.dropEnd 1 pluginOpt.enable.loc; + cmpLoc = lib.dropEnd 1 options.plugins.cmp.enable.loc; + + # Collect defined sources for this plugin + defaultDef = getSrcDefs pluginCfg.cmp.name cfg.settings.sources; + sourceDefs = + lib.optionalAttrs (defaultDef != { }) { + default = cleanSrc defaultDef; + } + // lib.filterAttrs (_: v: v != { }) { + cmdline = getNestedSrcDefs pluginCfg.cmp.name cfg.cmdline; + filetypes = getNestedSrcDefs pluginCfg.cmp.name cfg.filetype; + }; + + indent = " "; + + showSrcDef = + loc: new: def: + let + defLoc = lib.showOption (cmpLoc ++ loc ++ [ "sources" ]); + join = if lib.hasInfix "\n" suggestion then "\n" + indent else " "; + suggestion = "${lib.showOption (pluginLoc ++ [ "cmp" ] ++ new)} = ${ + if def == { } then "true" else lib.generators.toPretty { inherit indent; } def + };"; + in + [ + "remove ${builtins.toJSON pluginCfg.cmp.name} from: ${defLoc}" + "instead define:${join}${suggestion}" + ]; + + lines = lib.flatten ( + lib.singleton "manually enable `${pluginOpt.enable}`" + ++ lib.optional (sourceDefs ? default) (showSrcDef [ "settings" ] [ "default" ] sourceDefs.default) + ++ lib.mapAttrsToList (name: showSrcDef [ "cmdline" name ] [ "cmdline" name ]) ( + sourceDefs.cmdline or { } + ) + ++ lib.mapAttrsToList (name: showSrcDef [ "filetype" name ] [ "filetypes" name ]) ( + sourceDefs.filetype or { } + ) + ); + + lineCount = builtins.length lines; + in + lib.mkIf + ( + cfg.enable + && !pluginCfg.enable + && pluginOpt.enable.highestPrio == 1500 + && pluginCfg.cmp.enable + && sourceDefs != { } + ) + ( + lib.nixvim.mkWarnings (lib.showOption pluginLoc) '' + The ${builtins.toJSON pluginCfg.cmp.name} nvim-cmp source has been defined via `${lib.showOption cmpLoc}`, howevew `${pluginOpt.enable}` is not enabled. + You should${ + if lineCount == 1 then + " " + builtins.head lines + else + ":" + + lib.concatImapStrings ( + i: line: "\n${builtins.toString i}. ${lib.nixvim.utils.upperFirstChar line}" + ) lines + } + You can suppress this warning by explicitly setting `${pluginOpt.enable} = false`. + '' # TODO: link to PR/docs/guide/faq + ); +in +{ + imports = [ + (lib.mkRemovedOptionModule [ + "cmpSourcePlugins" + ] "Use `lib.nixvim.modules.mkCmpPluginModule` instead.") + (lib.mkRemovedOptionModule [ "plugins" "cmp" "autoEnableSources" ] '' + Instead of defining `${ + lib.showOption (opt.settings.loc ++ [ "sources" ]) + }` and using `autoEnableSources` to enable the relevant plugins, + you should now enable the plugins and they will automatically add themselves to `${ + lib.showOption (opt.settings.loc ++ [ "sources" ]) + }`. + '') # TODO: add a link to PR/docs/faq/guide + ]; + + warnings = lib.pipe options.plugins [ + (lib.flip builtins.removeAttrs [ + # lspkind has its own `cmp` options, but isn't a nvim-cmp source + "lspkind" + ]) + # Actual options are probably aliases, not plugins + (lib.filterAttrs (_: opt: !lib.isOption opt)) + (lib.filterAttrs (_: opt: opt ? cmp)) + builtins.attrNames + (builtins.map mkWarningDef) + lib.mkMerge + ]; +} diff --git a/plugins/cmp/deprecations.nix b/plugins/cmp/deprecations.nix index 66ff925f2d..a45c60bfa2 100644 --- a/plugins/cmp/deprecations.nix +++ b/plugins/cmp/deprecations.nix @@ -168,6 +168,8 @@ let in { imports = renameWarnings ++ [ + # auto-enable was removed 2025-02-07 + ./deprecated-auto-enable.nix (mkRenamedOptionModule (oldPluginBasePath ++ [ "enable" ]) (newPluginBasePath ++ [ "enable" ])) (mkRenamedOptionModule (oldPluginBasePath ++ [ "autoEnableSources" ]) ( newPluginBasePath ++ [ "autoEnableSources" ] diff --git a/plugins/cmp/options/sources-option.nix b/plugins/cmp/options/sources-option.nix index ef82aa2575..4f53fb0a94 100644 --- a/plugins/cmp/options/sources-option.nix +++ b/plugins/cmp/options/sources-option.nix @@ -89,11 +89,52 @@ lib.mkOption { Can either be a list of `sourceConfigs` which will be made directly to a Lua object. Or it can be a raw lua string which might be necessary for more advanced use cases. - WARNING: - If `plugins.cmp.autoEnableSources` Nixivm will automatically enable the corresponding source - plugins. This will work only when this option is set to a list. - If you use a raw lua string, you will need to explicitly enable the relevant source plugins in - your nixvim configuration. + > [!TIP] + > Most of the time, you should enable sources by enabling the respective plugin. E.g: + > ```nix + > plugins = { + > cmp.enable = true; + > cmp-nvim-lsp.enable = true; + > cmp-path.enable = true; + > cmp-buffer.enable = true; + > }; + > ``` + + + + > [!WARNING] + > Automatic enabling will only work when `sources` is not defined or is defined as a list. + > + > If this option is defined as "raw lua", then you must take care to disable auto-enabling, e.g: + > ```nix + > plugins = { + > cmp = { + > enable = true; + > settings.sources.__raw = ''' + > { + > { name = "nvim_lsp" }, + > { name = "path" }, + > { name = "buffer" }, + > } + > ''' + > }; + > cmp-nvim-lsp = { + > enable = true; + > cmp.enable = false; + > }; + > cmp-path = { + > enable = true; + > cmp.enable = false; + > }; + > cmp-buffer = { + > enable = true; + > cmp.enable = false; + > }; + > }; + > ``` ''; example = [ { name = "nvim_lsp"; } diff --git a/plugins/cmp/sources/_mk-cmp-plugin.nix b/plugins/cmp/sources/_mk-cmp-plugin.nix index cad16699a4..39706ac83b 100644 --- a/plugins/cmp/sources/_mk-cmp-plugin.nix +++ b/plugins/cmp/sources/_mk-cmp-plugin.nix @@ -1,3 +1,4 @@ +# TODO: Remove this legacy function in favor of using `mkCmpPluginModule` directly { lib, pkgs, @@ -12,6 +13,8 @@ ] { }, maintainers ? [ lib.maintainers.GaetanLepage ], imports ? [ ], + # Whether to add a `plugin.*.blink` option, that uses blink.compat + mkCmpPluginModuleArgs ? { }, ... }@args: lib.nixvim.plugins.mkVimPlugin ( @@ -24,8 +27,8 @@ lib.nixvim.plugins.mkVimPlugin ( name = pluginName; imports = imports ++ [ - # Register the source -> plugin name association - { cmpSourcePlugins.${sourceName} = pluginName; } + # Create the `plugin.*.cmp` option + (lib.nixvim.modules.mkCmpPluginModule (mkCmpPluginModuleArgs // { inherit pluginName sourceName; })) ]; } ) diff --git a/plugins/cmp/sources/default.nix b/plugins/cmp/sources/default.nix index b68b762ffb..c435548f89 100644 --- a/plugins/cmp/sources/default.nix +++ b/plugins/cmp/sources/default.nix @@ -8,7 +8,7 @@ let # A list of most cmp source plugins, passed to mkCmpSourcePlugin. # More complex cmp sources can instead be defined as their own plugin - # and register their source-name association using the `cmpSourcePlugins` option. + # and import a module constructed by `lib.nixvim.modules.mkCmpPluginModule`. sources = [ { pluginName = "cmp-async-path"; @@ -96,6 +96,11 @@ let { pluginName = "cmp-nvim-lsp"; sourceName = "nvim_lsp"; + extraConfig = cfg: { + plugins.lsp.capabilities = '' + capabilities = vim.tbl_deep_extend("force", capabilities, require('cmp_nvim_lsp').default_capabilities()) + ''; + }; } { pluginName = "cmp-nvim-lsp-document-symbol"; diff --git a/tests/test-sources/example-configurations/issues.nix b/tests/test-sources/example-configurations/issues.nix index a25494fec5..e4c6921182 100644 --- a/tests/test-sources/example-configurations/issues.nix +++ b/tests/test-sources/example-configurations/issues.nix @@ -105,7 +105,6 @@ cmp = { enable = true; - autoEnableSources = true; settings = { formatting = { @@ -125,19 +124,20 @@ end ''; }; - sources = [ - { name = "nvim_lsp"; } - { - name = "luasnip"; - option = { - show_autosnippets = true; - }; - } - { name = "path"; } - { name = "buffer"; } - ]; }; }; + + # Completion sources + cmp-path.enable = true; + cmp-buffer.enable = true; + cmp-nvim-lsp.enable = true; + cmp_luasnip = { + enable = true; + cmp.default = { + option.show_autosnippets = true; + }; + }; + barbar.enable = true; web-devicons.enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-cmp-copilot/default.nix b/tests/test-sources/plugins/by-name/blink-cmp-copilot/default.nix index 35eec8bd45..4221191d25 100644 --- a/tests/test-sources/plugins/by-name/blink-cmp-copilot/default.nix +++ b/tests/test-sources/plugins/by-name/blink-cmp-copilot/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-copilot.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-copilot = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-cmp-dictionary/default.nix b/tests/test-sources/plugins/by-name/blink-cmp-dictionary/default.nix index a0853b8607..b2c48136f9 100644 --- a/tests/test-sources/plugins/by-name/blink-cmp-dictionary/default.nix +++ b/tests/test-sources/plugins/by-name/blink-cmp-dictionary/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-dictionary.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-dictionary = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-cmp-git/default.nix b/tests/test-sources/plugins/by-name/blink-cmp-git/default.nix index d920f5b29d..4afaf2611c 100644 --- a/tests/test-sources/plugins/by-name/blink-cmp-git/default.nix +++ b/tests/test-sources/plugins/by-name/blink-cmp-git/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-git.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-git = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-cmp-spell/default.nix b/tests/test-sources/plugins/by-name/blink-cmp-spell/default.nix index a23c97c3ae..8c913cd17d 100644 --- a/tests/test-sources/plugins/by-name/blink-cmp-spell/default.nix +++ b/tests/test-sources/plugins/by-name/blink-cmp-spell/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-spell.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-cmp-spell = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-cmp/default.nix b/tests/test-sources/plugins/by-name/blink-cmp/default.nix index 985616aaa0..f47a7d4e77 100644 --- a/tests/test-sources/plugins/by-name/blink-cmp/default.nix +++ b/tests/test-sources/plugins/by-name/blink-cmp/default.nix @@ -414,4 +414,47 @@ }; plugins.lsp.enable = true; }; + + # Test that a provider plugin's settings are propagated to `plugins.blink-cmp.settings.providers` + provider-settings = + { config, lib, ... }: + let + expectEqual = name: expected: actual: { + assertion = expected == actual; + message = '' + Expected ${name} to equal: + ${lib.generators.toPretty { } expected} + But found: + ${lib.generators.toPretty { } actual} + ''; + }; + in + { + test.buildNixvim = false; + assertions = [ + (expectEqual "config.plugins.blink-cmp-git.blink.settings" { + name = "git"; + module = "blink-cmp-git"; + bar = "bar"; + opts.foo = "foo"; + } (lib.filterAttrs (_: v: v != null) config.plugins.blink-cmp-git.blink.settings)) + (expectEqual "config.plugins.blink-cmp.settings.sources.providers.git" { + name = "git"; + module = "blink-cmp-git"; + bar = "bar"; + opts.foo = "foo"; + } (lib.filterAttrs (_: v: v != null) config.plugins.blink-cmp.settings.sources.providers.git)) + ]; + + plugins.blink-cmp.enable = true; + plugins.blink-cmp-git = { + enable = true; + settings = { + foo = "foo"; + }; + blink.settings = { + bar = "bar"; + }; + }; + }; } diff --git a/tests/test-sources/plugins/by-name/blink-copilot/default.nix b/tests/test-sources/plugins/by-name/blink-copilot/default.nix index 42bbab9f3a..a9b08bf4d2 100644 --- a/tests/test-sources/plugins/by-name/blink-copilot/default.nix +++ b/tests/test-sources/plugins/by-name/blink-copilot/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-copilot.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-copilot = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-emoji/default.nix b/tests/test-sources/plugins/by-name/blink-emoji/default.nix index 28771af335..5bd7d76123 100644 --- a/tests/test-sources/plugins/by-name/blink-emoji/default.nix +++ b/tests/test-sources/plugins/by-name/blink-emoji/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-emoji.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-emoji = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/blink-ripgrep/default.nix b/tests/test-sources/plugins/by-name/blink-ripgrep/default.nix index 1e595c5ec4..883f343d4e 100644 --- a/tests/test-sources/plugins/by-name/blink-ripgrep/default.nix +++ b/tests/test-sources/plugins/by-name/blink-ripgrep/default.nix @@ -1,9 +1,11 @@ { empty = { + plugins.blink-cmp.enable = true; plugins.blink-ripgrep.enable = true; }; defaults = { + plugins.blink-cmp.enable = true; plugins.blink-ripgrep = { enable = true; }; diff --git a/tests/test-sources/plugins/by-name/cmp-ai/default.nix b/tests/test-sources/plugins/by-name/cmp-ai/default.nix index 389fb5e74f..57de4a33f0 100644 --- a/tests/test-sources/plugins/by-name/cmp-ai/default.nix +++ b/tests/test-sources/plugins/by-name/cmp-ai/default.nix @@ -3,9 +3,9 @@ # We do not provide the required HF_API_KEY environment variable. test.runNvim = false; - plugins.cmp = { - enable = true; - settings.sources = [ { name = "cmp_ai"; } ]; + plugins = { + cmp.enable = true; + cmp-ai.enable = true; }; }; @@ -14,10 +14,8 @@ test.runNvim = false; plugins = { - cmp = { - enable = true; - settings.sources = [ { name = "cmp_ai"; } ]; - }; + cmp.enable = true; + cmp-ai.enable = true; cmp-ai.settings = { max_lines = 1000; provider = "HF"; diff --git a/tests/test-sources/plugins/by-name/cmp-git/default.nix b/tests/test-sources/plugins/by-name/cmp-git/default.nix index a80f0a043b..c4721bdeea 100644 --- a/tests/test-sources/plugins/by-name/cmp-git/default.nix +++ b/tests/test-sources/plugins/by-name/cmp-git/default.nix @@ -1,11 +1,9 @@ { defaults = { plugins = { - cmp = { - enable = true; - settings.sources = [ { name = "git"; } ]; - }; + cmp.enable = true; + cmp-git.enable = true; cmp-git.settings = { filetypes = [ "gitcommit" @@ -140,11 +138,9 @@ example = { plugins = { - cmp = { - enable = true; - settings.sources = [ { name = "git"; } ]; - }; + cmp.enable = true; + cmp-git.enable = true; cmp-git.settings = { remotes = [ "upstream" diff --git a/tests/test-sources/plugins/by-name/cmp-tabby/default.nix b/tests/test-sources/plugins/by-name/cmp-tabby/default.nix index e9816b955a..44df12b1f3 100644 --- a/tests/test-sources/plugins/by-name/cmp-tabby/default.nix +++ b/tests/test-sources/plugins/by-name/cmp-tabby/default.nix @@ -1,17 +1,15 @@ { empty = { - plugins.cmp = { - enable = true; - settings.sources = [ { name = "cmp_tabby"; } ]; - }; + plugins.cmp.enable = true; + plugins.cmp-tabby.enable = true; }; defaults = { plugins = { cmp = { enable = true; - settings.sources = [ { name = "cmp_tabby"; } ]; }; + cmp-tabby.enable = true; cmp-tabby.settings = { host = "http://localhost:5000"; max_lines = 100; diff --git a/tests/test-sources/plugins/by-name/codeium-nvim/default.nix b/tests/test-sources/plugins/by-name/codeium-nvim/default.nix index 7fc2279755..cb2f44ef6d 100644 --- a/tests/test-sources/plugins/by-name/codeium-nvim/default.nix +++ b/tests/test-sources/plugins/by-name/codeium-nvim/default.nix @@ -2,15 +2,18 @@ empty = { plugins.codeium-nvim = { enable = true; + cmp.enable = false; settings.enable_cmp_source = false; }; }; enabled-by-cmp = { - plugins.cmp = { - enable = true; - - settings.sources = [ { name = "codeium"; } ]; + plugins = { + cmp.enable = true; + codeium-nvim = { + enable = true; + settings.enable_cmp_source = false; + }; }; }; diff --git a/tests/test-sources/plugins/by-name/copilot-cmp/default.nix b/tests/test-sources/plugins/by-name/copilot-cmp/default.nix index 8be807f88a..8200fafa6f 100644 --- a/tests/test-sources/plugins/by-name/copilot-cmp/default.nix +++ b/tests/test-sources/plugins/by-name/copilot-cmp/default.nix @@ -1,11 +1,15 @@ { empty = { - plugins.copilot-cmp.enable = true; + plugins.copilot-cmp = { + enable = true; + cmp.enable = false; + }; }; defaults = { - plugins.copilot-cmp = { - enable = true; + plugins = { + cmp.enable = true; + copilot-cmp.enable = true; }; }; } diff --git a/tests/test-sources/plugins/by-name/crates/default.nix b/tests/test-sources/plugins/by-name/crates/default.nix index f466b3cb9f..ed39c8ea42 100644 --- a/tests/test-sources/plugins/by-name/crates/default.nix +++ b/tests/test-sources/plugins/by-name/crates/default.nix @@ -1,6 +1,8 @@ { empty = { plugins.crates.enable = true; + # Explicit disable to suppress warnings + plugins.cmp.enable = false; }; defaults = { @@ -202,6 +204,8 @@ }; }; }; + # Explicit disable to suppress warnings + plugins.cmp.enable = false; }; example = { @@ -214,5 +218,7 @@ autoupdate = true; }; }; + # Explicit disable to suppress warnings + plugins.cmp.enable = false; }; } diff --git a/tests/test-sources/plugins/by-name/papis/default.nix b/tests/test-sources/plugins/by-name/papis/default.nix index 19c23e4886..3fdabdf9b4 100644 --- a/tests/test-sources/plugins/by-name/papis/default.nix +++ b/tests/test-sources/plugins/by-name/papis/default.nix @@ -1,9 +1,11 @@ { empty = { plugins.papis.enable = true; + plugins.papis.cmp.enable = false; }; defaults = { + plugins.cmp.enable = true; plugins.papis = { enable = true; @@ -328,6 +330,7 @@ }; example = { + plugins.cmp.enable = true; plugins.papis = { enable = true; diff --git a/tests/test-sources/plugins/by-name/vim-dadbod-completion/default.nix b/tests/test-sources/plugins/by-name/vim-dadbod-completion/default.nix index 81a3f12d91..de4ec80db4 100644 --- a/tests/test-sources/plugins/by-name/vim-dadbod-completion/default.nix +++ b/tests/test-sources/plugins/by-name/vim-dadbod-completion/default.nix @@ -1,5 +1,11 @@ { empty = { plugins.vim-dadbod-completion.enable = true; + plugins.vim-dadbod-completion.cmp.enable = false; + }; + + with-cmp = { + plugins.cmp.enable = true; + plugins.vim-dadbod-completion.enable = true; }; } diff --git a/tests/test-sources/plugins/cmp/all-sources.nix b/tests/test-sources/plugins/cmp/all-sources.nix index 623ec1fbb6..84df542eab 100644 --- a/tests/test-sources/plugins/cmp/all-sources.nix +++ b/tests/test-sources/plugins/cmp/all-sources.nix @@ -1,43 +1,85 @@ -{ pkgs, ... }: { all-sources = - { config, ... }: { - plugins = { - copilot-lua = { - enable = true; + config, + options, + lib, + pkgs, + ... + }: + let + disabledSources = + [ + # We do not provide the required HF_API_KEY environment variable. + "cmp-ai" + # Triggers the warning complaining about treesitter highlighting being disabled + "otter" + # Invokes the `nix` command at startup which is not available in the sandbox + "cmp-nixpkgs-maintainers" + # lspkind has its own `cmp` options, but isn't a nvim-cmp source + "lspkind" + ] + # TODO: why is this disabled? + ++ lib.optionals (pkgs.stdenv.hostPlatform.system == "aarch64-linux") [ + "cmp-tabnine" + ]; + in + { + config = lib.mkMerge [ + { + plugins.cmp = { + enable = true; + }; + + plugins.copilot-lua = { + enable = true; - settings = { - panel.enabled = false; - suggestion.enabled = false; + settings = { + panel.enabled = false; + suggestion.enabled = false; + }; }; - }; + } + { + plugins = lib.pipe options.plugins [ + # First, a manual blacklist + (lib.flip builtins.removeAttrs disabledSources) + # Filter for non-options (all plugins are plain attrsets, not options) + # i.e. remove rename aliases + (lib.filterAttrs (name: opt: !lib.isOption opt)) + # Collect the plugin names + builtins.attrNames + # Filter for plugins that have a `cmp` option + (builtins.filter (name: config.plugins.${name} ? cmp)) + (lib.flip lib.genAttrs (name: { + enable = true; + cmp.enable = true; + })) + ]; + } + ]; + }; - cmp = { - enable = true; - settings.sources = - with pkgs.lib; - let - disabledSources = [ - # We do not provide the required HF_API_KEY environment variable. - "cmp_ai" - # Triggers the warning complaining about treesitter highlighting being disabled - "otter" - # Invokes the `nix` command at startup which is not available in the sandbox - "nixpkgs_maintainers" - ] ++ optional (pkgs.stdenv.hostPlatform.system == "aarch64-linux") "cmp_tabnine"; - in - pipe config.cmpSourcePlugins [ - # All known source names - attrNames - # Filter out disabled sources - (filter (name: !(elem name disabledSources))) - # Convert names to source attributes - (map (name: { - inherit name; - })) - ]; - }; + bad-source-defs = { + plugins = { + cmp = { + enable = true; + settings.sources = [ + { name = "emoji"; } + ]; }; + cmp-git.enable = true; + }; + test = { + buildNixvim = false; + warnings = expect: [ + (expect "count" 1) + (expect "any" "Nixvim (plugins.cmp-emoji): The \"emoji\" nvim-cmp source has been defined via `plugins.cmp`, howevew `plugins.cmp-emoji.enable` is not enabled.") + (expect "any" "1. Manually enable `plugins.cmp-emoji.enable`") + (expect "any" "2. Remove \"emoji\" from: plugins.cmp.settings.sources") + (expect "any" "3. Instead define: plugins.cmp-emoji.cmp.default = true;") + (expect "any" "You can suppress this warning by explicitly setting `plugins.cmp-emoji.enable = false`.") + ]; }; + }; } diff --git a/tests/test-sources/plugins/cmp/cmp-async-path.nix b/tests/test-sources/plugins/cmp/cmp-async-path.nix index 47ab6fc794..00104123bd 100644 --- a/tests/test-sources/plugins/cmp/cmp-async-path.nix +++ b/tests/test-sources/plugins/cmp/cmp-async-path.nix @@ -1,16 +1,16 @@ { example = { - plugins.cmp = { - enable = true; - settings.sources = [ - { - name = "async_path"; + plugins = { + cmp.enable = true; + cmp-async-path = { + enable = true; + cmp.default = { option = { - trailing_slash = false; label_trailing_slash = true; + trailing_slash = false; }; - } - ]; + }; + }; }; }; } diff --git a/tests/test-sources/plugins/cmp/default.nix b/tests/test-sources/plugins/cmp/default.nix index efc7424289..19c52d1e1d 100644 --- a/tests/test-sources/plugins/cmp/default.nix +++ b/tests/test-sources/plugins/cmp/default.nix @@ -161,15 +161,19 @@ { name = "neorg"; } ]; }; + + test.runNvim = false; + test.warnings = expect: [ + # Expect a warning for each source in the list, + # other than neorg for _some_ reason... + (expect "count" 4) + ]; }; list-of-lists-of-sources = { plugins.cmp = { enable = true; - # Here we are setting sources with raw lua. This cannot be parsed by Nixvim. - autoEnableSources = false; - settings.sources.__raw = '' cmp.config.sources({ { @@ -215,9 +219,6 @@ plugins.cmp = { enable = true; - # Here we are setting sources with raw lua. This cannot be parsed by Nixvim. - autoEnableSources = false; - settings = { mapping.__raw = '' cmp.mapping.preset.insert({