Skip to content

Commit a021225

Browse files
authored
Merge pull request #21 from kylesnowschwartz/kyle/start-terminal-in-normal-mode
Add option to start terminal in normal mode
2 parents 91b38f2 + 6178dbe commit a021225

5 files changed

Lines changed: 88 additions & 10 deletions

File tree

doc/claude-code.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ default configuration:
9393
split_ratio = 0.3, -- Percentage of screen for the terminal window (height or width)
9494
position = "botright", -- Position of the window: "botright", "topleft", "vertical", "vsplit", etc.
9595
enter_insert = true, -- Whether to enter insert mode when opening Claude Code
96+
start_in_normal_mode = false, -- Whether to start in normal mode instead of insert mode
9697
hide_numbers = true, -- Hide line numbers in the terminal window
9798
hide_signcolumn = true, -- Hide the sign column in the terminal window
9899
},

lua/claude-code/config.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local M = {}
1111
-- @field split_ratio number Percentage of screen for the terminal window (height for horizontal, width for vertical splits)
1212
-- @field position string Position of the window: "botright", "topleft", "vertical", etc.
1313
-- @field enter_insert boolean Whether to enter insert mode when opening Claude Code
14+
-- @field start_in_normal_mode boolean Whether to start in normal mode instead of insert mode when opening Claude Code
1415
-- @field hide_numbers boolean Hide line numbers in the terminal window
1516
-- @field hide_signcolumn boolean Hide the sign column in the terminal window
1617

@@ -63,6 +64,7 @@ M.default_config = {
6364
height_ratio = 0.3, -- DEPRECATED: Use split_ratio instead
6465
position = 'botright', -- Position of the window: "botright", "topleft", "vertical", etc.
6566
enter_insert = true, -- Whether to enter insert mode when opening Claude Code
67+
start_in_normal_mode = false, -- Whether to start in normal mode instead of insert mode
6668
hide_numbers = true, -- Hide line numbers in the terminal window
6769
hide_signcolumn = true, -- Hide the sign column in the terminal window
6870
},
@@ -129,6 +131,10 @@ local function validate_config(config)
129131
return false, 'window.enter_insert must be a boolean'
130132
end
131133

134+
if type(config.window.start_in_normal_mode) ~= 'boolean' then
135+
return false, 'window.start_in_normal_mode must be a boolean'
136+
end
137+
132138
if type(config.window.hide_numbers) ~= 'boolean' then
133139
return false, 'window.hide_numbers must be a boolean'
134140
end

lua/claude-code/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ M.claude_code = terminal.terminal
4141
--- Force insert mode when entering the Claude Code window
4242
--- This is a public function used in keymaps
4343
function M.force_insert_mode()
44-
terminal.force_insert_mode(M)
44+
terminal.force_insert_mode(M, M.config)
4545
end
4646

4747
--- Toggle the Claude Code terminal window

lua/claude-code/terminal.lua

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,16 @@ end
4747

4848
--- Set up function to force insert mode when entering the Claude Code window
4949
--- @param claude_code table The main plugin module
50-
function M.force_insert_mode(claude_code)
50+
--- @param config table The plugin configuration
51+
function M.force_insert_mode(claude_code, config)
5152
local bufnr = claude_code.claude_code.bufnr
5253
if bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.fn.bufnr '%' == bufnr then
5354
-- Only enter insert mode if we're in the terminal buffer and not already in insert mode
55+
-- and not configured to stay in normal mode
56+
if config.window.start_in_normal_mode then
57+
return
58+
end
59+
5460
local mode = vim.api.nvim_get_mode().mode
5561
if vim.bo.buftype == 'terminal' and mode ~= 't' and mode ~= 'i' then
5662
vim.cmd 'silent! stopinsert'
@@ -79,10 +85,12 @@ function M.toggle(claude_code, config, git)
7985
else
8086
-- Claude Code buffer exists but is not visible, open it in a split
8187
create_split(config.window.position, config, bufnr)
82-
-- Force insert mode more aggressively
83-
vim.schedule(function()
84-
vim.cmd 'stopinsert | startinsert'
85-
end)
88+
-- Force insert mode more aggressively unless configured to start in normal mode
89+
if not config.window.start_in_normal_mode then
90+
vim.schedule(function()
91+
vim.cmd 'stopinsert | startinsert'
92+
end)
93+
end
8694
end
8795
else
8896
-- Claude Code is not running, start it in a new split
@@ -113,8 +121,8 @@ function M.toggle(claude_code, config, git)
113121
-- Store buffer number for future reference
114122
claude_code.claude_code.bufnr = vim.fn.bufnr '%'
115123

