nvim-neotest / neotest

An extensible framework for interacting with tests within NeoVim.
MIT License
2.44k stars 123 forks source link

`Error executing luv callback` in custom Neotest plugin #74

Closed rouge8 closed 2 years ago

rouge8 commented 2 years ago

I'm working on a Neotest plugin for Rust and I've gotten it to the point where it can run the first test fine, but on every subsequent test it fails with:

|| Error executing luv callback:
|| ...re/nvim/plugged/plenary.nvim/lua/plenary/async/async.lua:14: The coroutine failed with this message: vim/_editor.lua:0: E5560: nvim_echo must not be called in a lua loop callback
|| stack traceback:
||  [C]: in function 'error'
||  ...re/nvim/plugged/plenary.nvim/lua/plenary/async/async.lua:14: in function 'callback_or_next'
||  ...re/nvim/plugged/plenary.nvim/lua/plenary/async/async.lua:40: in function <...re/nvim/plugged/plenary.nvim/lua/plenary/async/async.lua:39>

Do you have any idea what might be causing that? I don't see the error if I comment out the file writing on lines 105-107, but without that the tests don't run. I've tried running directly with vim.loop.fs_* in sync and async modes:

    local fd = assert(vim.loop.fs_open(tmp_nextest_config, "a", 438))
    assert(vim.loop.fs_write(fd, '[profile.neotest.junit]\npath = "' .. junit_path .. '"'))
    assert(vim.loop.fs_close(fd))
    vim.loop.fs_open(tmp_nextest_config, "a", 438, function(err, fd)
        assert(not err, err)
        vim.loop.fs_write(fd, '[profile.neotest.junit]\npath = "' .. junit_path .. '"', function(err, _)
            assert(not err, err)
            vim.loop.fs_close(fd, function(err)
                assert(not err, err)
            end)
        end)
    end)

and those both see the same error...

rouge8 commented 2 years ago

Interestingly if I comment out local success, data = pcall(lib.files.read, spec.context.junit_path) on line 139, that also "works"...

rouge8 commented 2 years ago

If I replace local success, data = pcall(lib.files.read, spec.context.junit_path) with

    with(open(spec.context.junit_path, "r"), function(reader)
        data = reader:read("*a")
    end)

then it works fine 😵

rcarriga commented 2 years ago

I don't seem to be able to reproduce with the following (also altered your code to use the async read/write as above)

nvim --clean -u minimal.lua

-- ignore default config and plugins
vim.opt.runtimepath:remove(vim.fn.expand("~/.config/nvim"))
vim.opt.packpath:remove(vim.fn.expand("~/.local/share/nvim/site"))
vim.opt.termguicolors = true

-- append test directory
local test_dir = "/tmp/nvim-config"
vim.opt.runtimepath:append(vim.fn.expand(test_dir))
vim.opt.packpath:append(vim.fn.expand(test_dir))

-- install packer
local install_path = test_dir .. "/pack/packer/start/packer.nvim"
local install_plugins = false

if vim.fn.empty(vim.fn.glob(install_path)) > 0 then
  vim.cmd("!git clone https://github.com/wbthomason/packer.nvim " .. install_path)
  vim.cmd("packadd packer.nvim")
  install_plugins = true
end

local packer = require("packer")

packer.init({
  package_root = test_dir .. "/pack",
  compile_path = test_dir .. "/plugin/packer_compiled.lua",
})

packer.startup(function(use)
  -- Packer can manage itself
  use("wbthomason/packer.nvim")

  use("vim-test/vim-test")
  use({
    "nvim-neotest/neotest",
    requires = {
      "nvim-lua/plenary.nvim",
      "nvim-treesitter/nvim-treesitter",
      "antoinemadec/FixCursorHold.nvim",
      "rouge8/neotest-rust",
    },
    config = function()
      require("neotest").setup({
        adapters = {
          require("neotest-rust"),
        },
      })
    end,
  })

  if install_plugins then
    packer.sync()
  end
end)

vim.cmd([[
command! NeotestSummary lua require("neotest").summary.toggle()
command! NeotestFile lua require("neotest").run.run(vim.fn.expand("%"))
command! Neotest lua require("neotest").run.run(vim.fn.getcwd())
command! NeotestNearest lua require("neotest").run.run()
command! NeotestDebug lua require("neotest").run.run({ strategy = "dap" })
command! NeotestAttach lua require("neotest").run.attach()
]])
rouge8 commented 2 years ago

You need to specify an earlier commit in the repo, { "rouge8/neotest-rust", commit = "833255157eb5c48a8b824d084b5088f617ca687d" },. I was able to work around it by switching to with(open(...)) in later commits, but never figured out the local success, data = pcall(lib.files.read, spec.context.junit_path) issue. Then :TSInstall rust and :NeotestNearest on a test. The first time it succeeds, the second time it crashes with the error above.

rcarriga commented 2 years ago

Ah it was the second run that I was missing! OK so the issue was that neotest-rust was throwing an error, which neotest catches and sends in a vim.notify call. I'm using nvim-notify which automatically schedules itself on main thread but the default one does not and so errors out if it's called in async function :facepalm: Should be fixed in master now :grin:

rouge8 commented 2 years ago

That seems to fix it, thanks!