From 2e0a5a596aeb3d3f31a106604bf9274288c92989 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 7 Aug 2026 07:44:19 -0400 Subject: [PATCH] fix(terminal): spawn in effective CWD #41211 Problem: `:terminal` does not respect the invocation-time CWD. This wasn't noticeable with `:lcd` because the window-local CWD gets applied to the new terminal buffer. But it is noticeable with `:bcd`. Solution: Specify `cwd` in the job spec. --- runtime/lua/vim/_core/ex_cmd.lua | 13 ++++++++----- test/functional/terminal/ex_terminal_spec.lua | 13 +++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/runtime/lua/vim/_core/ex_cmd.lua b/runtime/lua/vim/_core/ex_cmd.lua index e626b256a9..5187dade61 100644 --- a/runtime/lua/vim/_core/ex_cmd.lua +++ b/runtime/lua/vim/_core/ex_cmd.lua @@ -248,17 +248,20 @@ function M.ex_terminal(eap, shell_argv) or smods.horizontal or smods.vertical + -- Use the invocation-time CWD, before creating a new buffer. + local opts = { term = true, cwd = vim.fn.getcwd() } + if has_mods then vim.cmd.new { mods = smods } else vim.cmd.enew { bang = eap.bang } end - if shell_argv then -- No `cmd`, run 'shell'. - vim.fn.jobstart(shell_argv, { term = true }) - else -- Run [cmd] in 'shell'. - vim.fn.jobstart(eap.args, { term = true }) - end + vim.fn.jobstart( + shell_argv and shell_argv -- No `cmd`, run 'shell'. + or eap.args, -- Run [cmd] in 'shell'. + opts + ) end function M.ex_uptime() diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 96f62a4883..95e2079aef 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -13,7 +13,6 @@ local fn = n.fn local api = n.api local exec_lua = n.exec_lua local retry = t.retry -local pcall_err = t.pcall_err local ok = t.ok local command = n.command local skip = t.skip @@ -268,6 +267,16 @@ local function test_terminal_with_fake_shell(backslash) ]]) end) + it('spawns in CWD effective at time of invocation', function() + command('terminal') + local dir = fn.bufname():match('^term://(.-)//') + command('bcd ..') -- :terminal should use this CWD. + command('terminal') + local parent = fn.bufname():match('^term://(.-)//') + neq(dir, parent) + eq(fn.fnamemodify(dir, ':h'), parent) + end) + it('allows quotes and slashes', function() command([[terminal echo 'hello' \ "world"]]) screen:expect([[ @@ -360,7 +369,7 @@ local function test_terminal_with_fake_shell(backslash) end) end -describe(':terminal (with fake shell)', function() +describe(':terminal (fake shell)', function() test_terminal_with_fake_shell(false) if is_os('win') then describe("when 'shell' uses backslashes", function()