Skip to content

Commit 4f8b10b

Browse files
committed
lib/modules: init mkBlinkPluginModule & mkCmpPluginModule
1 parent 5024ef2 commit 4f8b10b

File tree

4 files changed

+313
-2
lines changed

4 files changed

+313
-2
lines changed

lib/modules.nix

Lines changed: 309 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,314 @@ 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+
opts = opt.type.getSubOptions opt.loc;
98+
in
99+
{
100+
options = lib.setAttrByPath loc {
101+
blink = lib.mkOption {
102+
description = "Configure blink.cmp options for ${pluginName}.";
103+
default = { };
104+
example = {
105+
enable = false;
106+
cmdline = true;
107+
};
108+
type = lib.types.submodule {
109+
options = {
110+
enable = lib.mkOption {
111+
type = lib.types.bool;
112+
default = enableProvider;
113+
example = !enableProvider;
114+
description = ''
115+
Whether to integrate this plugin with blink.cmp.
116+
'';
117+
};
118+
key = lib.mkOption {
119+
type = lib.types.str;
120+
default = key;
121+
description = ''
122+
The key to use for ${pluginName}'s blink.cmp provider.
123+
This is the id you should use when including this provider in completion source lists.
124+
Must be unique.
125+
'';
126+
};
127+
default = lib.mkOption {
128+
type = lib.types.bool;
129+
default = enableDefault;
130+
example = !enableDefault;
131+
description = ''
132+
Whether to include this plugin in the `default` completion source list.
133+
'';
134+
};
135+
cmdline = lib.mkOption {
136+
type = lib.types.bool;
137+
default = enableCmdline;
138+
example = !enableCmdline;
139+
description = ''
140+
Whether to include this plugin in the `cmdline` completion source list.
141+
'';
142+
};
143+
filetypes = lib.mkOption {
144+
type = lib.types.attrsOf lib.types.bool;
145+
# Only include `true` attrs in the final value
146+
apply = lib.filterAttrs (_: lib.id);
147+
default = enabledFiletypes;
148+
# TODO: example
149+
description = ''
150+
Whether to include this plugin in the specific `per_filetype` completion source lists.
151+
'';
152+
};
153+
settings = lib.mkOption {
154+
default = { };
155+
description = ''
156+
Settings for the blink.cmp completion provider.
157+
'';
158+
example = settingsExample;
159+
type = lib.types.submodule [
160+
{
161+
options = {
162+
enabled = internal;
163+
module = internal;
164+
};
165+
config = {
166+
name = lib.mkDefault sourceName;
167+
inherit module;
168+
# One-way alias for `plugin.*.settings` -> `plugin.*.blink.settings.opts`
169+
# Use mkAliasDefinitions to preserve override priorities
170+
opts = lib.mkIf usePluginSettings (lib.modules.mkAliasDefinitions pluginOpts.settings);
171+
};
172+
}
173+
(import ../plugins/by-name/blink-cmp/provider-config.nix lib)
174+
];
175+
};
176+
};
177+
};
178+
};
179+
};
180+
config = lib.mkIf (pluginCfg.enable && cfg.enable) {
181+
plugins.blink-cmp.settings.sources = {
182+
# Use mkAliasDefinitions to preserve override priorities
183+
providers.${cfg.key} = lib.modules.mkAliasDefinitions opts.settings;
184+
default = lib.mkIf cfg.default [ cfg.key ];
185+
# FIXME: the reference shows `cmdline` should/could be defined as a function
186+
# https://cmp.saghen.dev/configuration/reference.html#sources
187+
cmdline = lib.mkIf cfg.cmdline [ cfg.key ];
188+
per_filetype = lib.mkIf (cfg.filetypes != { }) (
189+
builtins.mapAttrs (_: _: [ cfg.key ]) cfg.filetypes
190+
);
191+
};
192+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
193+
when = !config.plugins.blink-cmp.enable && options.plugins.blink-cmp.enable.highestPrio == 1500;
194+
message = ''
195+
You have enabled the blink.cmp provider, but `plugins.blink-cmp` is not enabled.
196+
You can disable this warning by explicitly setting `plugins.blink-cmp.enable = false`.
197+
'';
198+
};
199+
};
200+
};
201+
202+
# Create a module configuring a plugin's integration with nvim-cmp and blink.cmp
203+
mkCmpPluginModule =
204+
{
205+
# The plugin's option location-path
206+
loc ? [
207+
"plugins"
208+
pluginName
209+
],
210+
# Name of the plugin, used in documentation
211+
pluginName,
212+
# The nvim-cmp source name
213+
# TODO: can we compute a sane default for sourceName?
214+
sourceName,
215+
# Defaults for the corresponding cmp options
216+
enableDefault ? true,
217+
enableCmdline ? { },
218+
enabledFiletypes ? { },
219+
# Whether to include a `blink` option at all
220+
offerBlinkCompatibility ? true,
221+
# Defaults for the blink compatibility option
222+
enableBlinkProvider ? false,
223+
enableBlinkDefault ? false,
224+
enableBlinkCmdline ? false,
225+
enabledBlinkFiletypes ? { },
226+
# Whether the plugin's settings should be used as the blink provider's `opts`
227+
usePluginSettingsForBlink ? false,
228+
# The key to use with blink,
229+
# i.e. the attr name for `sources.providers.<name>`
230+
# TODO: should this default to pluginName or sourceName?
231+
blinkProviderKey ? lib.strings.toLower pluginName,
232+
}:
233+
{ config, options, ... }:
234+
let
235+
pluginOpt = lib.getAttrFromPath loc options;
236+
pluginCfg = lib.getAttrFromPath loc config;
237+
blinkOpt = pluginOpt.blink.type.getSubOptions pluginOpt.blink.loc;
238+
blinkCfg = pluginCfg.blink;
239+
cfg = pluginCfg.cmp;
240+
toSourceDef = v: lib.optionalAttrs (builtins.isAttrs v) v // { inherit (cfg) name; };
241+
toSources = v: { sources = [ (toSourceDef v) ]; };
242+
in
243+
{
244+
imports = lib.optionals offerBlinkCompatibility [
245+
(lib.nixvim.modules.mkBlinkPluginModule {
246+
inherit loc pluginName sourceName;
247+
key = blinkProviderKey;
248+
module = "blink.compat.source";
249+
enableProvider = enableBlinkProvider;
250+
enableDefault = enableBlinkDefault;
251+
enableCmdline = enableBlinkCmdline;
252+
enabledFiletypes = enabledBlinkFiletypes;
253+
usePluginSettings = usePluginSettingsForBlink;
254+
})
255+
{
256+
options = lib.setAttrByPath loc {
257+
blink.settings.name = internal;
258+
};
259+
config = lib.mkIf (pluginCfg.enable && blinkCfg.enable) {
260+
# Enable blink-compat if the plugin has `blink.enable = true`
261+
plugins.blink-compat.enable = true;
262+
# This warning will show if someone overrides `plugins.blink-compat.enable = mkForce false`
263+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
264+
when = !config.plugins.blink-compat.enable;
265+
message = ''
266+
`${blinkOpt.enable}` is enabled, but `${options.plugins.blink-compat.enable}` is not.
267+
This plugin is a nvim-cmp source, so it requires blink.compat when used with blink.cmp.
268+
'';
269+
};
270+
};
271+
}
272+
];
273+
options = lib.setAttrByPath loc {
274+
cmp = lib.mkOption {
275+
description = "Configure nvim-cmp options for ${pluginName}.";
276+
default = { };
277+
example = {
278+
enable = false;
279+
cmdline.":" = true;
280+
};
281+
type = lib.types.submodule {
282+
options = {
283+
enable = lib.mkOption {
284+
type = lib.types.bool;
285+
# FIXME: this should default to true, but it is incompatible with autoEnableCmpSources
286+
default = false;
287+
example = true;
288+
description = ''
289+
Whether to integrate this plugin with nvim-cmp.
290+
'';
291+
};
292+
name = lib.mkOption {
293+
type = lib.types.str;
294+
default = sourceName;
295+
description = "${pluginName}'s nvim-cmp source name.";
296+
internal = true;
297+
};
298+
default = lib.mkOption {
299+
type = with lib.types; either bool (attrsOf anything);
300+
default = enableDefault;
301+
example = !enableDefault;
302+
description = ''
303+
Whether to include this plugin in the `default` completion source list.
304+
305+
Can be defined as attrs to pass additional config to the source.
306+
'';
307+
};
308+
cmdline = lib.mkOption {
309+
type = with lib.types; attrsOf (either bool (attrsOf anything));
310+
# Remove false attrs in the final value
311+
apply = lib.filterAttrs (_: v: v != false);
312+
default = enableCmdline;
313+
# TODO: example
314+
description = ''
315+
Whether to include this plugin in the specific `cmdline` completion source lists.
316+
317+
Elements can be defined as attrs to pass additional config to the source.
318+
'';
319+
};
320+
filetypes = lib.mkOption {
321+
type = with lib.types; attrsOf (either bool (attrsOf anything));
322+
# Remove false attrs in the final value
323+
apply = lib.filterAttrs (_: v: v != false);
324+
default = enabledFiletypes;
325+
# TODO: example
326+
description = ''
327+
Whether to include this plugin in the specific `per_filetype` completion source lists.
328+
329+
Elements can be defined as attrs to pass additional config to the source.
330+
'';
331+
};
332+
};
333+
};
334+
};
335+
};
336+
config = lib.mkMerge [
337+
{
338+
# Backwards compatibility with autoEnableCmpSources
339+
cmpSourcePlugins.${sourceName} =
340+
assert lib.assertMsg (builtins.length loc == 2 && builtins.head loc == "plugins")
341+
"autoEnableCmpSources assumes all cmp source plugins are in the `plugins` namespace. Unsupported plugin `${lib.showOption loc}`.";
342+
pluginName;
343+
}
344+
(lib.mkIf (pluginCfg.enable && cfg.enable) {
345+
# FIXME: even though we have the mkIf, we also need optionalAttrs
346+
# to avoid inf-recursion caused by `autoEnableSources`
347+
plugins.cmp = lib.optionalAttrs cfg.enable {
348+
# TODO: consider setting:
349+
# autoEnableSources = lib.mkDefault false;
350+
settings = lib.mkIf (cfg.default != false) (toSources cfg.default);
351+
cmdline = lib.mkIf (cfg.cmdline != { }) (builtins.mapAttrs (_: toSources) cfg.cmdline);
352+
filetype = lib.mkIf (cfg.filetypes != { }) (builtins.mapAttrs (_: toSources) cfg.filetypes);
353+
};
354+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
355+
when = !config.plugins.cmp.enable && options.plugins.cmp.enable.highestPrio == 1500;
356+
message = ''
357+
You have enabled the nvim-cmp source, but `plugins.cmp` is not enabled.
358+
You can disable this warning by explicitly setting `plugins.cmp.enable = false`.
359+
'';
360+
};
361+
})
362+
];
363+
};
55364
}
56365
// lib.mapAttrs (
57366
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ 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 (import ./provider-config.nix lib));
529529
description = ''
530530
Definition of completion providers.
531531
'';

0 commit comments

Comments
 (0)