From 292d44b50fd0cd65000190e52bbaa79064bfb4c2 Mon Sep 17 00:00:00 2001 From: Antoine Gaudreau Simard Date: Sat, 30 Aug 2025 22:04:49 -0400 Subject: [PATCH] feat: next edit suggestion (nes) Fixes #544 --- README.md | 65 +++++++++++--- lua/copilot/client/config.lua | 2 + lua/copilot/config/init.lua | 4 + lua/copilot/config/nes.lua | 58 ++++++++++++ lua/copilot/highlight.lua | 14 +++ lua/copilot/keymaps/init.lua | 89 +++++++++++++++++++ lua/copilot/logger/init.lua | 16 +++- lua/copilot/nes/api.lua | 46 ++++++++++ lua/copilot/nes/init.lua | 74 +++++++++++++++ lua/copilot/panel/init.lua | 11 +-- lua/copilot/suggestion/init.lua | 85 ++++++------------ lua/copilot/util.lua | 31 ------- ...sthrough-Esc---base-test-setting-highlight | 23 +++++ ...through-Esc---return-false,-will-remove-hl | 23 +++++ ...ough-Esc---return-true,-will-not-remove-hl | 23 +++++ ...)---passthrough-Esc-passes-original-keymap | 23 +++++ tests/test_keymaps.lua | 62 +++++++++++++ tests/test_util.lua | 30 +++++++ 18 files changed, 572 insertions(+), 107 deletions(-) create mode 100644 lua/copilot/config/nes.lua create mode 100644 lua/copilot/keymaps/init.lua create mode 100644 lua/copilot/nes/api.lua create mode 100644 lua/copilot/nes/init.lua create mode 100644 tests/screenshots/tests-test_keymaps.lua---keymaps()---passthrough-Esc---base-test-setting-highlight create mode 100644 tests/screenshots/tests-test_keymaps.lua---keymaps()---passthrough-Esc---return-false,-will-remove-hl create mode 100644 tests/screenshots/tests-test_keymaps.lua---keymaps()---passthrough-Esc---return-true,-will-not-remove-hl create mode 100644 tests/screenshots/tests-test_util.lua---util()---passthrough-Esc-passes-original-keymap create mode 100644 tests/test_keymaps.lua create mode 100644 tests/test_util.lua diff --git a/README.md b/README.md index bfe520f4..956c78a4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # copilot.lua This plugin is the pure lua replacement for [github/copilot.vim](https://github.com/github/copilot.vim). +A huge thank you to @tris203 for the code behind the nes functionality ([copilot-lsp](https://github.com/copilotlsp-nvim/copilot-lsp)).
Motivation behind `copilot.lua` @@ -48,7 +49,11 @@ Install the plugin with your preferred plugin manager. For example, with [packer.nvim](https://github.com/wbthomason/packer.nvim): ```lua -use { "zbirenbaum/copilot.lua" } +use { "zbirenbaum/copilot.lua" + requires = { + "copilotlsp-nvim/copilot-lsp", -- (optional) for NES functionality + }, +} ``` ### Authentication @@ -93,6 +98,9 @@ For example: ```lua use { "zbirenbaum/copilot.lua", + requires = { + "copilotlsp-nvim/copilot-lsp", -- (optional) for NES functionality + }, cmd = "Copilot", event = "InsertEnter", config = function() @@ -136,16 +144,14 @@ require('copilot').setup({ dismiss = "", }, }, - filetypes = { - yaml = false, - markdown = false, - help = false, - gitcommit = false, - gitrebase = false, - hgcommit = false, - svn = false, - cvs = false, - ["."] = false, + nes = { + enabled = false, -- requires copilot-lsp as a dependency + auto_trigger = false, + keymap = { + accept_and_goto = false, + accept = false, + dismiss = false, + }, }, auth_provider_url = nil, -- URL to authentication provider, if not "https://github.com/" logger = { @@ -270,6 +276,43 @@ require("copilot.suggestion").toggle_auto_trigger() ``` These can also be accessed through the `:Copilot suggestion ` command (eg. `:Copilot suggestion accept`). +### nes (next edit suggestion) + +>[!WARNING] +> This feature is still experimental and may not work as expected in all scenarios, please report any issues you encounter. + +When `enabled` is `true`, copilot will provide suggestions based on the next edit you are likely to make, through [copilot-lsp](https://github.com/copilotlsp-nvim/copilot-lsp). +If there is no suggestion, the keymaps will pass through the original keymap. + +`copilot-lsp` has a few configurations built-in as well, for additional configurations, please refer to the [copilot-lsp documentation](https://github.com/copilotlsp-nvim/copilot-lsp/blob/main/README.md). +These configurations should be set in the `init` function of the `copilot-lsp` dependency. + +```lua +use { + "zbirenbaum/copilot.lua", + requires = { + "copilotlsp-nvim/copilot-lsp", + init = function() + vim.g.copilot_nes_debounce = 500 + end, + }, + cmd = "Copilot", + event = "InsertEnter", + config = function() + require("copilot").setup({ + nes = { + enabled = true, + keymap = { + accept_and_goto = "p", + accept = false, + dismiss = "", + }, + }, + }) + end, +} +``` + ### filetypes Specify filetypes for attaching copilot. diff --git a/lua/copilot/client/config.lua b/lua/copilot/client/config.lua index 518e50e1..5c88d126 100644 --- a/lua/copilot/client/config.lua +++ b/lua/copilot/client/config.lua @@ -122,6 +122,8 @@ function M.prepare_client_config(overrides, client) if token_env_set then require("copilot.auth").signin() end + + require("copilot.nes").setup(lsp_client) end) end, on_exit = function(code, _, client_id) diff --git a/lua/copilot/config/init.lua b/lua/copilot/config/init.lua index eedc0b34..97433ca5 100644 --- a/lua/copilot/config/init.lua +++ b/lua/copilot/config/init.lua @@ -5,6 +5,7 @@ local logger = require("copilot.logger") ---@field suggestion SuggestionConfig ---@field logger LoggerConfig ---@field server ServerConfig +---@field nes NesConfig ---@field filetypes table Filetypes to enable Copilot for ---@field auth_provider_url string|nil URL for the authentication provider ---@field workspace_folders string[] Workspace folders to enable Copilot for @@ -23,6 +24,7 @@ local M = { suggestion = require("copilot.config.suggestion").default, logger = require("copilot.config.logger").default, server = require("copilot.config.server").default, + nes = require("copilot.config.nes").default, root_dir = require("copilot.config.root_dir").default, should_attach = require("copilot.config.should_attach").default, filetypes = {}, @@ -59,6 +61,7 @@ end function M.validate(config) vim.validate("panel", config.panel, "table") vim.validate("suggestion", config.suggestion, "table") + vim.validate("nes", config.nes, "table") vim.validate("logger", config.logger, "table") vim.validate("server", config.server, "table") vim.validate("filetypes", config.filetypes, "table") @@ -76,6 +79,7 @@ function M.validate(config) require("copilot.config.server").validate(config.server) require("copilot.config.root_dir").validate(config.root_dir) require("copilot.config.should_attach").validate(config.should_attach) + require("copilot.config.nes").validate(config.nes) end return M diff --git a/lua/copilot/config/nes.lua b/lua/copilot/config/nes.lua new file mode 100644 index 00000000..50bbd9b1 --- /dev/null +++ b/lua/copilot/config/nes.lua @@ -0,0 +1,58 @@ +local logger = require("copilot.logger") +local nes_api = require("copilot.nes.api") +---@class NesKeymap +---@field accept_and_goto string|false Keymap to accept the suggestion and go to the end of the suggestion +---@field accept string|false Keymap to accept the suggestion +---@field dismiss string|false Keymap to dismiss the suggestion + +---@class NesConfig +---@field enabled boolean Whether to enable nes (next edit suggestions) +---@field auto_trigger boolean Whether to automatically trigger next edit suggestions +---@field keymap NesKeymap Keymaps for nes actions + +local M = { + ---@type NesConfig + default = { + enabled = false, + auto_trigger = false, + keymap = { + accept_and_goto = false, + accept = false, + dismiss = false, + }, + }, +} + +---@type NesConfig +M.config = vim.deepcopy(M.default) + +---@param opts? NesConfig +function M.setup(opts) + opts = opts or {} + M.config = vim.tbl_deep_extend("force", M.default, opts) +end + +---@param config NesConfig +function M.validate(config) + vim.validate("enabled", config.enabled, "boolean") + vim.validate("auto_trigger", config.auto_trigger, "boolean") + vim.validate("keymap", config.keymap, "table") + vim.validate("keymap.accept_and_goto", config.keymap.accept_and_goto, { "string", "boolean" }) + vim.validate("keymap.accept", config.keymap.accept, { "string", "boolean" }) + vim.validate("keymap.dismiss", config.keymap.dismiss, { "string", "boolean" }) + + if config.enabled then + local has_nes, _ = pcall(function() + nes_api.test() + end) + + if not has_nes then + logger.error( + "copilot-lsp is not available, disabling nes.\nPlease refer to the documentation and ensure it is installed." + ) + config.enabled = false + end + end +end + +return M diff --git a/lua/copilot/highlight.lua b/lua/copilot/highlight.lua index edc9a844..e3636a0b 100644 --- a/lua/copilot/highlight.lua +++ b/lua/copilot/highlight.lua @@ -1,3 +1,7 @@ +local logger = require("copilot.logger") +local config = require("copilot.config") +local nes_api = require("copilot.nes.api") + local M = { group = { CopilotAnnotation = "CopilotAnnotation", @@ -19,6 +23,16 @@ function M.setup() vim.api.nvim_set_hl(0, from_group, { link = to_group }) end end + + if config.nes.enabled then + local ok, err = pcall(function() + nes_api.set_hl() + end) + + if not ok then + logger.error("Error setting copilot-lsp highlights: ", err) + end + end end) end diff --git a/lua/copilot/keymaps/init.lua b/lua/copilot/keymaps/init.lua new file mode 100644 index 00000000..8355ba89 --- /dev/null +++ b/lua/copilot/keymaps/init.lua @@ -0,0 +1,89 @@ +local logger = require("copilot.logger") +local config = require("copilot.config") + +local M = {} + +local previous_keymaps = {} + +---@param mode string +---@param key string +---@param action function +---@param desc string +function M.register_keymap(mode, key, action, desc) + if not mode or not key or not action then + return + end + + vim.keymap.set(mode, key, function() + action() + end, { + desc = desc, + silent = true, + }) +end + +---@param mode string +---@param key string +---@param action function: boolean +---@param desc string +function M.register_keymap_with_passthrough(mode, key, action, desc) + if not mode or not key or not action then + return + end + + local keymap_key = mode .. ":" .. key + -- Save any existing mapping for this key + local existing = vim.fn.maparg(key, mode, false, true) + if existing and existing.rhs and existing.rhs ~= "" then + previous_keymaps[keymap_key] = existing.rhs + else + previous_keymaps[keymap_key] = nil + end + + vim.keymap.set(mode, key, function() + local action_ran = action() + if not action_ran then + -- If there was a previous mapping, execute it + local prev = previous_keymaps[keymap_key] + if prev then + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(prev, true, false, true), mode, true) + end + end + end, { + desc = desc, + silent = true, + }) +end + +---@param mode string +---@param key string|false +function M.unset_keymap_if_exists(mode, key) + if not key then + return + end + + local ok, err = pcall(vim.api.nvim_del_keymap, mode, key) + + if not ok then + local suggestion_keymaps = config.suggestion.keymap or {} + local panel_keymaps = config.panel.keymap or {} + local found = false + + for _, tbl in ipairs({ suggestion_keymaps, panel_keymaps }) do + for _, v in pairs(tbl) do + if v == key then + if found then + logger.error("Keymap " .. key .. " is used for two different actions, please review your configuration.") + return + else + found = true + end + end + end + end + + logger.error("Could not unset keymap for " .. mode .. " " .. key .. ": " .. err) + end +end + +return M diff --git a/lua/copilot/logger/init.lua b/lua/copilot/logger/init.lua index a438e2c2..7a36c791 100644 --- a/lua/copilot/logger/init.lua +++ b/lua/copilot/logger/init.lua @@ -171,6 +171,20 @@ function M.handle_lsp_progress(_, result, _) M.trace(string.format("LSP progress - token %s", result.token), result.value) end +-- Known noisy errors that we do not want to show as they seem to be out of our control +---@param msg string +---@return boolean +local function force_log_to_trace(msg) + if + msg:match(".*Request textDocument/copilotInlineEdit: AbortError: The operation was aborted.*") + or msg:match(".*AsyncCompletionManager.*Request errored with AbortError: The operation was aborted.*") + then + return true + end + + return false +end + function M.handle_log_lsp_messages(_, result, _) if not result then return @@ -179,7 +193,7 @@ function M.handle_log_lsp_messages(_, result, _) local message = string.format("LSP message: %s", result.message) local message_type = result.type --[[@as integer]] - if message_type == 1 then + if message_type == 1 and not force_log_to_trace(message) then M.error(message) elseif message_type == 2 then M.warn(message) diff --git a/lua/copilot/nes/api.lua b/lua/copilot/nes/api.lua new file mode 100644 index 00000000..3170166e --- /dev/null +++ b/lua/copilot/nes/api.lua @@ -0,0 +1,46 @@ +-- Abstraction to the copilot-lsp module + +local M = {} + +function M.nes_set_auto_trigger(value) + local config = require("copilot-lsp.config") + config.config.require("copilot-lsp.nes").auto_trigger = value +end + +function M.nes_lsp_on_init(client, au) + require("copilot-lsp.nes").lsp_on_init(client, au) +end + +function M.set_hl() + local util = require("copilot-lsp.util") + util.set_hl() +end + +---@param bufnr? integer +---@return boolean --if the cursor walked +function M.nes_walk_cursor_start_edit(bufnr) + return require("copilot-lsp.nes").walk_cursor_start_edit(bufnr) +end + +---@param bufnr? integer +---@return boolean --if the cursor walked +function M.nes_walk_cursor_end_edit(bufnr) + return require("copilot-lsp.nes").walk_cursor_end_edit(bufnr) +end + +---@param bufnr? integer +---@return boolean --if the nes was applied +function M.nes_apply_pending_nes(bufnr) + return require("copilot-lsp.nes").apply_pending_nes(bufnr) +end + +---@return boolean -- true if a suggestion was cleared, false if no suggestion existed +function M.nes_clear() + return require("copilot-lsp.nes").clear() +end + +function M.test() + require("copilot-lsp.nes") +end + +return M diff --git a/lua/copilot/nes/init.lua b/lua/copilot/nes/init.lua new file mode 100644 index 00000000..e7b80df7 --- /dev/null +++ b/lua/copilot/nes/init.lua @@ -0,0 +1,74 @@ +local config = require("copilot.config") +local logger = require("copilot.logger") +local keymaps = require("copilot.keymaps") +local nes_api = require("copilot.nes.api") + +local M = { + initialized = false, +} + +---@param goto_end boolean Whether to move the cursor to the end of the accepted suggestion +---@return boolean +local function accept_suggestion(goto_end) + local result = nes_api.nes_apply_pending_nes() + + if goto_end then + nes_api.nes_walk_cursor_end_edit() + end + + return result +end + +---@class NesKeymap +local function set_keymap(keymap) + keymaps.register_keymap_with_passthrough("n", keymap.accept_and_goto, function() + return accept_suggestion(true) + end, "[copilot] (nes) accept suggestion and go to end") + + keymaps.register_keymap_with_passthrough("n", keymap.accept, function() + return accept_suggestion(false) + end, "[copilot] (nes) accept suggestion") + + keymaps.register_keymap_with_passthrough("n", keymap.dismiss, function() + return nes_api.nes_clear() + end, "[copilot] (nes) dismiss suggestion") +end + +---@param keymap NesKeymap +local function unset_keymap(keymap) + keymaps.unset_keymap_if_exists("n", keymap.accept_and_goto) + keymaps.unset_keymap_if_exists("n", keymap.accept) + keymaps.unset_keymap_if_exists("n", keymap.dismiss) +end + +---@param lsp_client vim.lsp.Client +function M.setup(lsp_client) + if not config.nes.enabled then + return + end + + local au = vim.api.nvim_create_augroup("copilotlsp.init", { clear = true }) + + local ok, err = pcall(function() + nes_api.nes_lsp_on_init(lsp_client, au) + end) + + if ok then + logger.info("copilot-lsp nes loaded") + else + logger.error("copilot-lsp nes failed to load:", err) + end + + set_keymap(config.nes.keymap) + M.initialized = true +end + +function M.teardown() + if not M.initialized then + return + end + + unset_keymap(config.nes.keymap) +end + +return M diff --git a/lua/copilot/panel/init.lua b/lua/copilot/panel/init.lua index 6d373dbc..d6824b3f 100644 --- a/lua/copilot/panel/init.lua +++ b/lua/copilot/panel/init.lua @@ -5,6 +5,7 @@ local hl_group = require("copilot.highlight").group local util = require("copilot.util") local logger = require("copilot.logger") local utils = require("copilot.panel.utils") +local keymaps = require("copilot.keymaps") local M = { handlers = require("copilot.panel.handlers"), @@ -597,13 +598,13 @@ function M.teardown() return end - util.unset_keymap_if_exists("i", panel.keymap.open) + keymaps.unset_keymap_if_exists("i", panel.keymap.open) if M.keymaps_set then - M.unset_keymap_if_exists("n", panel.keymap.accept) - M.unset_keymap_if_exists("n", panel.keymap.jump_prev) - M.unset_keymap_if_exists("n", panel.keymap.jump_next) - M.unset_keymap_if_exists("n", panel.keymap.refresh) + keymaps.unset_keymap_if_exists("n", panel.keymap.accept) + keymaps.unset_keymap_if_exists("n", panel.keymap.jump_prev) + keymaps.unset_keymap_if_exists("n", panel.keymap.jump_next) + keymaps.unset_keymap_if_exists("n", panel.keymap.refresh) end panel:close() diff --git a/lua/copilot/suggestion/init.lua b/lua/copilot/suggestion/init.lua index 5396fc48..33a62708 100644 --- a/lua/copilot/suggestion/init.lua +++ b/lua/copilot/suggestion/init.lua @@ -7,6 +7,7 @@ local util = require("copilot.util") local logger = require("copilot.logger") local suggestion_util = require("copilot.suggestion.utils") local utils = require("copilot.client.utils") +local keymaps = require("copilot.keymaps") local M = {} @@ -119,72 +120,38 @@ local function reset_ctx(ctx) end local function set_keymap(keymap) - if keymap.accept then - vim.keymap.set("i", keymap.accept, function() - local ctx = get_ctx() - if (config.suggestion.trigger_on_accept and not ctx.first) or M.is_visible() then - M.accept() - else - local termcode = vim.api.nvim_replace_termcodes(keymap.accept, true, false, true) - vim.api.nvim_feedkeys(termcode, "n", true) - end - end, { - desc = "[copilot] accept suggestion", - silent = true, - }) - end + keymaps.register_keymap_with_passthrough("i", keymap.accept, function() + local ctx = get_ctx() + if (config.suggestion.trigger_on_accept and not ctx.first) or M.is_visible() then + M.accept() + return true + end - if keymap.accept_word then - vim.keymap.set("i", keymap.accept_word, M.accept_word, { - desc = "[copilot] accept suggestion (word)", - silent = true, - }) - end + return false + end, "[copilot] accept suggestion") - if keymap.accept_line then - vim.keymap.set("i", keymap.accept_line, M.accept_line, { - desc = "[copilot] accept suggestion (line)", - silent = true, - }) - end + keymaps.register_keymap("i", keymap.accept_word, M.accept_word, "[copilot] accept suggestion (word)") + keymaps.register_keymap("i", keymap.accept_line, M.accept_line, "[copilot] accept suggestion (line)") + keymaps.register_keymap("i", keymap.next, M.next, "[copilot] next suggestion") + keymaps.register_keymap("i", keymap.prev, M.prev, "[copilot] prev suggestion") - if keymap.next then - vim.keymap.set("i", keymap.next, M.next, { - desc = "[copilot] next suggestion", - silent = true, - }) - end - - if keymap.prev then - vim.keymap.set("i", keymap.prev, M.prev, { - desc = "[copilot] prev suggestion", - silent = true, - }) - end + keymaps.register_keymap_with_passthrough("i", keymap.dismiss, function() + if M.is_visible() then + M.dismiss() + return true + end - if keymap.dismiss then - vim.keymap.set("i", keymap.dismiss, function() - if M.is_visible() then - M.dismiss() - return "" - else - return keymap.dismiss - end - end, { - desc = "[copilot] dismiss suggestion", - expr = true, - silent = true, - }) - end + return false + end, "[copilot] dismiss suggestion") end local function unset_keymap(keymap) - util.unset_keymap_if_exists("i", keymap.accept) - util.unset_keymap_if_exists("i", keymap.accept_word) - util.unset_keymap_if_exists("i", keymap.accept_line) - util.unset_keymap_if_exists("i", keymap.next) - util.unset_keymap_if_exists("i", keymap.prev) - util.unset_keymap_if_exists("i", keymap.dismiss) + keymaps.unset_keymap_if_exists("i", keymap.accept) + keymaps.unset_keymap_if_exists("i", keymap.accept_word) + keymaps.unset_keymap_if_exists("i", keymap.accept_line) + keymaps.unset_keymap_if_exists("i", keymap.next) + keymaps.unset_keymap_if_exists("i", keymap.prev) + keymaps.unset_keymap_if_exists("i", keymap.dismiss) end local function stop_timer() diff --git a/lua/copilot/util.lua b/lua/copilot/util.lua index 0c06eb74..43219046 100644 --- a/lua/copilot/util.lua +++ b/lua/copilot/util.lua @@ -130,37 +130,6 @@ function M.strutf16len(str) end end ----@param mode string ----@param key string|false -function M.unset_keymap_if_exists(mode, key) - if not key then - return - end - - local ok, err = pcall(vim.api.nvim_del_keymap, mode, key) - - if not ok then - local suggestion_keymaps = config.suggestion.keymap or {} - local panel_keymaps = config.panel.keymap or {} - local found = false - - for _, tbl in ipairs({ suggestion_keymaps, panel_keymaps }) do - for _, v in pairs(tbl) do - if v == key then - if found then - logger.error("Keymap " .. key .. " is used for two different actions, please review your configuration.") - return - else - found = true - end - end - end - end - - logger.error("Could not unset keymap for " .. mode .. " " .. key .. ": " .. err) - end -end - ---@param bufnr integer ---@param status string function M.set_buffer_attach_status(bufnr, status) diff --git a/tests/screenshots/tests-test_keymaps.lua---keymaps()---passthrough-Esc---base-test-setting-highlight b/tests/screenshots/tests-test_keymaps.lua---keymaps()---passthrough-Esc---base-test-setting-highlight new file mode 100644 index 00000000..4e340d42 --- /dev/null +++ b/tests/screenshots/tests-test_keymaps.lua---keymaps()---passthrough-Esc---base-test-setting-highlight @@ -0,0 +1,23 @@ +--|---------|----- +01|123 +02|456 +03|~ +04|~ +05|~ +06|~ +07|~ +08|~ +09|", "noh", { desc = "general clear highlights" })]]) + child.lua([[ + require("copilot.keymaps").register_keymap_with_passthrough("n", "", function() + return true + end, "Passthrough Esc") + ]]) + child.type_keys("i123", "", "o456", "") + child.type_keys("/123", "") + + reference_screenshot(child.get_screenshot(), nil, { ignore_text = { 9, 10 }, ignore_attr = { 9, 10 } }) +end + +T["keymaps()"]["passthrough Esc - return false, will remove hl"] = function() + child.o.lines, child.o.columns = 10, 15 + child.lua([[vim.keymap.set("n", "", "noh", { desc = "general clear highlights" })]]) + child.lua([[ + require("copilot.keymaps").register_keymap_with_passthrough("n", "", function() + return false + end, "Passthrough Esc") + ]]) + child.type_keys("i123", "", "o456", "") + child.type_keys("/123", "") + child.type_keys("") + + reference_screenshot(child.get_screenshot(), nil, { ignore_text = { 9, 10 }, ignore_attr = { 9, 10 } }) +end + +T["keymaps()"]["passthrough Esc - return true, will not remove hl"] = function() + child.o.lines, child.o.columns = 10, 15 + child.lua([[vim.keymap.set("n", "", "noh", { desc = "general clear highlights" })]]) + child.lua([[ + require("copilot.keymaps").register_keymap_with_passthrough("n", "", function() + return true + end, "Passthrough Esc") + ]]) + child.type_keys("i123", "", "o456", "") + child.type_keys("/123", "") + child.type_keys("") + + reference_screenshot(child.get_screenshot(), nil, { ignore_text = { 9, 10 }, ignore_attr = { 9, 10 } }) +end + +return T diff --git a/tests/test_util.lua b/tests/test_util.lua new file mode 100644 index 00000000..cec787c3 --- /dev/null +++ b/tests/test_util.lua @@ -0,0 +1,30 @@ +local reference_screenshot = MiniTest.expect.reference_screenshot +local child_helper = require("tests.child_helper") +local child = child_helper.new_child_neovim("test_util") + +local T = MiniTest.new_set({ + hooks = { + pre_once = function() end, + pre_case = function() + child.run_pre_case(true) + child.bo.readonly = false + end, + post_once = child.stop, + }, +}) + +T["util()"] = MiniTest.new_set() + +T["util()"]["passthrough Esc passes original keymap"] = function() + child.o.lines, child.o.columns = 10, 15 + child.lua([[vim.keymap.set("n", "", "noh", { desc = "general clear highlights" })]]) + + child.config.suggestion = child.config.suggestion .. "auto_trigger = true," + child.configure_copilot() + child.type_keys("i123", "", "o456") + child.wait_for_suggestion() + + reference_screenshot(child.get_screenshot(), nil, { ignore_text = { 9, 10 }, ignore_attr = { 9, 10 } }) +end + +return T