@ 261105.2

261021.1 · 5beb1bf72b0810da6ccee50f6087c2f005aeb737

fix(spawn): never delete cwd when tempname() fails

`vim_tempname()` returns NULL when Neovim cannot create its tempdir (e.g. disk full), which Lua converts to an empty string. `fnamemodify("", ":h")` then yields "." and the cleanup `vim.fn.delete(tmpdir, "rf")` recursively wiped the current working directory.

Skip the cleanup when `tempname()` is empty. Successful tempnames are always absolute (`vim_settempdir()` expands them), so only the empty string needs guarding. Add a regression test that runs `spawn.lua` with a stubbed empty `tempname()`, feeds it a valid serialized spec, and asserts both a clean exit and that a sentinel file in the cwd survives.

Fixes #2838

reading declarations

Changes to tests/spawn_spec.lua. All files

tests/spawn_spec.lua

new file mode 100644@@ -0,0 +1,42 @@+local helpers = require("fzf-lua.test.helpers")+local assert = helpers.assert+local libuv = require("fzf-lua.libuv")+local eq = assert.are.equal++describe("Testing spawn.lua", function()+  it("does not delete the cwd when tempname() fails (#2838)", function()+    ---@diagnostic disable-next-line: deprecated+    local _info = debug.getinfo(1, "S")+    ---@cast _info {source: string}+    -- must be absolute: the child runs with `cwd` set to a temp directory+    local root = vim.fn.fnamemodify(_info.source:gsub("^@", ""), ":p:h:h")+    local script = (root .. "/lua/fzf-lua/spawn.lua"):gsub("\\", "/")+    eq(1, vim.fn.filereadable(script))++    -- disposable cwd with a sentinel file that must survive+    local dir = vim.fn.tempname()+    vim.fn.mkdir(dir, "p")+    local sentinel = dir .. "/sentinel"+    vim.fn.writefile({ "keep" }, sentinel)++    -- simulate Neovim failing to create its tempdir (e.g. disk full), which+    -- makes `tempname()` return an empty string+    local spec = libuv.serialize({ contents = { "spawn-test" } }, true)+    local jobid = vim.fn.jobstart({+      vim.v.progpath,+      "--headless",+      "--clean",+      "--cmd",+      [[lua vim.fn.tempname = function() return "" end]],+      "-l",+      script,+      spec,+    }, { cwd = dir })+    eq(true, jobid > 0)+    local rc = vim.fn.jobwait({ jobid }, 10000)[1]+    eq(0, rc)++    eq(1, vim.fn.filereadable(sentinel))+    vim.fn.delete(dir, "rf")+  end)+end)