{ config, lib, ... }: let inherit (builtins) toJSON; inherit (lib.modules) mkIf; inherit (lib.strings) optionalString; cfg = config.vim.assistant.copilot; wrapPanelBinding = luaFunction: key: '' function() local s, _ = pcall(${luaFunction}) if not s then local termcode = vim.api.nvim_replace_termcodes(${toJSON key}, true, false, true) vim.fn.feedkeys(termcode, 'n') end end ''; mkLuaKeymap = mode: key: action: desc: opts: opts // { inherit mode key action desc; lua = true; }; in { config = mkIf cfg.enable { vim = { lazy.plugins = { copilot-lua = { package = "copilot-lua"; setupModule = "copilot"; inherit (cfg) setupOpts; after = mkIf cfg.cmp.enable "require('copilot_cmp').setup()"; 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" {}) (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" {}) ]; }; 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") ''; }; nvim-cmp.after = mkIf cfg.cmp.enable "require('lz.n').trigger_load('copilot-cmp')"; }; 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; }; }; }; }; }