summaryrefslogtreecommitdiffstats
path: root/modules/plugins/completion/nvim-cmp/config.nix
blob: 8a0d19b4ca977b03f98c6067a247d74577d5edcc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
{
  lib,
  config,
  ...
}: let
  inherit (lib.attrsets) filterAttrs mapAttrs';
  inherit (lib.modules) mkIf;
  inherit (lib.strings) optionalString;
  inherit (lib.generators) mkLuaInline;
  inherit (lib.nvim.lua) toLuaObject;
  inherit (builtins) attrNames typeOf tryEval concatStringsSep;

  borders = config.vim.ui.borders.plugins.nvim-cmp;

  cfg = config.vim.autocomplete.nvim-cmp;
  luasnipEnable = config.vim.snippets.luasnip.enable;
  getPluginName = plugin:
    if typeOf plugin == "string"
    then plugin
    else if (plugin ? pname && (tryEval plugin.pname).success)
    then plugin.pname
    else plugin.name;
  inherit (cfg) mappings;
in {
  config = mkIf cfg.enable {
    vim = {
      lazy.plugins = {
        nvim-cmp = {
          package = "nvim-cmp";
          after = ''
            ${optionalString luasnipEnable "local luasnip = require('luasnip')"}
            local cmp = require("cmp")

            local kinds = require("cmp.types").lsp.CompletionItemKind
            local deprio = function(kind)
              return function(e1, e2)
                if e1:get_kind() == kind then
                  return false
                end
                if e2:get_kind() == kind then
                  return true
                end
                return nil
              end
            end

            cmp.setup(${toLuaObject cfg.setupOpts})

            ${optionalString config.vim.lazy.enable
              (concatStringsSep "\n" (map
                (package: "require('lz.n').trigger_load(${toLuaObject (getPluginName package)})")
                cfg.sourcePlugins))}
          '';

          event = ["InsertEnter" "CmdlineEnter"];
        };
      };

      autocomplete = {
        enableSharedCmpSources = true;

        nvim-cmp = {
          sourcePlugins = ["cmp-buffer" "cmp-path"];

          setupOpts = {
            sources = map (s: {name = s;}) (attrNames cfg.sources);

            window = mkIf borders.enable {
              completion.border = borders.style;
              documentation.border = borders.style;
            };

            formatting.format = cfg.format;

            # `cmp` and `luasnip` are defined above, in the `nvim-cmp` section
            mapping =
              mapAttrs' (mapping-name: action: {
                name = mappings.${mapping-name};
                value = action;
              }) (filterAttrs (mapping-name: _action: mappings.${mapping-name} != null)
                {
                  complete = mkLuaInline "cmp.mapping.complete()";
                  close = mkLuaInline "cmp.mapping.abort()";
                  scrollDocsUp = mkLuaInline "cmp.mapping.scroll_docs(-4)";
                  scrollDocsDown = mkLuaInline "cmp.mapping.scroll_docs(4)";
                  confirm = mkLuaInline "cmp.mapping.confirm({ select = true })";

                  next = mkLuaInline ''
                    cmp.mapping(function(fallback)
                      local has_words_before = function()
                        local line, col = unpack(vim.api.nvim_win_get_cursor(0))
                        return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
                      end

                      if cmp.visible() then
                        cmp.select_next_item()
                        ${optionalString luasnipEnable ''
                      elseif luasnip.locally_jumpable(1) then
                        luasnip.jump(1)
                    ''}
                      elseif has_words_before() then
                        cmp.complete()
                      else
                        fallback()
                      end
                    end)
                  '';

                  previous = mkLuaInline ''
                    cmp.mapping(function(fallback)
                      if cmp.visible() then
                        cmp.select_prev_item()
                        ${optionalString luasnipEnable ''
                      elseif luasnip.locally_jumpable(-1) then
                        luasnip.jump(-1)
                    ''}
                      else
                        fallback()
                      end
                    end)
                  '';
                });
          };
        };
      };
    };
  };
}