mirror of
https://github.com/neovim/neovim.git
synced 2026-08-14 11:29:31 +00:00
Problem: :bcd (buffer-local directory) is not preserved after `nvim_open_win` or `nvim_win_set_buf` Analysis: set_curbuf() ends with update_cwd(), which falls back to os_chdir(globaldir) when the target buffer has no b_localdir. Solution: Pass kCtxKeepCwd to ctx_switch().
653 lines
22 KiB
Lua
653 lines
22 KiB
Lua
-- Specs for :cd, :tcd, :lcd and getcwd()
|
|
|
|
local t = require('test.testutil')
|
|
local n = require('test.functional.testnvim')()
|
|
|
|
local describe, it, before_each, after_each = t.describe, t.it, t.before_each, t.after_each
|
|
local eq = t.eq
|
|
local pcall_err = t.pcall_err
|
|
local call = n.call
|
|
local clear = n.clear
|
|
local command = n.command
|
|
local pathsep = n.get_pathsep()
|
|
local skip = t.skip
|
|
local is_os = t.is_os
|
|
local mkdir = t.mkdir
|
|
|
|
-- These directories will be created for testing
|
|
local directories = {
|
|
tab = 'Xtest-functional-ex_cmds-cd_spec.tab', -- Tab
|
|
window = 'Xtest-functional-ex_cmds-cd_spec.window', -- Window
|
|
buffer = 'Xtest-functional-ex_cmds-cd_spec.buffer', -- Buffer
|
|
global = 'Xtest-functional-ex_cmds-cd_spec.global', -- New global
|
|
}
|
|
|
|
local tmpfile = 'Xtest-functional-ex_cmds-cd_spec-tmpfile'
|
|
local startdir ---@type string `getcwd()` at session start (set by `before_each`)
|
|
|
|
local function join(...)
|
|
return table.concat({ ... }, pathsep)
|
|
end
|
|
|
|
-- Get the current working directory.
|
|
local cwd = function(...)
|
|
return call('getcwd', ...)
|
|
end -- effective working dir
|
|
local wcwd = function()
|
|
return cwd(0)
|
|
end -- window dir
|
|
local bcwd = function()
|
|
return cwd(-1, -1, 0)
|
|
end -- buffer dir
|
|
local tcwd = function()
|
|
return cwd(-1, 0)
|
|
end -- tab dir
|
|
|
|
-- Same, except these tell us if there is a working directory at all
|
|
local lwd = function(...)
|
|
return call('haslocaldir', ...)
|
|
end -- effective working dir
|
|
local wlwd = function()
|
|
return lwd(0)
|
|
end -- window dir
|
|
local blwd = function()
|
|
return lwd(-1, -1, 0)
|
|
end -- buffer dir
|
|
local tlwd = function()
|
|
return lwd(-1, 0)
|
|
end -- tab dir
|
|
--local glwd = function() return eval('haslocaldir(-1, -1)') end -- global dir
|
|
|
|
before_each(function()
|
|
clear()
|
|
for _, d in pairs(directories) do
|
|
mkdir(d)
|
|
end
|
|
startdir = cwd()
|
|
end)
|
|
|
|
after_each(function()
|
|
for _, d in pairs(directories) do
|
|
n.rmdir(d)
|
|
end
|
|
end)
|
|
|
|
-- Test both the `cd` and `chdir` variants
|
|
for _, cmd in ipairs { 'cd', 'chdir' } do
|
|
describe(':' .. cmd, function()
|
|
describe('using explicit scope', function()
|
|
it('for window', function()
|
|
local globalDir = startdir
|
|
local globalwin = call('winnr')
|
|
local tabnr = call('tabpagenr')
|
|
|
|
-- Everything matches globalDir to start
|
|
eq(globalDir, cwd(globalwin))
|
|
eq(globalDir, cwd(globalwin, tabnr))
|
|
eq(0, lwd(globalwin))
|
|
eq(0, lwd(globalwin, tabnr))
|
|
|
|
command('bot split')
|
|
local localwin = call('winnr')
|
|
-- Initial window is still using globalDir
|
|
eq(globalDir, cwd(localwin))
|
|
eq(globalDir, cwd(localwin, tabnr))
|
|
eq(0, lwd(globalwin))
|
|
eq(0, lwd(globalwin, tabnr))
|
|
|
|
command('silent l' .. cmd .. ' ' .. directories.window)
|
|
-- From window with local dir, the original window
|
|
-- is still reporting the global dir
|
|
eq(globalDir, cwd(globalwin))
|
|
eq(globalDir, cwd(globalwin, tabnr))
|
|
eq(0, lwd(globalwin))
|
|
eq(0, lwd(globalwin, tabnr))
|
|
|
|
-- Window with local dir reports as such
|
|
eq(globalDir .. pathsep .. directories.window, cwd(localwin))
|
|
eq(globalDir .. pathsep .. directories.window, cwd(localwin, tabnr))
|
|
eq(1, lwd(localwin))
|
|
eq(1, lwd(localwin, tabnr))
|
|
|
|
command('tabnew')
|
|
-- From new tabpage, original window reports global dir
|
|
eq(globalDir, cwd(globalwin, tabnr))
|
|
eq(0, lwd(globalwin, tabnr))
|
|
|
|
-- From new tabpage, local window reports as such
|
|
eq(globalDir .. pathsep .. directories.window, cwd(localwin, tabnr))
|
|
eq(1, lwd(localwin, tabnr))
|
|
end)
|
|
|
|
it('for tabpage', function()
|
|
local globalDir = startdir
|
|
local globaltab = call('tabpagenr')
|
|
|
|
-- Everything matches globalDir to start
|
|
eq(globalDir, cwd(-1, 0))
|
|
eq(globalDir, cwd(-1, globaltab))
|
|
eq(0, lwd(-1, 0))
|
|
eq(0, lwd(-1, globaltab))
|
|
|
|
command('tabnew')
|
|
command('silent t' .. cmd .. ' ' .. directories.tab)
|
|
local localtab = call('tabpagenr')
|
|
|
|
-- From local tabpage, original tab reports globalDir
|
|
eq(globalDir, cwd(-1, globaltab))
|
|
eq(0, lwd(-1, globaltab))
|
|
|
|
-- new tab reports local
|
|
eq(globalDir .. pathsep .. directories.tab, cwd(-1, 0))
|
|
eq(globalDir .. pathsep .. directories.tab, cwd(-1, localtab))
|
|
eq(1, lwd(-1, 0))
|
|
eq(1, lwd(-1, localtab))
|
|
|
|
command('tabnext')
|
|
-- From original tabpage, local reports as such
|
|
eq(globalDir .. pathsep .. directories.tab, cwd(-1, localtab))
|
|
eq(1, lwd(-1, localtab))
|
|
end)
|
|
|
|
it('for buffer', function()
|
|
local globalDir = startdir
|
|
-- Create two buffers
|
|
command(('e %s1'):format(tmpfile))
|
|
command(('e %s%s%s2'):format(directories.buffer, pathsep, tmpfile))
|
|
|
|
-- Initially matches globalDir
|
|
eq(globalDir, cwd())
|
|
eq(0, lwd())
|
|
|
|
-- Change buffer-local directory to subdirectory
|
|
command('bcd ' .. directories.buffer)
|
|
eq(join(globalDir, directories.buffer), cwd())
|
|
eq(1, blwd())
|
|
|
|
-- ":bcd -" changes to the previous directory, still buffer-scoped.
|
|
command('bcd -')
|
|
eq(globalDir, cwd())
|
|
eq(1, blwd())
|
|
command('bcd -')
|
|
eq(join(globalDir, directories.buffer), cwd())
|
|
eq(1, blwd())
|
|
|
|
-- Verify Other buffer is unchanged
|
|
command('b# ')
|
|
eq(globalDir, cwd())
|
|
eq(0, blwd())
|
|
|
|
-- A new buffer created with :edit does not inherit the buffer-local directory.
|
|
command('b# ')
|
|
command(('e %s3'):format(tmpfile))
|
|
eq(0, blwd())
|
|
eq(globalDir, cwd())
|
|
|
|
-- getcwd({winnr}) reports the window's own scope chain: the buffer scope is separate, and
|
|
-- visible only via the {bufnr} form.
|
|
command(('split %s%s%s2'):format(directories.buffer, pathsep, tmpfile))
|
|
local bufnr = call('winbufnr', 1)
|
|
command('wincmd p')
|
|
eq(globalDir, cwd())
|
|
eq({ globalDir, globalDir }, { cwd(1), cwd(2) })
|
|
eq(join(globalDir, directories.buffer), cwd(-1, -1, bufnr))
|
|
|
|
-- The {bufnr} form skips window and tab: a buffer belongs to no particular window/tabpage.
|
|
command('lcd ' .. directories.window)
|
|
command('tcd ' .. join('..', directories.tab))
|
|
eq(
|
|
{ join(globalDir, directories.tab), join(globalDir, directories.tab) },
|
|
{ cwd(0), tcwd() }
|
|
)
|
|
eq(globalDir, cwd(-1, -1, 0))
|
|
end)
|
|
end)
|
|
|
|
describe('getcwd(-1, -1)', function()
|
|
it('works', function()
|
|
eq(startdir, cwd(-1, -1))
|
|
eq(0, lwd(-1, -1))
|
|
end)
|
|
|
|
it('with tab-local dir', function()
|
|
command('silent t' .. cmd .. ' ' .. directories.tab)
|
|
eq(startdir, cwd(-1, -1))
|
|
eq(0, lwd(-1, -1))
|
|
end)
|
|
|
|
it('with window-local dir', function()
|
|
command('silent l' .. cmd .. ' ' .. directories.window)
|
|
eq(startdir, cwd(-1, -1))
|
|
eq(0, lwd(-1, -1))
|
|
end)
|
|
|
|
it('with buffer-local dir', function()
|
|
command(('silent b%s %s'):format(cmd, directories.buffer))
|
|
eq(startdir, cwd(-1, -1))
|
|
eq(0, lwd(-1, -1))
|
|
|
|
-- Must behave the same if bufnr is -1
|
|
eq(startdir, cwd(-1, -1, -1))
|
|
eq(0, lwd(-1, -1, -1))
|
|
end)
|
|
end)
|
|
|
|
describe('Local directory gets inherited', function()
|
|
it('by tabs', function()
|
|
local globalDir = startdir
|
|
|
|
-- Create a new tab and change directory
|
|
command('tabnew')
|
|
command('silent t' .. cmd .. ' ' .. directories.tab)
|
|
eq(globalDir .. pathsep .. directories.tab, tcwd())
|
|
|
|
-- Create a new tab and verify it has inherited the directory
|
|
command('tabnew')
|
|
eq(globalDir .. pathsep .. directories.tab, tcwd())
|
|
|
|
-- Change tab and change back, verify that directories are correct
|
|
command('tabnext')
|
|
eq(globalDir, tcwd())
|
|
command('tabprevious')
|
|
eq(globalDir .. pathsep .. directories.tab, tcwd())
|
|
end)
|
|
end)
|
|
|
|
it('works', function()
|
|
local globalDir = startdir
|
|
-- Create a new tab first and verify that is has the same working dir
|
|
command('tabnew')
|
|
eq(globalDir, cwd())
|
|
eq(globalDir, tcwd()) -- has no tab-local directory
|
|
eq(0, tlwd())
|
|
eq(globalDir, wcwd()) -- has no window-local directory
|
|
eq(0, wlwd())
|
|
|
|
-- Change tab-local working directory and verify it is different
|
|
command('silent t' .. cmd .. ' ' .. directories.tab)
|
|
eq(globalDir .. pathsep .. directories.tab, cwd())
|
|
eq(cwd(), tcwd()) -- working directory matches tab directory
|
|
eq(1, tlwd())
|
|
eq(cwd(), wcwd()) -- still no window-directory
|
|
eq(0, wlwd())
|
|
|
|
-- Create a new window in this tab to test `:lcd`
|
|
command('new')
|
|
eq(1, tlwd()) -- Still tab-local working directory
|
|
eq(0, wlwd()) -- Still no window-local working directory
|
|
eq(globalDir .. pathsep .. directories.tab, cwd())
|
|
command('silent l' .. cmd .. ' ../' .. directories.window)
|
|
eq(globalDir .. pathsep .. directories.window, cwd())
|
|
eq(globalDir .. pathsep .. directories.tab, tcwd())
|
|
eq(1, wlwd())
|
|
|
|
-- Verify the first window still has the tab local directory
|
|
command('wincmd w')
|
|
eq(globalDir .. pathsep .. directories.tab, cwd())
|
|
eq(globalDir .. pathsep .. directories.tab, tcwd())
|
|
eq(0, wlwd()) -- No window-local directory
|
|
|
|
-- Change back to initial tab and verify working directory has stayed
|
|
command('tabnext')
|
|
eq(globalDir, cwd())
|
|
eq(0, tlwd())
|
|
eq(0, wlwd())
|
|
|
|
-- Verify global changes don't affect local ones
|
|
command('silent ' .. cmd .. ' ' .. directories.global)
|
|
eq(globalDir .. pathsep .. directories.global, cwd())
|
|
command('tabnext')
|
|
eq(globalDir .. pathsep .. directories.tab, cwd())
|
|
eq(globalDir .. pathsep .. directories.tab, tcwd())
|
|
eq(0, wlwd()) -- Still no window-local directory in this window
|
|
|
|
-- Unless the global change happened in a tab with local directory
|
|
command('silent ' .. cmd .. ' ..')
|
|
eq(globalDir, cwd())
|
|
eq(0, tlwd())
|
|
eq(0, wlwd())
|
|
-- Which also affects the first tab
|
|
command('tabnext')
|
|
eq(globalDir, cwd())
|
|
|
|
-- But not in a window with its own local directory
|
|
command('tabnext | wincmd w')
|
|
eq(globalDir .. pathsep .. directories.window, cwd())
|
|
eq(0, tlwd())
|
|
eq(globalDir .. pathsep .. directories.window, wcwd())
|
|
end)
|
|
|
|
it('works when mixing tab-local and buffer-local directories', function()
|
|
local globalDir = startdir
|
|
|
|
-- Create two buffers for testing. One in each tab
|
|
command(('e %s1'):format(tmpfile))
|
|
command('tabnew')
|
|
command(('e %s2'):format(tmpfile))
|
|
|
|
-- Verify that buffer 2 has the same working directory
|
|
eq(globalDir, cwd())
|
|
eq(globalDir, tcwd()) -- Has no tab-local directory
|
|
eq(0, tlwd())
|
|
eq(globalDir, bcwd()) -- Has no buffer-local directory
|
|
eq(0, blwd())
|
|
|
|
-- Change tab-local working directory and verify it is different
|
|
command(('silent t%s %s'):format(cmd, directories.tab))
|
|
eq(join(globalDir, directories.tab), cwd())
|
|
eq(cwd(), tcwd()) -- Working directory matches tab directory
|
|
eq(1, tlwd())
|
|
eq(globalDir, bcwd()) -- Still no buffer-directory: the buffer form skips the tab scope
|
|
eq(0, blwd())
|
|
|
|
-- Change buffer 2's buffer-local directory
|
|
command(('silent b%s ..%s%s'):format(cmd, pathsep, directories.buffer))
|
|
eq(join(globalDir, directories.buffer), cwd())
|
|
eq(join(globalDir, directories.tab), tcwd())
|
|
eq(cwd(), bcwd()) -- Has no buffer-directory
|
|
eq(1, blwd())
|
|
|
|
-- Verify the first tab has no local-directory
|
|
command('tabfirst')
|
|
eq(0, tlwd())
|
|
|
|
-- Verify buffer 2 has buffer-local directory even in first tab
|
|
command(('b %s2'):format(tmpfile)) -- Switch to buffer 2
|
|
eq(join(globalDir, directories.buffer), bcwd())
|
|
eq(0, tlwd()) -- Still no tab-local directory
|
|
|
|
-- Verify buffer 1 did not have its directory changed
|
|
command('b#') -- Switch to buffer 1
|
|
eq(globalDir, cwd())
|
|
eq(0, blwd()) -- No window-buffer directory
|
|
end)
|
|
it('works when mixing window local and buffer local directories', function()
|
|
local globalDir = startdir
|
|
-- Create a new window first and verify that is has the same working directory
|
|
command('new')
|
|
eq(globalDir, cwd())
|
|
eq(globalDir, wcwd()) -- Has no window-local directory
|
|
eq(0, tlwd())
|
|
eq(globalDir, bcwd()) -- Has no buffer-local directory
|
|
eq(0, blwd())
|
|
|
|
-- Create a buffer in current window
|
|
command('e ' .. tmpfile)
|
|
|
|
-- Change buffer-local working directory and verify it is different
|
|
command(('silent b%s %s'):format(cmd, directories.buffer))
|
|
eq(join(globalDir, directories.buffer), cwd())
|
|
eq(cwd(), bcwd()) -- Working directory matches buffer directory
|
|
eq(1, blwd())
|
|
eq(globalDir, wcwd()) -- Still no window-directory
|
|
eq(0, wlwd())
|
|
|
|
-- :lcd sets the window-local dir WITHOUT clearing the narrower buffer-local one.
|
|
command(('silent l%s ../%s'):format(cmd, directories.window))
|
|
eq(join(globalDir, directories.buffer), cwd())
|
|
eq({ 1, 1 }, { blwd(), wlwd() })
|
|
eq(join(globalDir, directories.window), wcwd())
|
|
|
|
-- Window-local dir applies if the buffer-local one is unset.
|
|
command(('silent b%s!'):format(cmd))
|
|
eq(0, blwd())
|
|
eq(join(globalDir, directories.window), cwd())
|
|
|
|
-- Verify other window is unaffected.
|
|
command('wincmd w')
|
|
command('b ' .. tmpfile)
|
|
eq(globalDir, cwd())
|
|
command('wincmd w')
|
|
eq(join(globalDir, directories.window), cwd())
|
|
end)
|
|
end)
|
|
end
|
|
|
|
for _, cmd in ipairs { 'bcd', 'bchdir' } do
|
|
describe(':' .. cmd, function()
|
|
it('works after deleting the only buffer', function()
|
|
command(('%s %s'):format(cmd, directories.buffer))
|
|
command('bd') -- delete buffer
|
|
end)
|
|
|
|
it('buffer-local directory is NOT sticky/inherited', function()
|
|
local bufdir = join(startdir, directories.buffer)
|
|
|
|
command('edit ' .. tmpfile)
|
|
command(('%s %s'):format(cmd, directories.buffer))
|
|
eq(bufdir, cwd())
|
|
|
|
-- A new buffer starts without a buffer-local directory.
|
|
command('new')
|
|
eq(startdir, cwd())
|
|
eq(0, blwd())
|
|
command('close')
|
|
eq(bufdir, cwd())
|
|
command('enew')
|
|
eq(startdir, cwd())
|
|
eq(0, blwd())
|
|
command('b# ')
|
|
eq(bufdir, cwd())
|
|
|
|
-- Recycling an empty unnamed buffer (:edit) drops its directory with it.
|
|
command('enew')
|
|
command(('%s %s'):format(cmd, directories.buffer))
|
|
eq(bufdir, cwd())
|
|
command('edit ' .. tmpfile .. '2')
|
|
eq(startdir, cwd())
|
|
eq(0, blwd())
|
|
|
|
-- But re-editing the same buffer keeps it, like any other buffer-local state. #41213
|
|
command(('%s %s'):format(cmd, directories.buffer))
|
|
command('let b:kept = 1')
|
|
command('edit!')
|
|
eq({ 1, bufdir, 1 }, { blwd(), cwd(), n.eval('get(b:, "kept", 0)') })
|
|
end)
|
|
|
|
it('is not cleared or overridden by :lcd/:tcd/:cd', function()
|
|
local bufdir = join(startdir, directories.buffer)
|
|
|
|
command('edit ' .. tmpfile)
|
|
command(('%s %s'):format(cmd, directories.buffer))
|
|
-- Paths are relative to `bufdir`, which stays in effect throughout.
|
|
command('lcd ' .. join('..', directories.window))
|
|
eq({ 1, bufdir, join(startdir, directories.window) }, { blwd(), cwd(), wcwd() })
|
|
|
|
command('tcd ' .. join('..', directories.tab))
|
|
eq({ 1, bufdir, join(startdir, directories.tab) }, { blwd(), cwd(), tcwd() })
|
|
|
|
command('cd ..')
|
|
eq({ 1, bufdir, startdir }, { blwd(), cwd(), cwd(-1, -1) })
|
|
|
|
-- The overridden ":cd" still reset the window/tab scopes, so ":bcd!" lands on the global dir.
|
|
command(('%s!'):format(cmd))
|
|
eq({ 0, 0, 0, startdir }, { blwd(), wlwd(), tlwd(), cwd() })
|
|
end)
|
|
end)
|
|
end
|
|
|
|
describe(':lcd!/:tcd!/:bcd! (bang)', function()
|
|
it('clear only their own scope', function()
|
|
local bufdir = join(startdir, directories.buffer)
|
|
local windir = join(startdir, directories.window)
|
|
local tabdir = join(startdir, directories.tab)
|
|
|
|
command('tcd ' .. directories.tab)
|
|
command('lcd ' .. join('..', directories.window))
|
|
command('bcd ' .. join('..', directories.buffer))
|
|
eq({ 1, 1, 1 }, { blwd(), wlwd(), tlwd() })
|
|
eq(bufdir, cwd())
|
|
|
|
command('bcd!') -- Buffer scope gone: the window-local dir applies.
|
|
eq({ 0, 1, 1 }, { blwd(), wlwd(), tlwd() })
|
|
eq(windir, cwd())
|
|
|
|
command('lcd!') -- Window scope gone: the tab-local dir applies.
|
|
eq({ 0, 0, 1 }, { blwd(), wlwd(), tlwd() })
|
|
eq(tabdir, cwd())
|
|
|
|
command('tcd!') -- Tab scope gone: back to the global dir.
|
|
eq({ 0, 0, 0 }, { blwd(), wlwd(), tlwd() })
|
|
eq(startdir, cwd())
|
|
|
|
command('lcd!') -- No-op when the scope has no local directory.
|
|
eq(startdir, cwd())
|
|
|
|
-- :cd! does not unset.
|
|
command('lcd ' .. directories.window)
|
|
command('cd! ' .. join('..', directories.global))
|
|
eq(join(startdir, directories.global), cwd())
|
|
eq(0, wlwd()) -- ":cd" cleared it, as always.
|
|
|
|
-- Legacy: bang WITH arg ":lcd! {path}" is just ":lcd {path}".
|
|
command('lcd! ' .. join('..', directories.window))
|
|
eq({ 1, join(startdir, directories.window) }, { wlwd(), cwd() })
|
|
end)
|
|
end)
|
|
|
|
describe('cd during temp context-switch', function()
|
|
it(':bcd/:tcd/:lcd persists in target scope, does not leak into original context', function()
|
|
local exec_lua = n.exec_lua
|
|
local bufdir = join(startdir, directories.buffer)
|
|
local windir = join(startdir, directories.window)
|
|
local tabdir = join(startdir, directories.tab)
|
|
|
|
--- Creates a loaded, hidden buffer.
|
|
local function hidden_buf(name)
|
|
local b = call('bufadd', name)
|
|
call('bufload', b)
|
|
return b
|
|
end
|
|
|
|
--- Runs `vim.cmd[cmd](dir)` with buffer `b` as temporary curbuf.
|
|
local function cd_in_buf_call(b, cmd, dir)
|
|
exec_lua(function(b_, cmd_, d)
|
|
vim.api.nvim_buf_call(b_, function()
|
|
vim.cmd[cmd_](d)
|
|
end)
|
|
end, b, cmd, dir)
|
|
end
|
|
|
|
-- :bcd on a hidden buffer via nvim_buf_call() persists; the caller's cwd is unchanged.
|
|
local hidden = hidden_buf('Xtest-cd-hidden')
|
|
cd_in_buf_call(hidden, 'bcd', bufdir)
|
|
eq({ 1, bufdir, startdir }, { lwd(-1, -1, hidden), cwd(-1, -1, hidden), cwd() })
|
|
|
|
-- :lcd targets the temporary window, which is discarded; the caller's cwd is unchanged.
|
|
cd_in_buf_call(hidden, 'lcd', windir)
|
|
eq({ 0, startdir }, { wlwd(), cwd() })
|
|
|
|
-- :lcd via win_execute() persists on the target window; the CWD outside it is unchanged.
|
|
command('split')
|
|
call('win_execute', call('win_getid', 2), ('lcd %s'):format(windir))
|
|
eq({ 1, windir, startdir }, { lwd(2), cwd(2), cwd() })
|
|
command('only')
|
|
|
|
-- An autocmd handler targeting a hidden buffer can set its buffer-local dir; the caller's
|
|
-- cwd is unchanged.
|
|
local hidden2 = hidden_buf('Xtest-cd-hidden2')
|
|
exec_lua(function(b, d)
|
|
vim.api.nvim_create_autocmd('TermRequest', {
|
|
buffer = b,
|
|
once = true,
|
|
callback = function()
|
|
vim.cmd.bcd(d)
|
|
end,
|
|
})
|
|
vim.api.nvim_exec_autocmds('TermRequest', { buffer = b, data = { sequence = 'x' } })
|
|
end, hidden2, bufdir)
|
|
eq({ 1, bufdir, startdir }, { lwd(-1, -1, hidden2), cwd(-1, -1, hidden2), cwd() })
|
|
|
|
-- :tcd via nvim_buf_call() persists, and the tab scope claims the new cwd.
|
|
cd_in_buf_call(hidden, 'tcd', tabdir)
|
|
eq({ 1, tabdir, tabdir }, { tlwd(), tcwd(), cwd() })
|
|
end)
|
|
|
|
it("nvim_open_win / nvim_win_set_buf keep the caller's cwd", function()
|
|
local bufdir = join(startdir, directories.buffer)
|
|
command('bcd ' .. bufdir)
|
|
eq(bufdir, cwd())
|
|
|
|
-- A transient switch to a scratch float must not reset the caller's cwd.
|
|
local float = call('nvim_open_win', call('nvim_create_buf', true, true), false, {
|
|
relative = 'editor',
|
|
width = 20,
|
|
height = 5,
|
|
row = 1,
|
|
col = 1,
|
|
})
|
|
eq(bufdir, cwd())
|
|
|
|
call('nvim_win_set_buf', float, call('nvim_create_buf', true, true))
|
|
eq(bufdir, cwd())
|
|
|
|
call('nvim_win_close', float, true)
|
|
eq(bufdir, cwd())
|
|
command('bcd!')
|
|
end)
|
|
end)
|
|
|
|
-- Test legal parameters for 'getcwd' and 'haslocaldir'
|
|
for _, cmd in ipairs { 'getcwd', 'haslocaldir' } do
|
|
describe(cmd .. '()', function()
|
|
it('validation', function()
|
|
local err474 = 'Vim:E474: Invalid argument'
|
|
eq(err474, pcall_err(call, cmd, 'some string'))
|
|
eq(err474, pcall_err(call, cmd, 1.5))
|
|
eq(err474, pcall_err(call, cmd, { 1, 2 }))
|
|
eq(err474, pcall_err(call, cmd, { key = 'value' }))
|
|
eq(err474, pcall_err(call, cmd, -2))
|
|
-- Funcref is not representable over RPC.
|
|
eq(
|
|
'Vim(call):E474: Invalid argument',
|
|
pcall_err(command, ('call %s(function("tr"))'):format(cmd))
|
|
)
|
|
|
|
-- -1 preceded by an argument >= 0
|
|
local err5001 = 'Vim:E5001: Argument cannot be -1 if preceding argument is >= 0.'
|
|
eq(err5001, pcall_err(call, cmd, 0, -1))
|
|
eq(err5001, pcall_err(call, cmd, 2, 3, -1))
|
|
eq(err5001, pcall_err(call, cmd, -1, 0, -1))
|
|
eq(err5001, pcall_err(call, cmd, 0, -1, 0))
|
|
-- Buffer scope requires window and tab args to be -1.
|
|
local err5006 = 'Vim:E5006: Window and tab scope must be -1 when using buffer scope'
|
|
eq(err5006, pcall_err(call, cmd, 0, 0, 0))
|
|
eq(err5006, pcall_err(call, cmd, 1, 2, 3))
|
|
eq('Vim:E5007: Cannot find buffer number.', pcall_err(call, cmd, -1, -1, 99999))
|
|
eq(
|
|
('Vim:E118: Too many arguments for function: %s'):format(cmd),
|
|
pcall_err(call, cmd, 0, 0, 0, 0)
|
|
)
|
|
end)
|
|
end)
|
|
end
|
|
|
|
describe('getcwd()', function()
|
|
it('returns empty string if working directory does not exist', function()
|
|
skip(is_os('win'), 'N/A for Windows')
|
|
command('cd ' .. directories.global)
|
|
command("call delete('../" .. directories.global .. "', 'd')")
|
|
eq('', n.eval('getcwd()'))
|
|
end)
|
|
|
|
it("works with 'autochdir' after local directory was set (#9892)", function()
|
|
local curdir = cwd()
|
|
command('lcd ' .. directories.global)
|
|
command('lcd -')
|
|
command('set autochdir')
|
|
command('edit ' .. directories.global .. '/foo')
|
|
eq(curdir .. pathsep .. directories.global, cwd())
|
|
eq(curdir, wcwd())
|
|
call('mkdir', 'bar')
|
|
command('edit ' .. 'bar/foo')
|
|
eq(curdir .. pathsep .. directories.global .. pathsep .. 'bar', cwd())
|
|
eq(curdir, wcwd())
|
|
command('lcd ..')
|
|
eq(curdir .. pathsep .. directories.global, cwd())
|
|
eq(curdir .. pathsep .. directories.global, wcwd())
|
|
command('edit')
|
|
eq(curdir .. pathsep .. directories.global .. pathsep .. 'bar', cwd())
|
|
eq(curdir .. pathsep .. directories.global, wcwd())
|
|
end)
|
|
end)
|