mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-23 09:18:38 +02:00
This represents a major rearchitecture for nixvim, so I'm leaving this up to track the progress for now, and to serve as a reference for any breaking changes during transition. The main change is, of course, being able to use nixvim standalone. To do this, you should use the new build function, which takes in two arguments: the system architecture (e.g. x86_64-linux) and the configuration. For the new configuration, do not use the programs.nixvim. prefix. For module development, the main change is that you should no longer prefix your modules with programs.nixvim..
421 lines
13 KiB
Nix
421 lines
13 KiB
Nix
{ pkgs, config, lib, ... }@args:
|
|
with lib;
|
|
let
|
|
cfg = config.plugins.nvim-cmp;
|
|
helpers = import ../../helpers.nix { lib = lib; };
|
|
mkNullOrOption = helpers.mkNullOrOption;
|
|
cmpLib = import ./cmp-helpers.nix args;
|
|
# functionName should be a string
|
|
# parameters should be a list of strings
|
|
wrapWithFunction = functionName: parameters:
|
|
let
|
|
parameterString = strings.concatStringsSep "," parameters;
|
|
in
|
|
''${functionName}(${parameterString})'';
|
|
in
|
|
{
|
|
options.plugins.nvim-cmp = {
|
|
enable = mkEnableOption "Enable nvim-cmp";
|
|
|
|
performance = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
debounce = mkOption {
|
|
type = types.nullOr types.int;
|
|
default = null;
|
|
};
|
|
throttle = mkOption {
|
|
type = types.nullOr types.int;
|
|
default = null;
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
preselect = mkOption {
|
|
type = types.nullOr (types.enum [ "Item" "None" ]);
|
|
default = null;
|
|
example = ''"Item"'';
|
|
};
|
|
|
|
snippet = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
expand = mkOption {
|
|
type = types.nullOr types.str;
|
|
example = ''
|
|
function(args)
|
|
vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
|
|
-- require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
|
|
-- require('snippy').expand_snippet(args.body) -- For `snippy` users.
|
|
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
|
|
end
|
|
'';
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
mappingPresets = mkOption {
|
|
default = [ ];
|
|
type = types.listOf (types.enum [
|
|
"insert"
|
|
"cmdline"
|
|
# Not sure if there are more or if this should just be str
|
|
]);
|
|
description = "Mapping presets to use; cmp.mapping.preset.\${mappingPreset} will be called with the configured mappings";
|
|
example = ''
|
|
[ "insert" "cmdline" ]
|
|
'';
|
|
};
|
|
|
|
mapping = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.attrsOf (types.either types.str (types.submodule ({ ... }: {
|
|
options = {
|
|
action = mkOption {
|
|
type = types.nonEmptyStr;
|
|
description = "The function the mapping should call";
|
|
example = ''"cmp.mapping.scroll_docs(-4)"'';
|
|
};
|
|
modes = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.listOf types.str);
|
|
example = ''[ "i" "s" ]'';
|
|
};
|
|
};
|
|
}))));
|
|
example = ''
|
|
{
|
|
"<CR>" = "cmp.mapping.confirm({ select = true })";
|
|
"<Tab>" = {
|
|
modes = [ "i" "s" ];
|
|
action = '${""}'
|
|
function(fallback)
|
|
if cmp.visible() then
|
|
cmp.select_next_item()
|
|
elseif luasnip.expandable() then
|
|
luasnip.expand()
|
|
elseif luasnip.expand_or_jumpable() then
|
|
luasnip.expand_or_jump()
|
|
elseif check_backspace() then
|
|
fallback()
|
|
else
|
|
fallback()
|
|
end
|
|
end
|
|
'${""}';
|
|
};
|
|
}
|
|
'';
|
|
};
|
|
|
|
completion = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
keyword_length = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
|
|
keyword_pattern = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
};
|
|
|
|
autocomplete = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
description = "Lua code for the event.";
|
|
example = ''"false"'';
|
|
};
|
|
|
|
completeopt = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
confirmation = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
get_commit_characters = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
description = "Direct lua code as a string";
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
formatting = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
fields = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.listOf types.str);
|
|
example = ''[ "kind" "abbr" "menu" ]'';
|
|
};
|
|
format = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
description = "A lua function as a string";
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
matching = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
disallow_fuzzy_matching = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.bool;
|
|
};
|
|
disallow_partial_matching = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.bool;
|
|
};
|
|
disallow_prefix_unmatching = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.bool;
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
sorting = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
priority_weight = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
comparators = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
auto_enable_sources = mkOption {
|
|
default = true;
|
|
description = ''
|
|
Scans the sources array and installs the plugins if they are known to nixvim.
|
|
'';
|
|
};
|
|
|
|
sources =
|
|
let
|
|
source_config = types.submodule ({ ... }: {
|
|
options = {
|
|
name = mkOption {
|
|
type = types.str;
|
|
description = "The name of the source.";
|
|
example = ''"buffer"'';
|
|
};
|
|
|
|
option = mkOption {
|
|
default = null;
|
|
type = with types; nullOr (attrsOf anything);
|
|
description = "If direct lua code is needed use helpers.mkRaw";
|
|
};
|
|
|
|
keyword_length = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
|
|
keyword_pattern = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
|
|
trigger_characters = mkOption {
|
|
default = null;
|
|
type = with types; nullOr (listOf str);
|
|
};
|
|
|
|
priority = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
|
|
max_item_count = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
|
|
group_index = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.int;
|
|
};
|
|
};
|
|
});
|
|
in
|
|
mkOption {
|
|
default = null;
|
|
type = with types; nullOr (either (listOf source_config) (listOf (listOf source_config)));
|
|
description = ''
|
|
The sources to use.
|
|
Can either be a list of sourceConfigs which will be made directly to a Lua object.
|
|
Or it can be a list of lists, which will use the cmp built-in helper function `cmp.config.sources`.
|
|
'';
|
|
example = ''
|
|
[
|
|
{ name = "nvim_lsp"; }
|
|
{ name = "luasnip"; } #For luasnip users.
|
|
{ name = "path"; }
|
|
{ name = "buffer"; }
|
|
]
|
|
'';
|
|
};
|
|
|
|
view = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
entries = mkOption {
|
|
default = null;
|
|
type = with types; nullOr (either str attrs);
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
window =
|
|
let
|
|
# Reusable options
|
|
border = with types; mkNullOrOption (either str (listOf str)) null;
|
|
winhighlight = mkNullOrOption types.str null;
|
|
zindex = mkNullOrOption types.int null;
|
|
in
|
|
mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
completion = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
inherit border winhighlight zindex;
|
|
};
|
|
}));
|
|
};
|
|
|
|
documentation = mkOption {
|
|
default = null;
|
|
type = types.nullOr (types.submodule ({ ... }: {
|
|
options = {
|
|
inherit border winhighlight zindex;
|
|
max_width = mkNullOrOption types.int "Window's max width";
|
|
max_height = mkNullOrOption types.int "Window's max height";
|
|
};
|
|
}));
|
|
};
|
|
};
|
|
}));
|
|
};
|
|
|
|
# This can be kept as types.attrs since experimental features are often removed or completely changed after a while
|
|
experimental = mkNullOrOption types.attrs "Experimental features";
|
|
};
|
|
|
|
config =
|
|
let
|
|
options = {
|
|
enabled = cfg.enable;
|
|
performance = cfg.performance;
|
|
preselect = if (isNull cfg.preselect) then null else helpers.mkRaw "cmp.PreselectMode.${cfg.preselect}";
|
|
|
|
# Not very readable sorry
|
|
# If null then null
|
|
# If an attribute is a string, just treat it as lua code for that mapping
|
|
# If an attribute is a module, create a mapping with cmp.mapping() using the action as the first input and the modes as the second.
|
|
mapping =
|
|
let
|
|
mappings =
|
|
if (isNull cfg.mapping) then null
|
|
else
|
|
mapAttrs
|
|
(bind: mapping: helpers.mkRaw (if isString mapping then mapping
|
|
else "cmp.mapping(${mapping.action}${optionalString (mapping.modes != null && length mapping.modes >= 1) ("," + (helpers.toLuaObject mapping.modes))})"))
|
|
cfg.mapping;
|
|
luaMappings = (helpers.toLuaObject mappings);
|
|
wrapped = lists.fold (presetName: prevString: ''cmp.mapping.preset.${presetName}(${prevString})'') luaMappings cfg.mappingPresets;
|
|
in
|
|
helpers.mkRaw wrapped;
|
|
|
|
snippet = {
|
|
expand = if (isNull cfg.snippet || isNull cfg.snippet.expand) then null else helpers.mkRaw cfg.snippet.expand;
|
|
};
|
|
|
|
completion = if (isNull cfg.completion) then null else {
|
|
keyword_length = cfg.completion.keyword_length;
|
|
keyword_pattern = cfg.completion.keyword_pattern;
|
|
autocomplete = if (isNull cfg.completion.autocomplete) then null else mkRaw cfg.completion.autocomplete;
|
|
completeopt = cfg.completion.completeopt;
|
|
};
|
|
|
|
confirmation = if (isNull cfg.confirmation) then null else {
|
|
get_commit_characters =
|
|
if (isString cfg.confirmation.get_commit_characters) then helpers.mkRaw cfg.confirmation.get_commit_characters
|
|
else cfg.confirmation.get_commit_characters;
|
|
};
|
|
|
|
formatting = if (isNull cfg.formatting) then null else {
|
|
fields = cfg.formatting.fields;
|
|
format = if (isNull cfg.formatting.format) then null else helpers.mkRaw cfg.formatting.format;
|
|
};
|
|
|
|
matching = cfg.matching;
|
|
|
|
sorting = if (isNull cfg.sorting) then null else {
|
|
priority_weight = cfg.sorting.priority_weight;
|
|
comparators = if (isNull cfg.sorting.comparators) then null else helpers.mkRaw cfg.sorting.comparators;
|
|
};
|
|
|
|
sources = cfg.sources;
|
|
view = cfg.view;
|
|
window = cfg.window;
|
|
experimental = cfg.experimental;
|
|
};
|
|
in
|
|
mkIf cfg.enable {
|
|
extraPlugins = [ pkgs.vimPlugins.nvim-cmp ];
|
|
|
|
extraConfigLua = ''
|
|
local cmp = require('cmp')
|
|
cmp.setup(${helpers.toLuaObject options})
|
|
'';
|
|
|
|
# If auto_enable_sources is set to true, figure out which are provided by the user
|
|
# and enable the corresponding plugins.
|
|
plugins =
|
|
let
|
|
flattened_sources = if (isNull cfg.sources) then [ ] else flatten cfg.sources;
|
|
# Take only the names from the sources provided by the user
|
|
found_sources = lists.unique (lists.map (source: source.name) flattened_sources);
|
|
# A list of known source names
|
|
known_source_names = attrNames cmpLib.pluginAndSourceNames;
|
|
|
|
attrs_enabled = listToAttrs (map
|
|
(name: {
|
|
name = cmpLib.pluginAndSourceNames.${name};
|
|
value.enable = mkIf (elem name found_sources) true;
|
|
})
|
|
known_source_names);
|
|
in
|
|
mkIf cfg.auto_enable_sources attrs_enabled;
|
|
};
|
|
}
|