diff --git a/lua/claudecode/diff.lua b/lua/claudecode/diff.lua index 79f8bb9d..e763d270 100644 --- a/lua/claudecode/diff.lua +++ b/lua/claudecode/diff.lua @@ -278,17 +278,20 @@ local function display_terminal_in_new_tab() apply_window_options(terminal_win, terminal_options) -- Set up autocmd to enter terminal mode when focusing this terminal window - vim.api.nvim_create_autocmd("BufEnter", { - buffer = terminal_bufnr, - group = get_autocmd_group(), - callback = function() - -- Only enter insert mode if we're in a terminal buffer and in normal mode - if vim.bo.buftype == "terminal" and vim.fn.mode() == "n" then - vim.cmd("startinsert") - end - end, - desc = "Auto-enter terminal mode when focusing Claude Code terminal", - }) + local terminal_auto_insert = not config or not config.terminal or config.terminal.auto_insert ~= false + if terminal_auto_insert then + vim.api.nvim_create_autocmd("BufEnter", { + buffer = terminal_bufnr, + group = get_autocmd_group(), + callback = function() + -- Only enter insert mode if we're in a terminal buffer and in normal mode + if vim.bo.buftype == "terminal" and vim.fn.mode() == "n" then + vim.cmd("startinsert") + end + end, + desc = "Auto-enter terminal mode when focusing Claude Code terminal", + }) + end local total_width = vim.o.columns local terminal_width = math.floor(total_width * split_width) @@ -596,17 +599,22 @@ local function setup_new_buffer( vim.b[new_buf].claudecode_diff_target_win = target_win_for_meta if config and config.diff_opts and config.diff_opts.keep_terminal_focus then + local auto_insert = not config.terminal or config.terminal.auto_insert ~= false vim.schedule(function() if terminal_win_in_new_tab and vim.api.nvim_win_is_valid(terminal_win_in_new_tab) then vim.api.nvim_set_current_win(terminal_win_in_new_tab) - vim.cmd("startinsert") + if auto_insert then + vim.cmd("startinsert") + end return end local terminal_win = find_claudecode_terminal_window() if terminal_win then vim.api.nvim_set_current_win(terminal_win) - vim.cmd("startinsert") + if auto_insert then + vim.cmd("startinsert") + end end end) end diff --git a/lua/claudecode/terminal.lua b/lua/claudecode/terminal.lua index fae0b30f..7424b848 100644 --- a/lua/claudecode/terminal.lua +++ b/lua/claudecode/terminal.lua @@ -17,6 +17,7 @@ local defaults = { external_terminal_cmd = nil, }, auto_close = true, + auto_insert = true, env = {}, snacks_win_opts = {}, -- Working directory control @@ -268,6 +269,7 @@ local function build_config(opts_override) split_side = effective_config.split_side, split_width_percentage = effective_config.split_width_percentage, auto_close = effective_config.auto_close, + auto_insert = effective_config.auto_insert, snacks_win_opts = effective_config.snacks_win_opts, cwd = resolved_cwd, } @@ -447,6 +449,12 @@ function M.setup(user_term_config, p_terminal_cmd, p_env) else vim.notify("claudecode.terminal.setup: Invalid value for auto_close: " .. tostring(v), vim.log.levels.WARN) end + elseif k == "auto_insert" then + if type(v) == "boolean" then + defaults.auto_insert = v + else + vim.notify("claudecode.terminal.setup: Invalid value for auto_insert: " .. tostring(v), vim.log.levels.WARN) + end elseif k == "snacks_win_opts" then if type(v) == "table" then defaults.snacks_win_opts = v diff --git a/lua/claudecode/terminal/native.lua b/lua/claudecode/terminal/native.lua index 7cd24dd5..a1a711df 100644 --- a/lua/claudecode/terminal/native.lua +++ b/lua/claudecode/terminal/native.lua @@ -54,7 +54,9 @@ local function open_terminal(cmd_string, env_table, effective_config, focus) if focus then -- Focus existing terminal: switch to terminal window and enter insert mode vim.api.nvim_set_current_win(winid) - vim.cmd("startinsert") + if effective_config.auto_insert ~= false then + vim.cmd("startinsert") + end end -- If focus=false, preserve user context by staying in current window return true @@ -137,7 +139,9 @@ local function open_terminal(cmd_string, env_table, effective_config, focus) if focus then -- Focus the terminal: switch to terminal window and enter insert mode vim.api.nvim_set_current_win(winid) - vim.cmd("startinsert") + if effective_config.auto_insert ~= false then + vim.cmd("startinsert") + end else -- Preserve user context: return to the window they were in before terminal creation vim.api.nvim_set_current_win(original_win) @@ -164,7 +168,9 @@ end local function focus_terminal() if is_valid() then vim.api.nvim_set_current_win(winid) - vim.cmd("startinsert") + if config.auto_insert ~= false then + vim.cmd("startinsert") + end end end @@ -237,7 +243,9 @@ local function show_hidden_terminal(effective_config, focus) if focus then -- Focus the terminal: switch to terminal window and enter insert mode vim.api.nvim_set_current_win(winid) - vim.cmd("startinsert") + if effective_config.auto_insert ~= false then + vim.cmd("startinsert") + end else -- Preserve user context: return to the window they were in before showing terminal vim.api.nvim_set_current_win(original_win) diff --git a/lua/claudecode/terminal/snacks.lua b/lua/claudecode/terminal/snacks.lua index 2b4c7c98..75722b83 100644 --- a/lua/claudecode/terminal/snacks.lua +++ b/lua/claudecode/terminal/snacks.lua @@ -48,11 +48,12 @@ end ---@return snacks.terminal.Opts opts Snacks terminal options with start_insert/auto_insert controlled by focus parameter local function build_opts(config, env_table, focus) focus = utils.normalize_focus(focus) + local should_insert = focus and config.auto_insert ~= false return { env = env_table, cwd = config.cwd, - start_insert = focus, - auto_insert = focus, + start_insert = should_insert, + auto_insert = should_insert, auto_close = false, win = vim.tbl_deep_extend("force", { position = config.split_side, @@ -100,12 +101,14 @@ function M.open(cmd_string, env_table, config, focus) terminal:toggle() if focus then terminal:focus() - local term_buf_id = terminal.buf - if term_buf_id and vim.api.nvim_buf_get_option(term_buf_id, "buftype") == "terminal" then - if terminal.win and vim.api.nvim_win_is_valid(terminal.win) then - vim.api.nvim_win_call(terminal.win, function() - vim.cmd("startinsert") - end) + if config.auto_insert ~= false then + local term_buf_id = terminal.buf + if term_buf_id and vim.api.nvim_buf_get_option(term_buf_id, "buftype") == "terminal" then + if terminal.win and vim.api.nvim_win_is_valid(terminal.win) then + vim.api.nvim_win_call(terminal.win, function() + vim.cmd("startinsert") + end) + end end end end @@ -113,13 +116,15 @@ function M.open(cmd_string, env_table, config, focus) -- Terminal is already visible if focus then terminal:focus() - local term_buf_id = terminal.buf - if term_buf_id and vim.api.nvim_buf_get_option(term_buf_id, "buftype") == "terminal" then - -- Check if window is valid before calling nvim_win_call - if terminal.win and vim.api.nvim_win_is_valid(terminal.win) then - vim.api.nvim_win_call(terminal.win, function() - vim.cmd("startinsert") - end) + if config.auto_insert ~= false then + local term_buf_id = terminal.buf + if term_buf_id and vim.api.nvim_buf_get_option(term_buf_id, "buftype") == "terminal" then + -- Check if window is valid before calling nvim_win_call + if terminal.win and vim.api.nvim_win_is_valid(terminal.win) then + vim.api.nvim_win_call(terminal.win, function() + vim.cmd("startinsert") + end) + end end end end @@ -226,11 +231,13 @@ function M.focus_toggle(cmd_string, env_table, config) else logger.debug("terminal", "Focus toggle: focusing terminal") vim.api.nvim_set_current_win(claude_term_neovim_win_id) - if terminal.buf and vim.api.nvim_buf_is_valid(terminal.buf) then - if vim.api.nvim_buf_get_option(terminal.buf, "buftype") == "terminal" then - vim.api.nvim_win_call(claude_term_neovim_win_id, function() - vim.cmd("startinsert") - end) + if config.auto_insert ~= false then + if terminal.buf and vim.api.nvim_buf_is_valid(terminal.buf) then + if vim.api.nvim_buf_get_option(terminal.buf, "buftype") == "terminal" then + vim.api.nvim_win_call(claude_term_neovim_win_id, function() + vim.cmd("startinsert") + end) + end end end end diff --git a/tests/unit/terminal_spec.lua b/tests/unit/terminal_spec.lua index cd61b70a..abd228c3 100644 --- a/tests/unit/terminal_spec.lua +++ b/tests/unit/terminal_spec.lua @@ -420,6 +420,28 @@ describe("claudecode.terminal (wrapper for Snacks.nvim)", function() ) end) + it("should store valid auto_insert setting", function() + terminal_wrapper.setup({ auto_insert = false }) + terminal_wrapper.open() + local config_arg = mock_snacks_provider.open:get_call(1).refs[3] + assert.are.equal(false, config_arg.auto_insert) + end) + + it("should default auto_insert to true", function() + terminal_wrapper.setup({}) + terminal_wrapper.open() + local config_arg = mock_snacks_provider.open:get_call(1).refs[3] + assert.are.equal(true, config_arg.auto_insert) + end) + + it("should ignore invalid auto_insert and use default", function() + terminal_wrapper.setup({ auto_insert = "invalid" }) + terminal_wrapper.open() + local config_arg = mock_snacks_provider.open:get_call(1).refs[3] + assert.are.equal(true, config_arg.auto_insert) + vim.notify:was_called_with(spy.matching.string.match("Invalid value for auto_insert"), vim.log.levels.WARN) + end) + it("should use defaults if user_term_config is not a table and notify", function() terminal_wrapper.setup("not_a_table") terminal_wrapper.open()