From 7d0c5ac74f8bae8d8bc7180cd1486d03e88c941d Mon Sep 17 00:00:00 2001 From: Alejandro Espinoza Date: Fri, 19 Jun 2026 14:16:57 -0600 Subject: [PATCH 1/3] fix: harden WSL terminal key protocol and ColorScheme debounce Re-apply kitty protocol disable after Neovim startup, detect WSL GUI terminals with generic TERM, debounce double-Enter on :ColorScheme, and suppress diagnostics during cmdline completion. Co-authored-by: Cursor --- init.lua | 22 +----------------- lua/config/autocmds.lua | 42 +++++++++++++++++++++++++++++++--- lua/config/term.lua | 50 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 24 deletions(-) create mode 100644 lua/config/term.lua diff --git a/init.lua b/init.lua index 6a6b555..0d65b3a 100644 --- a/init.lua +++ b/init.lua @@ -1,24 +1,4 @@ --- Disable Kitty keyboard protocol to avoid double Enter/Tab/Backspace on --- Kitty and Alacritty (common on WSL GUI terminals with Neovim 0.11+). -local function kitty_protocol_terminal() - local term = vim.env.TERM or "" - if term:match("kitty") or term:match("alacritty") then - return true - end - return vim.env.KITTY_WINDOW_ID ~= nil or vim.env.ALACRITTY_WINDOW_ID ~= nil -end - -if kitty_protocol_terminal() then - vim.api.nvim_create_autocmd({ "VimEnter", "VimLeavePre" }, { - callback = function(ev) - if ev.event == "VimEnter" then - io.stdout:write("\027[>1u") - else - io.stdout:write("\027[<1u") - end - end, - }) -end +require("config.term").setup() -- bootstrap lazy.nvim, LazyVim and your plugins require("config.lazy") diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua index 3d140ed..582cfac 100644 --- a/lua/config/autocmds.lua +++ b/lua/config/autocmds.lua @@ -102,15 +102,51 @@ vim.api.nvim_create_user_command( { desc = "show hi name" } ) +local in_cmdline = false +local colorscheme_picker_opening = false + local function open_colorscheme_picker() - -- Defer past cmdline teardown; keymaps don't need this, :commands do. - vim.schedule(function() + -- Double Enter (kitty protocol) can invoke the command twice and toggle-close. + if colorscheme_picker_opening then + return + end + colorscheme_picker_opening = true + + vim.defer_fn(function() + colorscheme_picker_opening = false + + local ok, picker_api = pcall(require, "snacks.picker") + if not ok then + return + end + + if picker_api.get({ source = "colorschemes" })[1] then + return + end + require("snacks").picker.colorschemes({ auto_close = false }) - end) + end, 100) end +vim.api.nvim_create_autocmd("CmdlineEnter", { + callback = function() + in_cmdline = true + pcall(vim.diagnostic.hide) + end, +}) + +vim.api.nvim_create_autocmd({ "CmdlineLeave", "CmdlineAbort" }, { + callback = function() + in_cmdline = false + end, +}) + vim.api.nvim_create_autocmd("CursorHold", { callback = function() + if in_cmdline then + return + end + -- Cmdline/wildmenu: avoid diagnostic float stealing focus (WSL tab completion jump). local mode = vim.api.nvim_get_mode().mode if mode:find("^c") or vim.fn.getcmdwintype() ~= "" then diff --git a/lua/config/term.lua b/lua/config/term.lua new file mode 100644 index 0000000..cfd264c --- /dev/null +++ b/lua/config/term.lua @@ -0,0 +1,50 @@ +local M = {} + +--- Kitty/Alacritty on WSL often reports a generic $TERM; detect via env too. +function M.needs_key_protocol_fix() + if vim.env.KITTY_WINDOW_ID or vim.env.ALACRITTY_WINDOW_ID then + return true + end + + local term = vim.env.TERM or "" + if term:match("kitty") or term:match("alacritty") then + return true + end + + if vim.env.WSL_DISTRO_NAME and (vim.env.WAYLAND_DISPLAY or vim.env.DISPLAY) then + return true + end + + return false +end + +--- Neovim 0.11+ enables CSI-u / kitty protocol after startup; disable it. +function M.disable_key_protocol() + io.stdout:write("\027[>0u\027[<1u") + io.stdout:flush() +end + +function M.setup() + if not M.needs_key_protocol_fix() then + return + end + + M.disable_key_protocol() + + vim.api.nvim_create_autocmd("VimEnter", { + callback = function() + -- Neovim may re-enable the protocol after VimEnter; apply twice to be sure. + vim.defer_fn(M.disable_key_protocol, 0) + vim.defer_fn(M.disable_key_protocol, 100) + end, + }) + + vim.api.nvim_create_autocmd("VimLeavePre", { + callback = function() + io.stdout:write("\027[<1u") + io.stdout:flush() + end, + }) +end + +return M From 17a1ca294d0c5f91ddb76c7e3b8fce49097631a2 Mon Sep 17 00:00:00 2001 From: Alejandro Espinoza Date: Fri, 19 Jun 2026 14:21:13 -0600 Subject: [PATCH 2/3] fix: drop CmdlineAbort autocmd for older Neovim versions Co-authored-by: Cursor --- lua/config/autocmds.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua index 582cfac..a3015bd 100644 --- a/lua/config/autocmds.lua +++ b/lua/config/autocmds.lua @@ -135,7 +135,7 @@ vim.api.nvim_create_autocmd("CmdlineEnter", { end, }) -vim.api.nvim_create_autocmd({ "CmdlineLeave", "CmdlineAbort" }, { +vim.api.nvim_create_autocmd("CmdlineLeave", { callback = function() in_cmdline = false end, From a71f62788c0756e940c2933195b23ede19b3c269 Mon Sep 17 00:00:00 2001 From: Alejandro Espinoza Date: Fri, 19 Jun 2026 14:34:26 -0600 Subject: [PATCH 3/3] fix: use kitty protocol flags=1 for Neovim 0.12 double Tab/BS Neovim 0.12.0-dev enables flags=3 (key-up reporting), which makes Enter/Tab/Backspace fire twice in Kitty/Alacritty on WSL. Push flags=1 after startup instead of trying to pop the protocol stack. Co-authored-by: Cursor --- lua/config/autocmds.lua | 4 ++-- lua/config/term.lua | 33 ++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua index a3015bd..e5c7bfa 100644 --- a/lua/config/autocmds.lua +++ b/lua/config/autocmds.lua @@ -115,7 +115,7 @@ local function open_colorscheme_picker() vim.defer_fn(function() colorscheme_picker_opening = false - local ok, picker_api = pcall(require, "snacks.picker") + local ok, picker_api = pcall(require, 'snacks.picker') if not ok then return end @@ -158,7 +158,7 @@ vim.api.nvim_create_autocmd("CursorHold", { return end - local ok, picker = pcall(require, "snacks.picker") + local ok, picker = pcall(require, 'snacks.picker') if ok and #picker.get() > 0 then return end diff --git a/lua/config/term.lua b/lua/config/term.lua index cfd264c..3c75269 100644 --- a/lua/config/term.lua +++ b/lua/config/term.lua @@ -2,6 +2,10 @@ local M = {} --- Kitty/Alacritty on WSL often reports a generic $TERM; detect via env too. function M.needs_key_protocol_fix() + if vim.env.NVIM_DISABLE_KEY_PROTOCOL == "1" then + return true + end + if vim.env.KITTY_WINDOW_ID or vim.env.ALACRITTY_WINDOW_ID then return true end @@ -18,27 +22,38 @@ function M.needs_key_protocol_fix() return false end ---- Neovim 0.11+ enables CSI-u / kitty protocol after startup; disable it. -function M.disable_key_protocol() - io.stdout:write("\027[>0u\027[<1u") +--- Neovim 0.12+ enables kitty protocol with flags=3 (disambiguate + report key-up). +--- That makes Enter/Tab/Backspace fire on keydown and keyup in Kitty/Alacritty (#31806). +--- Push flags=1 (disambiguate only) after Neovim starts so each keypress fires once. +function M.fix_key_protocol() + io.stdout:write("\027[>1u") io.stdout:flush() end +local function schedule_fix() + for _, delay in ipairs({ 0, 50, 150, 500 }) do + vim.defer_fn(M.fix_key_protocol, delay) + end +end + function M.setup() if not M.needs_key_protocol_fix() then return end - M.disable_key_protocol() + schedule_fix() vim.api.nvim_create_autocmd("VimEnter", { - callback = function() - -- Neovim may re-enable the protocol after VimEnter; apply twice to be sure. - vim.defer_fn(M.disable_key_protocol, 0) - vim.defer_fn(M.disable_key_protocol, 100) - end, + callback = schedule_fix, }) + if vim.fn.exists("##UIEnter") == 1 then + vim.api.nvim_create_autocmd("UIEnter", { + once = true, + callback = schedule_fix, + }) + end + vim.api.nvim_create_autocmd("VimLeavePre", { callback = function() io.stdout:write("\027[<1u")