diff --git a/lua/fzf-lua/actions.lua b/lua/fzf-lua/actions.lua index 7a053845..92a36bba 100644 --- a/lua/fzf-lua/actions.lua +++ b/lua/fzf-lua/actions.lua @@ -1078,6 +1078,10 @@ M.complete = function(selected, opts) newline = line:sub(1, col) .. selected[1] .. after newcol = col + #selected[1] end + if opts.__CTX.mode == "t" and vim.bo[opts.__CTX.bufnr].buftype == "terminal" then + vim.api.nvim_chan_send(vim.bo.channel, newline) + return + end vim.api.nvim_set_current_line(newline or opts.__CTX.line) vim.api.nvim_win_set_cursor(0, { opts.__CTX.cursor[1], newcol or col }) if opts.__CTX.mode == "i" then diff --git a/lua/fzf-lua/fzf.lua b/lua/fzf-lua/fzf.lua index 8e3fca84..02a57bd6 100644 --- a/lua/fzf-lua/fzf.lua +++ b/lua/fzf-lua/fzf.lua @@ -222,6 +222,10 @@ function M.raw_fzf(contents, fzf_cli_args, opts) vim.keymap.set("t", "", "", { buffer = 0 }) end + -- local fzf_bufnr = vim.api.nvim_get_current_buf() + -- vim.api.nvim_create_autocmd("TermOpen", { once = true, buffer = fzf_bufnr, command = "startinsert" }) + -- vim.api.nvim_create_autocmd("TermOpen", + -- { once = true, buffer = fzf_bufnr, callback = function() utils.ensure_startinsert(fzf_bufnr) end }) -- A more robust way of entering TERMINAL mode "t". We had quite a few issues -- sending `feedkeys|startinsert` after the term job is started, this approach -- seems more consistent as it triggers when entering terminal normal mode "nt" @@ -333,14 +337,8 @@ function M.raw_fzf(contents, fzf_cli_args, opts) -- fzf-tmux spawns outside neovim, don't set filetype/insert mode if not opts.is_fzf_tmux then vim.bo.filetype = "fzf" - -- See note in "ModeChanged" above - if vim.api.nvim_get_mode().mode == "t" then - -- Called from another fzf-win most likely - utils.feed_keys_termcodes("i") - else - vim.cmd [[startinsert]] - end + utils.ensure_startinsert() end return coroutine.yield() diff --git a/lua/fzf-lua/utils.lua b/lua/fzf-lua/utils.lua index 59b71515..9603fbff 100644 --- a/lua/fzf-lua/utils.lua +++ b/lua/fzf-lua/utils.lua @@ -1329,6 +1329,28 @@ function M.setmetatable__gc(t, mt) return setmetatable(t, mt) end +---@param bufnr integer? +---@param retry integer? +---@param timeout integer? +function M.ensure_startinsert(bufnr, retry, timeout) + bufnr = bufnr or vim.api.nvim_get_current_buf() + local function ensure_startinsert(_retry, _timeout) + if _retry == 0 then return end + -- abort for some reason we switch to another buffer + if vim.api.nvim_get_current_buf() ~= bufnr then return end + if vim.api.nvim_get_mode().mode ~= "t" then + vim.cmd [[startinsert]] + return + end + -- Called from another fzf-win most likely + -- don't startinsert until we enter new terminal mode + return vim.defer_fn(function() + return ensure_startinsert(_retry - 1, math.min(100, _timeout * 2)) + end, _timeout) + end + return ensure_startinsert(retry or 5, timeout or 10) +end + --- Checks if treesitter parser for language is installed ---@param lang string function M.has_ts_parser(lang) diff --git a/tests/file/ui_spec.lua b/tests/file/ui_spec.lua index 9b88e27c..408f73f8 100644 --- a/tests/file/ui_spec.lua +++ b/tests/file/ui_spec.lua @@ -220,4 +220,25 @@ T["files()"]["preview should work after chdir #1864"] = function() child.expect_screen_lines(screen_opts) end +T["files()"]["perioldly reset mode"] = function() + child.cmd [[exe 'au TermOpen * startinsert' | term]] + sleep(10) + child.lua [=[ + FzfLua.files { + cwd_prompt = false, + fzf_opts = { ["--no-info"] = "", ["--info"] = false }, + query = "foo", + } + ]=] + child.wait_until(function() return child.lua_get([[_G._fzf_load_called]]) == true end) + -- child.expect_screen_lines({ start_line = 1, end_line = 3 }) + -- print("\n") + -- print(child.get_screen_lines({ start_line = 1, end_line = 3 })) + child.assert_screen_lines([[ + ╭─────────────────── Files h ────────────────────╮ + │> foo │ + │──────────────────────────────────────────────── │ + ]], { start_line = 3, end_line = 5 }) +end + return T