plugins/cmp: refactor source->plugin association

Introduce the internal option `cmpSourcePlugins` where plugins can
register their nvim-cmp source name association.
This commit is contained in:
Matt Sturgeon 2024-06-29 08:26:56 +01:00
parent bd422db9ba
commit 3a8d4fee35
No known key found for this signature in database
GPG key ID: 4F91844CED1A8299
6 changed files with 137 additions and 100 deletions

View file

@ -0,0 +1,90 @@
{
lib,
helpers,
config,
...
}:
with lib;
let
cfg = config.plugins.cmp;
extractSources = { sources, ... }: if isList sources then sources else [ ];
# Collect the names of the sources provided by the user
# ["foo" "bar"]
enabledSources =
pipe
[
# cfg.setup.sources
(extractSources cfg.settings)
# cfg.filetype.<name>.sources
(mapAttrsToList (_: extractSources) cfg.filetype)
# cfg.cmdline.<name>.sources
(mapAttrsToList (_: extractSources) cfg.cmdline)
]
[
flatten
(map (getAttr "name"))
unique
];
in
{
options = {
# Note: this option must be outside of `plugins` to avoid infinite recursion
cmpSourcePlugins = mkOption {
type = with types; attrsOf str;
default = { };
description = ''
Internal option used to associate nvim-cmp source names with nixvim plugin module names.
Maps `<source-name> = <plugin-name>` where _plugin-name_ is the module name: `plugins.<plugin-name>.enable`.
'';
example = {
foo = "cmp-foo";
bar = "cmp-bar";
};
internal = true;
visible = false;
};
plugins.cmp.autoEnableSources = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Scans the sources array and enable the corresponding plugins if they are known to nixvim.
'';
};
};
config = mkIf (cfg.enable && cfg.autoEnableSources) (mkMerge [
{
warnings =
# TODO: expand this warning to ft & cmd sources lists and `showDefs` the offending definitions
optional (helpers.nixvimTypes.isRawType cfg.settings.sources) ''
Nixvim (plugins.cmp): 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`;
'';
# If the user has enabled the `foo` and `bar` sources, then `plugins` will look like:
# {
# cmp-foo.enable = true;
# cmp-bar.enable = true;
# }
plugins = mapAttrs' (source: name: {
inherit name;
value.enable = mkIf (elem source enabledSources) true;
}) config.cmpSourcePlugins;
}
{
plugins.lsp.capabilities = mkIf (elem "nvim_lsp" enabledSources) ''
capabilities = vim.tbl_deep_extend("force", capabilities, require('cmp_nvim_lsp').default_capabilities())
'';
}
]);
}

View file

@ -7,10 +7,11 @@
}: }:
with helpers.vim-plugin; with helpers.vim-plugin;
with lib; with lib;
rec { {
mkCmpSourcePlugin = mkCmpSourcePlugin =
{ {
name, name,
sourceName,
extraPlugins ? [ ], extraPlugins ? [ ],
useDefaultPackage ? true, useDefaultPackage ? true,
... ...
@ -20,49 +21,8 @@ rec {
extraPlugins = extraPlugins ++ (lists.optional useDefaultPackage pkgs.vimPlugins.${name}); extraPlugins = extraPlugins ++ (lists.optional useDefaultPackage pkgs.vimPlugins.${name});
maintainers = [ maintainers.GaetanLepage ]; maintainers = [ maintainers.GaetanLepage ];
# Register the source -> plugin name association
imports = [ { cmpSourcePlugins.${sourceName} = name; } ];
}; };
extractSourcesFromOptionValue = sources: if isList sources then sources else [ ];
autoInstallSourcePluginsModule =
cfg:
let
# cfg.setup.sources
setupSources = extractSourcesFromOptionValue cfg.settings.sources;
# cfg.filetype.<name>.sources
filetypeSources = mapAttrsToList (
_: filetypeConfig: extractSourcesFromOptionValue filetypeConfig.sources
) cfg.filetype;
# cfg.cmdline.<name>.sources
cmdlineSources = mapAttrsToList (
_: cmdlineConfig: extractSourcesFromOptionValue cmdlineConfig.sources
) cfg.cmdline;
# [{name = "foo";} {name = "bar"; x = 42;} ...]
allSources = flatten (setupSources ++ filetypeSources ++ cmdlineSources);
# Take only the names from the sources provided by the user
# ["foo" "bar"]
foundSources = lists.unique (map (source: source.name) allSources);
# If the user has enabled the `foo` and `bar` sources, this attrs will look like:
# {
# cmp-foo.enable = true;
# cmp-bar.enable = true;
# }
attrsEnabled = mapAttrs' (sourceName: pluginName: {
name = pluginName;
value.enable = mkIf (elem sourceName foundSources) true;
}) (import ./sources.nix);
lspCapabilities = mkIf (elem "nvim_lsp" foundSources) {
lsp.capabilities = ''
capabilities = vim.tbl_deep_extend("force", capabilities, require('cmp_nvim_lsp').default_capabilities())
'';
};
in
mkMerge [
(mkIf cfg.autoEnableSources attrsEnabled)
lspCapabilities
];
} }

View file

@ -16,42 +16,22 @@ helpers.neovim-plugin.mkNeovimPlugin config {
maintainers = [ maintainers.GaetanLepage ]; maintainers = [ maintainers.GaetanLepage ];
imports = [
# Introduced on 2024 February 21 # Introduced on 2024 February 21
# TODO: remove ~June 2024 # TODO: remove ~June 2024
imports = [
./deprecations.nix ./deprecations.nix
./auto-enable.nix
./sources ./sources
]; ];
deprecateExtraOptions = true; deprecateExtraOptions = true;
inherit (cmpOptions) settingsOptions settingsExample;
extraOptions = { extraOptions = {
autoEnableSources = mkOption {
type = types.bool;
default = true;
description = ''
Scans the sources array and installs the plugins if they are known to nixvim.
'';
};
inherit (cmpOptions) filetype cmdline; inherit (cmpOptions) filetype cmdline;
}; };
inherit (cmpOptions) settingsOptions settingsExample;
callSetup = false; callSetup = false;
extraConfig = cfg: { extraConfig = cfg: {
warnings =
optional (cfg.autoEnableSources && (helpers.nixvimTypes.isRawType cfg.settings.sources))
''
Nixvim (plugins.cmp): 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`;
'';
extraConfigLua = extraConfigLua =
'' ''
local cmp = require('cmp') local cmp = require('cmp')
@ -68,9 +48,5 @@ helpers.neovim-plugin.mkNeovimPlugin config {
cmdtype: settings: "cmp.setup.cmdline('${cmdtype}', ${helpers.toLuaObject settings})\n" cmdtype: settings: "cmp.setup.cmdline('${cmdtype}', ${helpers.toLuaObject settings})\n"
) cfg.cmdline ) cfg.cmdline
)); ));
# If autoEnableSources is set to true, figure out which are provided by the user
# and enable the corresponding plugins.
plugins = (import ./cmp-helpers.nix args).autoInstallSourcePluginsModule cfg;
}; };
} }

