Skip to content

Commit 8ecaeaa

Browse files
committed
lib/modules: init mkBlinkPluginModule & mkCmpPluginModule
1 parent 2ecc535 commit 8ecaeaa

File tree

4 files changed

+290
-2
lines changed

4 files changed

+290
-2
lines changed

lib/modules.nix

Lines changed: 286 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,291 @@ 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+
};
193+
};
194+
195+
# Create a module configuring a plugin's integration with nvim-cmp and blink.cmp
196+
mkCmpPluginModule =
197+
{
198+
# The plugin's option location-path
199+
loc ? [
200+
"plugins"
201+
pluginName
202+
],
203+
# Name of the plugin, used in documentation
204+
pluginName,
205+
# The nvim-cmp source name
206+
# TODO: can we compute a sane default for sourceName?
207+
sourceName,
208+
# Defaults for the corresponding cmp options
209+
enableDefault ? true,
210+
enableCmdline ? false,
211+
enabledFiletypes ? { },
212+
# Whether to include a `blink` option at all
213+
offerBlinkCompatibility ? true,
214+
# Defaults for the blink compatibility option
215+
enableBlinkProvider ? false,
216+
enableBlinkDefault ? false,
217+
enableBlinkCmdline ? false,
218+
enabledBlinkFiletypes ? { },
219+
# Whether the plugin's settings should be used as the blink provider's `opts`
220+
usePluginSettingsForBlink ? false,
221+
# The key to use with blink,
222+
# i.e. the attr name for `sources.providers.<name>`
223+
# TODO: should this default to pluginName or sourceName?
224+
blinkProviderKey ? lib.strings.toLower pluginName,
225+
}:
226+
{ config, options, ... }:
227+
let
228+
pluginOpt = lib.getAttrFromPath loc options;
229+
pluginCfg = lib.getAttrFromPath loc config;
230+
blinkOpt = pluginOpt.blink.type.getSubOptions pluginOpt.blink.loc;
231+
blinkCfg = pluginCfg.blink;
232+
cfg = pluginCfg.cmp;
233+
toSourceDef = v: lib.optionalAttrs (builtins.isAttrs v) v // { inherit (cfg) name; };
234+
toSources = v: { sources = [ (toSourceDef v) ]; };
235+
in
236+
{
237+
imports = lib.optionals offerBlinkCompatibility [
238+
(lib.nixvim.modules.mkBlinkPluginModule {
239+
inherit loc pluginName sourceName;
240+
key = blinkProviderKey;
241+
module = "blink.compat.source";
242+
enableProvider = enableBlinkProvider;
243+
enableDefault = enableBlinkDefault;
244+
enableCmdline = enableBlinkCmdline;
245+
enabledFiletypes = enabledBlinkFiletypes;
246+
usePluginSettings = usePluginSettingsForBlink;
247+
})
248+
{
249+
options = lib.setAttrByPath loc {
250+
blink.settings.name = internal;
251+
};
252+
config = lib.mkIf (pluginCfg.enable && blinkCfg.enable) {
253+
# Enable blink-compat if the plugin has `blink.enable = true`
254+
plugins.blink-compat.enable = true;
255+
# This warning will show if someone overrides `plugins.blink-compat.enable = mkForce false`
256+
warnings = lib.nixvim.mkWarnings (lib.showOption loc) {
257+
when = !config.plugins.blink-compat.enable;
258+
message = ''
259+
`${blinkOpt.enable}` is enabled, but `${options.plugins.blink-compat.enable}` is not.
260+
This plugin is a nvim-cmp source, so it requires blink.compat when used with blink.cmp.
261+
'';
262+
};
263+
};
264+
}
265+
];
266+
options = lib.setAttrByPath loc {
267+
cmp = lib.mkOption {
268+
# TODO: this option will replace the current autoEnableCmpSources system
269+
type = lib.types.submodule {
270+
options = {
271+
enable = lib.mkOption {
272+
type = lib.types.bool;
273+
# FIXME: this should default to true, but it is incompatible with autoEnableCmpSources
274+
default = false;
275+
example = true;
276+
description = ''
277+
Whether to integrate this plugin with nvim-cmp.
278+
'';
279+
};
280+
name = lib.mkOption {
281+
type = lib.types.str;
282+
default = sourceName;
283+
description = "${pluginName}'s nvim-cmp source name.";
284+
internal = true;
285+
};
286+
default = lib.mkOption {
287+
type = with lib.types; either bool (attrsOf anything);
288+
default = enableDefault;
289+
example = !enableDefault;
290+
description = ''
291+
Whether to include this plugin in the `default` completion source list.
292+
293+
Can be defined as attrs to pass additional config to the source.
294+
'';
295+
};
296+
cmdline = lib.mkOption {
297+
type = with lib.types; attrsOf (either bool (attrsOf anything));
298+
# Remove false attrs in the final value
299+
apply = lib.filterAttrs (_: v: v != false);
300+
default = enableCmdline;
301+
example = !enableCmdline;
302+
description = ''
303+
Whether to include this plugin in the specific `cmdline` completion source lists.
304+
305+
Elements can be defined as attrs to pass additional config to the source.
306+
'';
307+
};
308+
filetypes = 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 = enabledFiletypes;
313+
# TODO: example
314+
description = ''
315+
Whether to include this plugin in the specific `per_filetype` completion source lists.
316+
317+
Elements can be defined as attrs to pass additional config to the source.
318+
'';
319+
};
320+
};
321+
};
322+
};
323+
};
324+
config = lib.mkMerge [
325+
{
326+
# Backwards compatibility with autoEnableCmpSources
327+
cmpSourcePlugins.${sourceName} =
328+
assert lib.assertMsg (builtins.length loc == 2 && builtins.head loc == "plugins")
329+
"autoEnableCmpSources assumes all cmp source plugins are in the `plugins` namespace. Unsupported plugin `${lib.showOption loc}`.";
330+
lib.last loc;
331+
}
332+
(lib.mkIf (pluginCfg.enable && cfg.enable) {
333+
plugins.cmp = {
334+
settings = lib.mkIf (cfg.default != false) (toSources cfg.default);
335+
cmdline = lib.mkIf (cfg.cmdline != { }) (builtins.mapAttrs (_: toSources) cfg.cmdline);
336+
filetype = lib.mkIf (cfg.filetypes != { }) (builtins.mapAttrs (_: toSources) cfg.filetypes);
337+
};
338+
})
339+
];
340+
};
55341
}
56342
// lib.mapAttrs (
57343
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)