From 70dd3446fba2e4f34971015095e8ba6494e8a428 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 5 Aug 2022 15:01:10 +0100 Subject: [PATCH] nvim-cmp: fix snippet not being able to be null --- plugins/completion/nvim-cmp/default.nix | 358 +++++++++++++----------- 1 file changed, 192 insertions(+), 166 deletions(-) diff --git a/plugins/completion/nvim-cmp/default.nix b/plugins/completion/nvim-cmp/default.nix index b0749dd3..48f17dea 100644 --- a/plugins/completion/nvim-cmp/default.nix +++ b/plugins/completion/nvim-cmp/default.nix @@ -7,9 +7,11 @@ let 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})''; + wrapWithFunction = functionName: parameters: + let + parameterString = strings.concatStringsSep "," parameters; + in + ''${functionName}(${parameterString})''; in { options.programs.nixvim.plugins.nvim-cmp = { @@ -17,7 +19,7 @@ in performance = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { debounce = mkOption { type = types.nullOr types.int; @@ -39,7 +41,7 @@ in snippet = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { expand = mkOption { type = types.nullOr types.str; @@ -57,20 +59,21 @@ in }; mappingPresets = mkOption { - default = []; + default = [ ]; type = types.listOf (types.enum [ - "insert" - "cmdline" -# Not sure if there are more or if this should just be str + "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 ({...}: { + type = types.nullOr (types.attrsOf (types.either types.str (types.submodule ({ ... }: { options = { action = mkOption { type = types.nonEmptyStr; @@ -111,7 +114,7 @@ in completion = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { keyword_length = mkOption { default = null; @@ -140,7 +143,7 @@ in confirmation = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { get_commit_characters = mkOption { default = null; @@ -153,7 +156,7 @@ in formatting = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { fields = mkOption { default = null; @@ -171,7 +174,7 @@ in matching = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { disallow_fuzzy_matching = mkOption { default = null; @@ -191,7 +194,7 @@ in sorting = mkOption { default = null; - type = types.nullOr (types.submodule ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { priority_weight = mkOption { default = null; @@ -212,73 +215,75 @@ in ''; }; - sources = let - source_config = types.submodule ({...}: { - options = { - name = mkOption { - type = types.str; - description = "The name of the source."; - example = ''"buffer"''; - }; + 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"; - }; + 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_length = mkOption { + default = null; + type = types.nullOr types.int; + }; - keyword_pattern = 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); - }; + trigger_characters = mkOption { + default = null; + type = with types; nullOr (listOf str); + }; - priority = mkOption { - default = null; - type = types.nullOr types.int; - }; + priority = mkOption { + default = null; + type = types.nullOr types.int; + }; - max_item_count = 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; + 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"; } - ] - ''; - }; + }); + 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 ({...}: { + type = types.nullOr (types.submodule ({ ... }: { options = { entries = mkOption { default = null; @@ -288,110 +293,131 @@ in })); }; - 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; - }; - })); - }; + 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"; - }; - })); + 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}"; + 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.expand) then null else helpers.mkRaw cfg.snippet.expand; + # 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; }; - 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; + in + mkIf cfg.enable { + programs.nixvim = { + 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; }; - 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 { - programs.nixvim = { - 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; - }; - }; }