View file

@ -15,8 +15,11 @@ let
pkgs pkgs
; ;
}; };
cmpSourcesPluginNames = attrValues (import ../sources.nix);
pluginModules = map (name: cmpLib.mkCmpSourcePlugin { inherit name; }) cmpSourcesPluginNames; cmpSourcesPluginNames = import ../sources.nix;
pluginModules = mapAttrsToList (
sourceName: name: cmpLib.mkCmpSourcePlugin { inherit sourceName name; }
) cmpSourcesPluginNames;
in in
{ {
# For extra cmp plugins # For extra cmp plugins

View file

@ -57,7 +57,6 @@ let
inherit pkgs lib helpers; inherit pkgs lib helpers;
config = { }; config = { };
}; };
cmp-sources = import ../plugins/completion/cmp/sources.nix;
}; };
inherit namespace; inherit namespace;
} }

View file

@ -1,6 +1,9 @@
{ pkgs, cmp-sources, ... }: { pkgs, ... }:
{ {
all-sources = { all-sources = {
module =
{ config, ... }:
{
plugins = { plugins = {
copilot-lua = { copilot-lua = {
enable = true; enable = true;
@ -18,12 +21,18 @@
# We do not provide the required HF_API_KEY environment variable. # We do not provide the required HF_API_KEY environment variable.
"cmp_ai" "cmp_ai"
] ++ optional (pkgs.stdenv.hostPlatform.system == "aarch64-linux") "cmp_tabnine"; ] ++ optional (pkgs.stdenv.hostPlatform.system == "aarch64-linux") "cmp_tabnine";
filterFunc = sourceName: !(elem sourceName disabledSources);
sourceNames = filter filterFunc (attrNames cmp-sources);
in in
map (sourceName: { name = sourceName; }) sourceNames; 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;
}))
];
};
}; };
}; };
}; };