return { { "robitx/gp.nvim", init = function() local wk = require("which-key") wk.add({ mode = { "n", "v", "x" }, { "G", group = "GPT" }, { "Gg", group = "Gp" }, { "GW", group = "Whisper" }, }) end, config = function() local function keymapOptions(desc) return { noremap = true, silent = true, nowait = true, desc = desc, } end local conf = { -- For customization, refer to Install > Configuration in the Documentation/Readme -- openai_api_key = { "pass", "show", "api/chatGPT/nvim" }, openai_api_key = { "pass", "show", "api/chatGPT/nvim" }, providers = { openai = { disable = false, endpoint = "https://api.openai.com/v1/chat/completions", -- secret = { "pass", "show", "api/chatGPT/nvim" }, }, }, hooks = { -- GpInspectPlugin provides a detailed inspection of the plugin state InspectPlugin = function(plugin, params) local bufnr = vim.api.nvim_create_buf(false, true) local copy = vim.deepcopy(plugin) local key = copy.config.openai_api_key or "" copy.config.openai_api_key = key:sub(1, 3) .. string.rep("*", #key - 6) .. key:sub(-3) local plugin_info = string.format("Plugin structure:\n%s", vim.inspect(copy)) local params_info = string.format("Command params:\n%s", vim.inspect(params)) local lines = vim.split(plugin_info .. "\n" .. params_info, "\n") vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) vim.api.nvim_win_set_buf(0, bufnr) end, -- GpInspectLog for checking the log file InspectLog = function(plugin, params) local log_file = plugin.config.log_file local buffer = plugin.helpers.get_buffer(log_file) if not buffer then vim.cmd("e " .. log_file) else vim.cmd("buffer " .. buffer) end end, -- GpImplement rewrites the provided selection/range based on comments in it Implement = function(gp, params) local template = "Having following from {{filename}}:\n\n" .. "```{{filetype}}\n{{selection}}\n```\n\n" .. "Please rewrite this according to the contained instructions." .. "\n\nRespond exclusively with the snippet that should replace the selection above." local agent = gp.get_command_agent() gp.logger.info("Implementing selection with agent: " .. agent.name) gp.Prompt( params, gp.Target.rewrite, agent, template, nil, -- command will run directly without any prompting for user input nil -- no predefined instructions (e.g. speech-to-text from Whisper) ) end, -- your own functions can go here, see README for more examples like -- :GpExplain, :GpUnitTests.., :GpTranslator etc. -- example of making :%GpChatNew a dedicated command which -- opens new chat with the entire current buffer as a context BufferChatNew = function(gp, _) -- call GpChatNew command in range mode on whole buffer vim.api.nvim_command("%" .. gp.config.cmd_prefix .. "ChatNew") end, -- example of adding command which opens new chat dedicated for translation Translator = function(gp, params) local chat_system_prompt = "You are a Translator, please translate between English and Korean." gp.cmd.ChatNew(params, chat_system_prompt) -- -- you can also create a chat with a specific fixed agent like this: -- local agent = gp.get_chat_agent("ChatGPT4o") -- gp.cmd.ChatNew(params, chat_system_prompt, agent) end, -- example of adding command which writes unit tests for the selected code UnitTests = function(gp, params) local template = "I have the following code from {{filename}}:\n\n" .. "```{{filetype}}\n{{selection}}\n```\n\n" .. "Please respond by writing table driven unit tests for the code above." local agent = gp.get_command_agent() gp.Prompt(params, gp.Target.enew, agent, template) end, -- example of adding command which explains the selected code Explain = function(gp, params) local template = "I have the following code from {{filename}}:\n\n" .. "```{{filetype}}\n{{selection}}\n```\n\n" .. "Please respond by explaining the code above." local agent = gp.get_chat_agent() gp.Prompt(params, gp.Target.popup, agent, template) end, -- example of usig enew as a function specifying type for the new buffer CodeReview = function(gp, params) local template = "I have the following code from {{filename}}:\n\n" .. "```{{filetype}}\n{{selection}}\n```\n\n" .. "Please analyze for code smells and suggest improvements." local agent = gp.get_chat_agent() gp.Prompt(params, gp.Target.enew("markdown"), agent, template) end, }, } require("gp").setup(conf) -- Setup shortcuts here (see Usage > Shortcuts in the Documentation/Readme) vim.keymap.set({ "n", "i" }, "Gc", "GpChatNew", keymapOptions("New chat")) vim.keymap.set({ "n", "i" }, "Gb", "GpBufferChatNew", keymapOptions("New buffer chat")) vim.keymap.set({ "n", "i" }, "Gt", "GpChatToggle", keymapOptions("Toggle chat")) vim.keymap.set({ "n", "i" }, "Gf", "GpChatFinder", keymapOptions("Chat finder")) vim.keymap.set("v", "Gc", ":'<,'>GpChatNew", keymapOptions("Chat new")) vim.keymap.set("v", "Gb", ":'<,'>GpBufferChatNew", keymapOptions("Buffer chat new")) vim.keymap.set("v", "Gp", ":'<,'>GpChatPaste", keymapOptions("Chat paste")) vim.keymap.set("v", "Gt", ":'<,'>GpChatToggle", keymapOptions("Toggle chat")) vim.keymap.set({ "n", "i" }, "Gh", "gpchatnew split", keymapOptions("New chat split")) vim.keymap.set({ "n", "i" }, "Gv", "gpchatnew vsplit", keymapOptions("New chat vsplit")) vim.keymap.set({ "n", "i" }, "Gn", "gpchatnew tabnew", keymapOptions("New chat tabnew")) vim.keymap.set("v", "Gh", ":'<,'>GpChatNew split", keymapOptions("Chat new split")) vim.keymap.set("v", "Gv", ":'<,'>GpChatNew vsplit", keymapOptions("Chat new vsplit")) vim.keymap.set("v", "Gn", ":'<,'>GpChatNew tabnew", keymapOptions("Chat new tabnew")) -- Prompt commands vim.keymap.set({ "n", "i" }, "Gw", "GpRewrite", keymapOptions("Inline rewrite")) vim.keymap.set({ "n", "i" }, "Gr", "GpCodeReview", keymapOptions("Code review")) vim.keymap.set({ "n", "i" }, "G]", "GpAppend", keymapOptions("Append (after)")) vim.keymap.set({ "n", "i" }, "G[", "GpPrepend", keymapOptions("Prepend (before)")) vim.keymap.set("v", "Gw", ":'<,'>GpRewrite", keymapOptions("Rewrite")) vim.keymap.set("v", "Gr", ":'<,'>GpCodeReview", keymapOptions("Code review")) vim.keymap.set("v", "G]", ":'<,'>GpAppend", keymapOptions("Append (after)")) vim.keymap.set("v", "G[", ":'<,'>GpPrepend", keymapOptions("Prepend (before)")) vim.keymap.set("v", "Gi", ":'<,'>GpImplement", keymapOptions("Implement selection")) vim.keymap.set({ "n", "i" }, "Ggp", "GpPopup", keymapOptions("Popup")) vim.keymap.set({ "n", "i" }, "Gge", "GpEnew", keymapOptions("GpEnew")) vim.keymap.set({ "n", "i" }, "Ggc", "GpNew", keymapOptions("GpNew")) vim.keymap.set({ "n", "i" }, "Ggv", "GpVnew", keymapOptions("GpVnew")) vim.keymap.set({ "n", "i" }, "Ggn", "GpTabnew", keymapOptions("GpTabnew")) vim.keymap.set("v", "Ggp", ":'<,'>GpPopup", keymapOptions("Popup")) vim.keymap.set("v", "Gge", ":'<,'>GpEnew", keymapOptions("GpEnew")) vim.keymap.set("v", "Ggc", ":'<,'>GpNew", keymapOptions("GpNew")) vim.keymap.set("v", "Ggv", ":'<,'>GpVnew", keymapOptions("GpVnew")) vim.keymap.set("v", "Ggn", ":'<,'>GpTabnew", keymapOptions("GpTabnew")) vim.keymap.set({ "n", "i" }, "Gx", "GpContext", keymapOptions("Toggle context")) vim.keymap.set("v", "Gx", ":'<,'>GpContext", keymapOptions("Toggle context")) vim.keymap.set({ "n", "i", "v", "x" }, "Ggs", "GpStop", keymapOptions("Stop")) vim.keymap.set({ "n", "i", "v", "x" }, "Gg]", "GpNextAgent", keymapOptions("Next agent")) -- optional Whisper commands with prefix w vim.keymap.set({ "n", "i" }, "GWw", "GpWhisper", keymapOptions("Whisper")) vim.keymap.set("v", "GWw", ":'<,'>GpWhisper", keymapOptions("Whisper")) vim.keymap.set({ "n", "i" }, "GWr", "GpWhisperRewrite", keymapOptions("Inline rewrite")) vim.keymap.set({ "n", "i" }, "GW]", "GpWhisperAppend", keymapOptions("Append (after)")) vim.keymap.set({ "n", "i" }, "GW[", "GpWhisperPrepend", keymapOptions("Prepend (before) ")) vim.keymap.set("v", "GWr", ":'<,'>GpWhisperRewrite", keymapOptions("Rewrite")) vim.keymap.set("v", "GW]", ":'<,'>GpWhisperAppend", keymapOptions("Append (after)")) vim.keymap.set("v", "GW[", ":'<,'>GpWhisperPrepend", keymapOptions("Prepend (before)")) vim.keymap.set({ "n", "i" }, "GWp", "GpWhisperPopup", keymapOptions("Popup")) vim.keymap.set({ "n", "i" }, "GWe", "GpWhisperEnew", keymapOptions("Enew")) vim.keymap.set({ "n", "i" }, "GWc", "GpWhisperNew", keymapOptions("New")) vim.keymap.set({ "n", "i" }, "GWv", "GpWhisperVnew", keymapOptions("Vnew")) vim.keymap.set({ "n", "i" }, "GWn", "GpWhisperTabnew", keymapOptions("Tabnew")) vim.keymap.set("v", "GWp", ":'<,'>GpWhisperPopup", keymapOptions("Popup")) vim.keymap.set("v", "GWe", ":'<,'>GpWhisperEnew", keymapOptions("Enew")) vim.keymap.set("v", "GWc", ":'<,'>GpWhisperNew", keymapOptions("New")) vim.keymap.set("v", "GWv", ":'<,'>GpWhisperVnew", keymapOptions("Vnew")) vim.keymap.set("v", "GWn", ":'<,'>GpWhisperTabnew", keymapOptions("Tabnew")) end, }, { "zbirenbaum/copilot.lua", cmd = "Copilot", build = ":Copilot auth", event = "InsertEnter", dependencies = { "hrsh7th/nvim-cmp", { "AndreM222/copilot-lualine" }, { "zbirenbaum/copilot-cmp", config = function() require("copilot_cmp").setup() end, }, }, config = function() require("copilot").setup({ panel = { enabled = true, auto_refresh = true, keymap = { jump_prev = "[a", jump_next = "]a", accept = "", refresh = "gr", open = "", }, layout = { position = "right", -- | top | left | right ratio = 0.4, }, }, suggestion = { enabled = true, auto_trigger = true, hide_during_completion = true, debounce = 75, keymap = { accept = "", accept_word = false, accept_line = false, next = "", prev = "", dismiss = "", }, }, filetypes = { cvs = false, gitcommit = false, gitrebase = false, help = true, hgcommit = false, markdown = true, sh = function() if string.match(vim.fs.basename(vim.api.nvim_buf_get_name(0)), "^%.env.*") then -- disable for .env files return false end return true end, svn = false, yaml = false, ["."] = false, ["*"] = true, }, copilot_node_command = "node", -- Node.js version must be > 18.x server_opts_overrides = {}, }) local cmp = require("cmp") cmp.event:on("menu_opened", function() vim.b.copilot_suggestion_hidden = true end) cmp.event:on("menu_closed", function() vim.b.copilot_suggestion_hidden = false end) end, vim.keymap.set("n", "ct", function() require("copilot.suggestion").toggle_auto_trigger() end, { noremap = true, silent = true, desc = "Toggle copilot" }), }, }