116-
-- Automatically enter insert mode in terminal
117-
if config.window.enter_insert then
124+
-- Automatically enter insert mode in terminal unless configured to start in normal mode
125+
if config.window.enter_insert and not config.window.start_in_normal_mode then
118126
vim.cmd 'startinsert'
119127
end
120128
end

tests/spec/terminal_spec.lua

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ describe('terminal module', function()
7272
position = 'botright',
7373
split_ratio = 0.5,
7474
enter_insert = true,
75+
start_in_normal_mode = false,
7576
hide_numbers = true,
7677
hide_signcolumn = true,
7778
},
@@ -196,6 +197,58 @@ describe('terminal module', function()
196197
end)
197198
end)
198199

200+
describe('start_in_normal_mode option', function()
201+
it('should not enter insert mode when start_in_normal_mode is true', function()
202+
-- Claude Code is not running (bufnr is nil)
203+
claude_code.claude_code.bufnr = nil
204+
205+
-- Set start_in_normal_mode to true
206+
config.window.start_in_normal_mode = true
207+
208+
-- Call toggle
209+
terminal.toggle(claude_code, config, git)
210+
211+
-- Check if startinsert was NOT called
212+
local startinsert_found = false
213+
for _, cmd in ipairs(vim_cmd_calls) do
214+
if cmd == 'startinsert' then
215+
startinsert_found = true
216+
break
217+
end
218+
end
219+
220+
assert.is_false(
221+
startinsert_found,
222+
'startinsert should not be called when start_in_normal_mode is true'
223+
)
224+
end)
225+
226+
it('should enter insert mode when start_in_normal_mode is false', function()
227+
-- Claude Code is not running (bufnr is nil)
228+
claude_code.claude_code.bufnr = nil
229+
230+
-- Set start_in_normal_mode to false
231+
config.window.start_in_normal_mode = false
232+
233+
-- Call toggle
234+
terminal.toggle(claude_code, config, git)
235+
236+
-- Check if startinsert was called
237+
local startinsert_found = false
238+
for _, cmd in ipairs(vim_cmd_calls) do
239+
if cmd == 'startinsert' then
240+
startinsert_found = true
241+
break
242+
end
243+
end
244+
245+
assert.is_true(
246+
startinsert_found,
247+
'startinsert should be called when start_in_normal_mode is false'
248+
)
249+
end)
250+
end)
251+
199252
describe('force_insert_mode', function()
200253
it('should check insert mode conditions in terminal buffer', function()
201254
-- For this test, we'll just verify that the function can be called without error
@@ -206,7 +259,12 @@ describe('terminal module', function()
206259
bufnr = 1,
207260
},
208261
}
209-
terminal.force_insert_mode(mock_claude_code)
262+
local mock_config = {
263+
window = {
264+
start_in_normal_mode = false,
265+
},
266+
}
267+
terminal.force_insert_mode(mock_claude_code, mock_config)
210268
end)
211269

212270
assert.is_true(success, 'Force insert mode function should run without error')
@@ -221,7 +279,12 @@ describe('terminal module', function()
221279
bufnr = 2,
222280
},
223281
}
224-
terminal.force_insert_mode(mock_claude_code)
282+
local mock_config = {
283+
window = {
284+
start_in_normal_mode = false,
285+
},
286+
}
287+
terminal.force_insert_mode(mock_claude_code, mock_config)
225288
end)
226289

227290
assert.is_true(success, 'Force insert mode function should run without error')

0 commit comments

Comments
 (0)