diff --git a/flake.lock b/flake.lock index 5b643b08..2d73a3ed 100644 --- a/flake.lock +++ b/flake.lock @@ -1630,6 +1630,22 @@ "type": "github" } }, + "plugin-rtp-nvim": { + "flake": false, + "locked": { + "lastModified": 1724409589, + "narHash": "sha256-lmJbiD7I7MTEEpukESs67uAmLyn+p66hrUKLbEHp0Kw=", + "owner": "nvim-neorocks", + "repo": "rtp.nvim", + "rev": "494ddfc888bb466555d90ace731856de1320fe45", + "type": "github" + }, + "original": { + "owner": "nvim-neorocks", + "repo": "rtp.nvim", + "type": "github" + } + }, "plugin-rustaceanvim": { "flake": false, "locked": { @@ -2038,6 +2054,7 @@ "plugin-project-nvim": "plugin-project-nvim", "plugin-registers": "plugin-registers", "plugin-rose-pine": "plugin-rose-pine", + "plugin-rtp-nvim": "plugin-rtp-nvim", "plugin-rustaceanvim": "plugin-rustaceanvim", "plugin-scrollbar-nvim": "plugin-scrollbar-nvim", "plugin-smartcolumn": "plugin-smartcolumn", diff --git a/flake.nix b/flake.nix index 40043588..4de493e7 100644 --- a/flake.nix +++ b/flake.nix @@ -124,6 +124,11 @@ flake = false; }; + plugin-rtp-nvim = { + url = "github:nvim-neorocks/rtp.nvim"; + flake = false; + }; + # LSP plugins plugin-nvim-lspconfig = { url = "github:neovim/nvim-lspconfig"; diff --git a/modules/plugins/assistant/copilot/config.nix b/modules/plugins/assistant/copilot/config.nix index 923a0c6d..9c337148 100644 --- a/modules/plugins/assistant/copilot/config.nix +++ b/modules/plugins/assistant/copilot/config.nix @@ -4,11 +4,8 @@ ... }: let inherit (builtins) toJSON; - inherit (lib.nvim.lua) toLuaObject; - inherit (lib.modules) mkIf mkMerge; - inherit (lib.nvim.dag) entryAnywhere; - inherit (lib.lists) optionals; - inherit (lib.nvim.binds) mkLuaBinding; + inherit (lib.modules) mkIf; + inherit (lib.strings) optionalString; cfg = config.vim.assistant.copilot; @@ -23,65 +20,77 @@ end end ''; + + mkLuaKeymap = mode: key: action: desc: opts: + opts + // { + inherit mode key action desc; + lua = true; + }; in { config = mkIf cfg.enable { - vim.startPlugins = - [ - "copilot-lua" - # cfg.copilotNodePackage - ] - ++ optionals cfg.cmp.enable [ - "copilot-cmp" - ]; + vim = { + lazy.plugins = { + copilot-lua = { + package = "copilot-lua"; + setupModule = "copilot"; + inherit (cfg) setupOpts; + after = mkIf cfg.cmp.enable "require('copilot_cmp').setup()"; - vim.autocomplete.nvim-cmp.sources = {copilot = "[Copilot]";}; + cmd = ["Copilot" "CopilotAuth" "CopilotDetach" "CopilotPanel" "CopilotStop"]; + keys = [ + (mkLuaKeymap ["n"] cfg.mappings.panel.accept (wrapPanelBinding ''require("copilot.panel").accept'' cfg.mappings.panel.accept) "[copilot] Accept suggestion" {}) + (mkLuaKeymap ["n"] cfg.mappings.panel.jumpNext (wrapPanelBinding "require(\"copilot.panel\").jump_next" cfg.mappings.panel.jumpNext) "[copilot] Accept suggestion" {}) + (mkLuaKeymap ["n"] cfg.mappings.panel.jumpPrev (wrapPanelBinding "require(\"copilot.panel\").jump_prev" cfg.mappings.panel.jumpPrev) "[copilot] Accept suggestion" {}) + (mkLuaKeymap ["n"] cfg.mappings.panel.refresh (wrapPanelBinding "require(\"copilot.panel\").refresh" cfg.mappings.panel.refresh) "[copilot] Accept suggestion" {}) + (mkLuaKeymap ["n"] cfg.mappings.panel.open (wrapPanelBinding '' + function() require("copilot.panel").open({ position = "${cfg.setupOpts.panel.layout.position}", ratio = ${toString cfg.setupOpts.panel.layout.ratio}, }) end + '' + cfg.mappings.panel.open) "[copilot] Accept suggestion" {}) - vim.pluginRC.copilot = entryAnywhere '' - require("copilot").setup(${toLuaObject cfg.setupOpts}) + (mkLuaKeymap ["i"] cfg.mappings.suggestion.accept "function() require('copilot.suggestion').accept() end" "[copilot] Accept suggestion" {}) + (mkLuaKeymap ["i"] cfg.mappings.suggestion.acceptLine "function() require('copilot.suggestion').accept_line() end" "[copilot] Accept suggestion (line)" {}) + (mkLuaKeymap ["i"] cfg.mappings.suggestion.acceptWord "function() require('copilot.suggestion').accept_word() end" "[copilot] Accept suggestion (word)" {}) + (mkLuaKeymap ["i"] cfg.mappings.suggestion.dismiss "function() require('copilot.suggestion').dismiss() end" "[copilot] dismiss suggestion" {}) + (mkLuaKeymap ["i"] cfg.mappings.suggestion.next "function() require('copilot.suggestion').next() end" "[copilot] next suggestion" {}) + (mkLuaKeymap ["i"] cfg.mappings.suggestion.prev "function() require('copilot.suggestion').prev() end" "[copilot] previous suggestion" {}) + ]; + }; - ${lib.optionalString cfg.cmp.enable '' - require("copilot_cmp").setup() - ''} - ''; + copilot-cmp = mkIf cfg.cmp.enable { + package = "copilot-cmp"; + lazy = true; + after = optionalString config.vim.lazy.enable '' + local path = vim.fn.globpath(vim.o.packpath, 'pack/*/opt/copilot-cmp') + require("rtp_nvim").source_after_plugin_dir(path) + require("lz.n").trigger_load("copilot-lua") + ''; + }; - # Disable plugin handled keymaps. - # Setting it here so that it doesn't show up in user docs - vim.assistant.copilot.setupOpts = { - panel.keymap = { - jump_prev = lib.mkDefault false; - jump_next = lib.mkDefault false; - accept = lib.mkDefault false; - refresh = lib.mkDefault false; - open = lib.mkDefault false; + nvim-cmp.after = mkIf cfg.cmp.enable "require('lz.n').trigger_load('copilot-cmp')"; }; - suggestion.keymap = { - accept = lib.mkDefault false; - accept_word = lib.mkDefault false; - accept_line = lib.mkDefault false; - next = lib.mkDefault false; - prev = lib.mkDefault false; - dismiss = lib.mkDefault false; + + autocomplete.nvim-cmp.sources = {copilot = "[Copilot]";}; + + # Disable plugin handled keymaps. + # Setting it here so that it doesn't show up in user docs + assistant.copilot.setupOpts = { + panel.keymap = { + jump_prev = lib.mkDefault false; + jump_next = lib.mkDefault false; + accept = lib.mkDefault false; + refresh = lib.mkDefault false; + open = lib.mkDefault false; + }; + suggestion.keymap = { + accept = lib.mkDefault false; + accept_word = lib.mkDefault false; + accept_line = lib.mkDefault false; + next = lib.mkDefault false; + prev = lib.mkDefault false; + dismiss = lib.mkDefault false; + }; }; }; - - vim.maps.normal = mkMerge [ - (mkLuaBinding cfg.mappings.panel.jumpPrev (wrapPanelBinding "require(\"copilot.panel\").jump_prev" cfg.mappings.panel.jumpPrev) "[copilot] Accept suggestion") - (mkLuaBinding cfg.mappings.panel.jumpNext (wrapPanelBinding "require(\"copilot.panel\").jump_next" cfg.mappings.panel.jumpNext) "[copilot] Accept suggestion") - (mkLuaBinding cfg.mappings.panel.accept (wrapPanelBinding ''require("copilot.panel").accept'' cfg.mappings.panel.accept) "[copilot] Accept suggestion") - (mkLuaBinding cfg.mappings.panel.refresh (wrapPanelBinding "require(\"copilot.panel\").refresh" cfg.mappings.panel.refresh) "[copilot] Accept suggestion") - (mkLuaBinding cfg.mappings.panel.open (wrapPanelBinding '' - function() require("copilot.panel").open({ position = "${cfg.setupOpts.panel.layout.position}", ratio = ${toString cfg.setupOpts.panel.layout.ratio}, }) end - '' - cfg.mappings.panel.open) "[copilot] Accept suggestion") - ]; - - vim.maps.insert = mkMerge [ - (mkLuaBinding cfg.mappings.suggestion.accept "require(\"copilot.suggestion\").accept" "[copilot] Accept suggestion") - (mkLuaBinding cfg.mappings.suggestion.acceptLine "require(\"copilot.suggestion\").accept_line" "[copilot] Accept suggestion (line)") - (mkLuaBinding cfg.mappings.suggestion.acceptWord "require(\"copilot.suggestion\").accept_word" "[copilot] Accept suggestion (word)") - (mkLuaBinding cfg.mappings.suggestion.next "require(\"copilot.suggestion\").next" "[copilot] next suggestion") - (mkLuaBinding cfg.mappings.suggestion.prev "require(\"copilot.suggestion\").prev" "[copilot] previous suggestion") - (mkLuaBinding cfg.mappings.suggestion.dismiss "require(\"copilot.suggestion\").dismiss" "[copilot] dismiss suggestion") - ]; }; } diff --git a/modules/plugins/completion/nvim-cmp/config.nix b/modules/plugins/completion/nvim-cmp/config.nix index 5d20242d..9140b05f 100644 --- a/modules/plugins/completion/nvim-cmp/config.nix +++ b/modules/plugins/completion/nvim-cmp/config.nix @@ -6,7 +6,6 @@ inherit (lib.modules) mkIf; inherit (lib.strings) optionalString; inherit (lib.generators) mkLuaInline; - inherit (lib.nvim.dag) entryAfter; inherit (lib.nvim.lua) toLuaObject; inherit (builtins) attrNames; @@ -16,78 +15,107 @@ in { config = mkIf cfg.enable { vim = { - startPlugins = [ - "nvim-cmp" - "cmp-buffer" - "cmp-path" - ]; + startPlugins = ["rtp-nvim"]; + lazy.plugins = { + # cmp sources are loaded via lzn-auto-require as long as it is defined + # in cmp sources + cmp-buffer = { + package = "cmp-buffer"; + lazy = true; + after = '' + local path = vim.fn.globpath(vim.o.packpath, 'pack/*/opt/cmp-buffer') + require("rtp_nvim").source_after_plugin_dir(path) + ''; + }; + cmp-path = { + package = "cmp-path"; + lazy = true; + after = '' + local path = vim.fn.globpath(vim.o.packpath, 'pack/*/opt/cmp-path') + require("rtp_nvim").source_after_plugin_dir(path) + ''; + }; + nvim-cmp = { + package = "nvim-cmp"; + after = '' + ${optionalString luasnipEnable "local luasnip = require('luasnip')"} + require("lz.n").trigger_load("cmp-path") + local cmp = require("cmp") + cmp.setup(${toLuaObject cfg.setupOpts}) - autocomplete.nvim-cmp.sources = { - nvim-cmp = null; - buffer = "[Buffer]"; - path = "[Path]"; + ${ + optionalString config.vim.lazy.enable '' + require("lz.n").trigger_load("cmp-buffer") + '' + } + ''; + + event = ["InsertEnter" "CmdlineEnter"]; + }; }; - autocomplete.nvim-cmp.setupOpts = { - sources = map (s: {name = s;}) (attrNames cfg.sources); - - # TODO: try to get nvim-cmp to follow global border style - window = mkIf config.vim.ui.borders.enable { - completion = mkLuaInline "cmp.config.window.bordered()"; - documentation = mkLuaInline "cmp.config.window.bordered()"; + autocomplete.nvim-cmp = { + sources = { + nvim-cmp = null; + buffer = "[Buffer]"; + path = "[Path]"; }; - formatting.format = cfg.format; - }; + setupOpts = { + sources = map (s: {name = s;}) (attrNames cfg.sources); - pluginRC.nvim-cmp = mkIf cfg.enable (entryAfter ["autopairs" "luasnip"] '' - ${optionalString luasnipEnable "local luasnip = require('luasnip')"} - local cmp = require("cmp") - cmp.setup(${toLuaObject cfg.setupOpts}) - ''); + # TODO: try to get nvim-cmp to follow global border style + window = mkIf config.vim.ui.borders.enable { + completion = mkLuaInline "cmp.config.window.bordered()"; + documentation = mkLuaInline "cmp.config.window.bordered()"; + }; - # `cmp` and `luasnip` are defined above, in the `nvim-cmp` section - autocomplete.nvim-cmp.setupOpts.mapping = { - ${mappings.complete} = mkLuaInline "cmp.mapping.complete()"; - ${mappings.close} = mkLuaInline "cmp.mapping.abort()"; - ${mappings.scrollDocsUp} = mkLuaInline "cmp.mapping.scroll_docs(-4)"; - ${mappings.scrollDocsDown} = mkLuaInline "cmp.mapping.scroll_docs(4)"; - ${mappings.confirm} = mkLuaInline "cmp.mapping.confirm({ select = true })"; + formatting.format = cfg.format; + }; - ${mappings.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 + # `cmp` and `luasnip` are defined above, in the `nvim-cmp` section + setupOpts.mapping = { + ${mappings.complete} = mkLuaInline "cmp.mapping.complete()"; + ${mappings.close} = mkLuaInline "cmp.mapping.abort()"; + ${mappings.scrollDocsUp} = mkLuaInline "cmp.mapping.scroll_docs(-4)"; + ${mappings.scrollDocsDown} = mkLuaInline "cmp.mapping.scroll_docs(4)"; + ${mappings.confirm} = mkLuaInline "cmp.mapping.confirm({ select = true })"; - 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) - ''; + ${mappings.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 - ${mappings.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) - ''; + 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) + ''; + + ${mappings.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) + ''; + }; }; }; }; diff --git a/modules/plugins/lsp/config.nix b/modules/plugins/lsp/config.nix index 52dc15b4..63c21d5a 100644 --- a/modules/plugins/lsp/config.nix +++ b/modules/plugins/lsp/config.nix @@ -23,7 +23,17 @@ in { config = mkIf cfg.enable { vim = { - startPlugins = optional usingNvimCmp "cmp-nvim-lsp"; + lazy.plugins = { + cmp-nvim-lsp = { + package = "cmp-nvim-lsp"; + lazy = true; + after = '' + local path = vim.fn.globpath(vim.o.packpath, 'pack/*/opt/cmp-treesitter') + require("rtp_nvim").source_after_plugin_dir(path) + ''; + }; + nvim-cmp.after = mkIf usingNvimCmp "require('lz.n').trigger_load('cmp-nvim-lsp')"; + }; autocomplete.nvim-cmp.sources = {nvim_lsp = "[LSP]";}; diff --git a/modules/plugins/snippets/luasnip/config.nix b/modules/plugins/snippets/luasnip/config.nix index 541fd0fd..4fbbd2cd 100644 --- a/modules/plugins/snippets/luasnip/config.nix +++ b/modules/plugins/snippets/luasnip/config.nix @@ -4,14 +4,32 @@ ... }: let inherit (lib.modules) mkIf; + inherit (lib.strings) optionalString; cfg = config.vim.snippets.luasnip; in { config = mkIf cfg.enable { vim = { - startPlugins = ["luasnip" "cmp-luasnip"] ++ cfg.providers; + lazy.plugins = { + luasnip = { + package = "luasnip"; + lazy = true; + after = cfg.loaders; + }; + cmp-luasnip = mkIf config.vim.autocomplete.nvim-cmp.enable { + package = "cmp-luasnip"; + lazy = true; + after = '' + local path = vim.fn.globpath(vim.o.packpath, 'pack/*/opt/cmp-luasnip') + require("rtp_nvim").source_after_plugin_dir(path) + ''; + }; + nvim-cmp.after = optionalString config.vim.lazy.enable '' + require("lz.n").trigger_load("cmp-luasnip") + ''; + }; + startPlugins = cfg.providers; autocomplete.nvim-cmp.sources = {luasnip = "[LuaSnip]";}; - pluginRC.luasnip = cfg.loaders; }; }; } diff --git a/modules/plugins/treesitter/config.nix b/modules/plugins/treesitter/config.nix index ae093862..e810d7e5 100644 --- a/modules/plugins/treesitter/config.nix +++ b/modules/plugins/treesitter/config.nix @@ -19,7 +19,18 @@ in { config = mkIf cfg.enable { vim = { - startPlugins = ["nvim-treesitter"] ++ optional usingNvimCmp "cmp-treesitter"; + startPlugins = ["nvim-treesitter"]; + + lazy.plugins = { + cmp-treesitter = mkIf usingNvimCmp { + package = "cmp-treesitter"; + after = '' + local path = vim.fn.globpath(vim.o.packpath, 'pack/*/opt/cmp-treesitter') + require("rtp_nvim").source_after_plugin_dir(path) + ''; + }; + nvim-cmp.after = mkIf usingNvimCmp "require('lz.n').trigger_load('cmp-treesitter')"; + }; autocomplete.nvim-cmp.sources = {treesitter = "[Treesitter]";}; treesitter.grammars = optionals cfg.addDefaultGrammars cfg.defaultGrammars; diff --git a/modules/wrapper/lazy/config.nix b/modules/wrapper/lazy/config.nix index 30f9626c..da5dd8c1 100644 --- a/modules/wrapper/lazy/config.nix +++ b/modules/wrapper/lazy/config.nix @@ -86,7 +86,7 @@ in { require('lz.n').load(${toLuaObject lznSpecs}) ''; }) - + (mkIf (!cfg.enable) { startPlugins = mapAttrsToList (_: plugin: plugin.package) cfg.plugins; luaConfigPre = diff --git a/modules/wrapper/lazy/lazy.nix b/modules/wrapper/lazy/lazy.nix index 52ed9c3f..e16a8aa2 100644 --- a/modules/wrapper/lazy/lazy.nix +++ b/modules/wrapper/lazy/lazy.nix @@ -92,7 +92,7 @@ description = '' Lua code to run after plugin is loaded. This will be wrapped in a function. - If [](#opt-vim.lazy.plugins._.setupModule) is provided, the setup will be ran before `after`. + If [](#opt-vim.lazy.plugins._name_.setupModule) is provided, the setup will be ran before `after`. ''; default = null; };