Skip to content

Commit 7e2ea60

Browse files
committed
lib/modules: init mkBlinkPluginModule & mkCmpPluginModule
1 parent a5147a3 commit 7e2ea60

File tree

4 files changed

+296
-3
lines changed

4 files changed

+296
-3
lines changed

lib/modules.nix

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ let
1414
applyExtraConfig = "It has been moved to `lib.plugins.utils`";
1515
mkConfigAt = "It has been moved to `lib.plugins.utils`";
1616
};
17+
internal = lib.mkOption { internal = true; };
1718
in
1819
{
1920
# Evaluate nixvim modules, checking warnings and assertions
@@ -52,6 +53,296 @@ in
5253
helpers = self;
5354
} // extraSpecialArgs;
5455
};
56+
57+
# Create a module configuring a plugin's integration with blink.cmp
58+
mkBlinkPluginModule =
59+
{
60+
# The plugin's option location-path
61+
loc ? [
62+
"plugins"
63+
pluginName
64+
],
65+
# Name of the plugin, used in documentation
66+
pluginName,
67+
# Name of the module blink should import
68+
# i.e. `sources.providers.<name>.module`
69+
module ? pluginName,
70+
# The default for `blink.settings.name`
71+
# i.e. `sources.providers.<name>.name`
72+
# TODO: consider doing some pre-processing to the default source name,
73+
# e.g. removing `-cmp` or `blink-` prefix/suffix?
74+
sourceName,
75+
# The default for `blink.key`
76+
# i.e. the attr name for `sources.providers.<name>`
77+
key ? lib.strings.toLower sourceName,
78+
# Whether to enable the blink completion provider by default
79+
enableProvider ? true,
80+
# Defaults for the corresponding source options
81+
enableDefault ? true,
82+
enableCmdline ? false,
83+
enabledFiletypes ? { },
84+
# Whether the plugin's settings should be used as the provider's `opts`
85+
usePluginSettings ? true,
86+
settingsExample ? {
87+
score_offset = -7;
88+
fallbacks = [ ];
89+
},
90+
}:
91+
{ config, options, ... }:
92+
let
93+
pluginCfg = lib.getAttrFromPath loc config;
94+
cfg = pluginCfg.blink;
95+
pluginOpts = lib.getAttrFromPath loc options;
96+
opt = pluginOpts.blink;
97+
in
98+
{
99+
options = lib.setAttrByPath loc {
100+
blink = {
101+
enable = lib.mkOption {
102+
type = lib.types.bool;
103+
default = enableProvider;
104+
example = !enableProvider;
105+
description = ''
106+
Whether to integrate this plugin with blink.cmp.
107+
'';
108+
};
109+
key = lib.mkOption {
110+
type = lib.types.str;
111+
default = key;
112+
description = ''
113+
The key to use for ${pluginName}'s blink.cmp provider.
114+
This is the id you should use when including this provider in completion source lists.
115+
Must be unique.
116+
'';
117+
};
118+
default = lib.mkOption {
119+
type = lib.types.bool;
120+
default = enableDefault;
121+
example = !enableDefault;
122+
description = ''
123+
Whether to include this plugin in the `default` completion source list.
124+
'';
125+
};
126+
cmdline = lib.mkOption {
127+
type = lib.types.bool;
128+
default = enableCmdline;
129+
example = !enableCmdline;
130+
description = ''
131+
Whether to include this plugin in the `cmdline` completion source list.
132+
'';
133+
};
134+
filetypes = lib.mkOption {
135+
type = lib.types.attrsOf lib.types.bool;
136+
# Only include `true` attrs in the final value
137+
apply = lib.filterAttrs (_: lib.id);
138+
default = enabledFiletypes;
139+
# TODO: example
140+
description = ''
141+
Whether to include this plugin in the specific `per_filetype` completion source lists.
142+
'';
143+
};
144+
settings = lib.mkOption {
145+
default = { };
146+
description = ''
147+
Settings for the blink.cmp completion provider.
148+
'';
149+
example = settingsExample;
150+
type = lib.types.submodule [
151+
{
152+
options.enabled = internal;
153+
options.module = internal;
154+
}
155+
../plugins/by-name/blink-cmp/provider-config.nix
156+
];
157+
};
158+
};
159+
};
160+
config = lib.mkMerge [
161+
(lib.setAttrByPath loc {
162+
# NOTE: this could be defined within the `blink.settings` submodule,
163+
# but that would not populate the option's `definitions` list.
164+
# Meaning we wouldn't be able to propagate the definitions further using `mkAliasDefinitions`.
165+
blink.settings = {
166+
name = lib.mkDefault sourceName;
167+
inherit module;
168+
opts = lib.mkIf usePluginSettings (lib.modules.mkAliasDefinitions pluginOpts.settings);
169+
};
170+
})
171+
(lib.mkIf (pluginCfg.enable && cfg.enable) {
172+
plugins.blink-cmp.settings.sources = {
173+
# Use mkAliasDefinitions to preserve override priorities
174+
providers.${cfg.key} = lib.modules.mkAliasDefinitions opt.settings;
175+
default = lib.mkIf cfg.default [ cfg.key ];
176+
# FIXME: the reference shows `cmdline` should/could be defined as a function
177+
# https://cmp.saghen.dev/configuration/reference.html#sources
178+
cmdline = lib.mkIf cfg.cmdline [ cfg.key ];
179+
per_filetype = lib.mkIf (cfg.filetypes != { }) (
180+
builtins.mapAttrs (_: _: [ cfg.key ]) cfg.filetypes
181+
);
182+
};
183+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
184+
when = !config.plugins.blink-cmp.enable && options.plugins.blink-cmp.enable.highestPrio == 1500;
185+
message = ''
186+
You have enabled the blink.cmp provider, but `plugins.blink-cmp` is not enabled.
187+
You can disable this warning by explicitly setting `plugins.blink-cmp.enable = false`.
188+
'';
189+
};
190+
})
191+
];
192+
};
193+
194+
# Create a module configuring a plugin's integration with nvim-cmp and blink.cmp
195+
mkCmpPluginModule =
196+
{
197+
# The plugin's option location-path
198+
loc ? [
199+
"plugins"
200+
pluginName
201+
],
202+
# Name of the plugin, used in documentation
203+
pluginName,
204+
# The nvim-cmp source name
205+
# TODO: can we compute a sane default for sourceName?
206+
sourceName,
207+
# Defaults for the corresponding cmp options
208+
enableDefault ? true,
209+
enableCmdline ? { },
210+
enabledFiletypes ? { },
211+
# Whether to include a `blink` option at all
212+
offerBlinkCompatibility ? true,
213+
# Defaults for the blink compatibility option
214+
enableBlinkProvider ? false,
215+
enableBlinkDefault ? false,
216+
enableBlinkCmdline ? false,
217+
enabledBlinkFiletypes ? { },
218+
# Whether the plugin's settings should be used as the blink provider's `opts`
219+
usePluginSettingsForBlink ? false,
220+
# The key to use with blink,
221+
# i.e. the attr name for `sources.providers.<name>`
222+
# TODO: should this default to pluginName or sourceName?
223+
blinkProviderKey ? lib.strings.toLower pluginName,
224+
}:
225+
{ config, options, ... }:
226+
let
227+
pluginOpt = lib.getAttrFromPath loc options;
228+
pluginCfg = lib.getAttrFromPath loc config;
229+
blinkOpt = pluginOpt.blink;
230+
blinkCfg = pluginCfg.blink;
231+
cfg = pluginCfg.cmp;
232+
toSourceDef = v: lib.optionalAttrs (builtins.isAttrs v) v // { inherit (cfg) name; };
233+
toSources = v: { sources = [ (toSourceDef v) ]; };
234+
in
235+
{
236+
imports = lib.optionals offerBlinkCompatibility [
237+
(lib.nixvim.modules.mkBlinkPluginModule {
238+
inherit loc pluginName sourceName;
239+
key = blinkProviderKey;
240+
module = "blink.compat.source";
241+
enableProvider = enableBlinkProvider;
242+
enableDefault = enableBlinkDefault;
243+
enableCmdline = enableBlinkCmdline;
244+
enabledFiletypes = enabledBlinkFiletypes;
245+
usePluginSettings = usePluginSettingsForBlink;
246+
})
247+
{
248+
options = lib.setAttrByPath loc {
249+
blink.settings.name = internal;
250+
};
251+
config = lib.mkIf (pluginCfg.enable && blinkCfg.enable) {
252+
# Enable blink-compat if the plugin has `blink.enable = true`
253+
plugins.blink-compat.enable = true;
254+
# This warning will show if someone overrides `plugins.blink-compat.enable = mkForce false`
255+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
256+
when = !config.plugins.blink-compat.enable;
257+
message = ''
258+
`${blinkOpt.enable}` is enabled, but `${options.plugins.blink-compat.enable}` is not.
259+
This plugin is a nvim-cmp source, so it requires blink.compat when used with blink.cmp.
260+
'';
261+
};
262+
};
263+
}
264+
];
265+
options = lib.setAttrByPath loc {
266+
cmp = {
267+
enable = lib.mkOption {
268+
type = lib.types.bool;
269+
# FIXME: this should default to true, but it is incompatible with autoEnableCmpSources
270+
default = false;
271+
example = true;
272+
description = ''
273+
Whether to integrate this plugin with nvim-cmp.
274+
'';
275+
};
276+
name = lib.mkOption {
277+
type = lib.types.str;
278+
default = sourceName;
279+
description = "${pluginName}'s nvim-cmp source name.";
280+
internal = true;
281+
};
282+
default = lib.mkOption {
283+
type = with lib.types; either bool (attrsOf anything);
284+
default = enableDefault;
285+
example = !enableDefault;
286+
description = ''
287+
Whether to include this plugin in the `default` completion source list.
288+
289+
Can be defined as attrs to pass additional config to the source.
290+
'';
291+
};
292+
cmdline = lib.mkOption {
293+
type = with lib.types; attrsOf (either bool (attrsOf anything));
294+
# Remove false attrs in the final value
295+
apply = lib.filterAttrs (_: v: v != false);
296+
default = enableCmdline;
297+
# TODO: example
298+
description = ''
299+
Whether to include this plugin in the specific `cmdline` completion source lists.
300+
301+
Elements can be defined as attrs to pass additional config to the source.
302+
'';
303+
};
304+
filetypes = lib.mkOption {
305+
type = with lib.types; attrsOf (either bool (attrsOf anything));
306+
# Remove false attrs in the final value
307+
apply = lib.filterAttrs (_: v: v != false);
308+
default = enabledFiletypes;
309+
# TODO: example
310+
description = ''
311+
Whether to include this plugin in the specific `per_filetype` completion source lists.
312+
313+
Elements can be defined as attrs to pass additional config to the source.
314+
'';
315+
};
316+
};
317+
};
318+
config = lib.mkMerge [
319+
{
320+
# Backwards compatibility with autoEnableCmpSources
321+
cmpSourcePlugins.${sourceName} =
322+
assert lib.assertMsg (builtins.length loc == 2 && builtins.head loc == "plugins")
323+
"autoEnableCmpSources assumes all cmp source plugins are in the `plugins` namespace. Unsupported plugin `${lib.showOption loc}`.";
324+
pluginName;
325+
}
326+
(lib.mkIf (pluginCfg.enable && cfg.enable) {
327+
# FIXME: even though we have the mkIf, we also need optionalAttrs
328+
# to avoid inf-recursion caused by `autoEnableSources`
329+
plugins.cmp = lib.optionalAttrs cfg.enable {
330+
# TODO: consider setting:
331+
# autoEnableSources = lib.mkDefault false;
332+
settings = lib.mkIf (cfg.default != false) (toSources cfg.default);
333+
cmdline = lib.mkIf (cfg.cmdline != { }) (builtins.mapAttrs (_: toSources) cfg.cmdline);
334+
filetype = lib.mkIf (cfg.filetypes != { }) (builtins.mapAttrs (_: toSources) cfg.filetypes);
335+
};
336+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
337+
when = !config.plugins.cmp.enable && options.plugins.cmp.enable.highestPrio == 1500;
338+
message = ''
339+
You have enabled the nvim-cmp source, but `plugins.cmp` is not enabled.
340+
You can disable this warning by explicitly setting `plugins.cmp.enable = false`.
341+
'';
342+
};
343+
})
344+
];
345+
};
55346
}
56347
// lib.mapAttrs (
57348
name: msg:

plugins/by-name/blink-cmp/default.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ lib.nixvim.plugins.mkNeovimPlugin {
1414

1515
description = ''
1616
Performant, batteries-included completion plugin for Neovim.
17+
18+
<!-- TODO: mention `plugins.*.blink` options -->
1719
'';
1820

1921
settingsOptions = import ./settings-options.nix lib;

plugins/by-name/blink-cmp/provider-config.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
lib:
1+
{ lib, ... }:
22
let
33
inherit (lib) types;
44
inherit (lib.nixvim) defaultNullOpts;
55
in
6-
types.submodule {
6+
{
77
freeformType = with types; attrsOf anything;
88
options = {
99
name = defaultNullOpts.mkStr' {

plugins/by-name/blink-cmp/settings-options.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ in
525525
'';
526526

527527
providers = mkNullOrOption' {
528-
type = with types; attrsOf (import ./provider-config.nix lib);
528+
type = with types; attrsOf (submodule ./provider-config.nix);
529529
description = ''
530530
Definition of completion providers.
531531
'';

0 commit comments

Comments
 (0)