diff --git a/doc/neotest.txt b/doc/neotest.txt index 6e05cae2..72f9a67d 100644 --- a/doc/neotest.txt +++ b/doc/neotest.txt @@ -290,12 +290,16 @@ neotest.output.open({opts}) *neotest.output.open()* {opts} (table) Fields: ~ - {short} (boolean) Show shortened output - {enter} (boolean) Enter output window - {position_id} (string) Open output for position with this ID, opens - nearest position if not given - {adapter} (string) Adapter ID, defaults to first found with - matching position + {open_win} (function) Function that takes a table with width and + height keys and opens a window for the + output. If a window ID is not returned, the + current window will be used + {short} (boolean) Show shortened output + {enter} (boolean) Enter output window + {position_id} (string) Open output for position with this ID, opens + nearest position if not given + {adapter} (string) Adapter ID, defaults to first found with + matching position diff --git a/lua/neotest/consumers/output.lua b/lua/neotest/consumers/output.lua index 6f744744..f8c80c5a 100644 --- a/lua/neotest/consumers/output.lua +++ b/lua/neotest/consumers/output.lua @@ -15,35 +15,69 @@ local function open_output(result, opts) async.util.sleep(10) -- Wait for chan to send local lines = async.api.nvim_buf_get_lines(buf, 0, -1, false) local width, height = 80, #lines - for _, line in pairs(lines) do + for i, line in ipairs(lines) do + if i > 500 then + break -- Don't want to parse very long output + end local line_length = vim.str_utfindex(line) if line_length > width then width = line_length end end - win = lib.ui.float.open({ - width = width, - height = height, - buffer = buf, - enter = opts.enter, - }) + local on_close = function() + pcall(vim.api.nvim_buf_delete, buf, { force = true }) + pcall(vim.fn.chanclose, chan) + win = nil + end + if opts.open_win then + local cur_win = vim.api.nvim_get_current_win() + win = opts.open_win({ width = width, height = height }) + if not win then + win = vim.api.nvim_get_current_win() + end + vim.api.nvim_create_autocmd("WinClosed", { + pattern = tostring(win), + callback = on_close, + }) + vim.api.nvim_win_set_buf(win, buf) + if opts.enter then + vim.api.nvim_set_current_win(win) + else + vim.api.nvim_set_current_win(cur_win) + end + else + local float = lib.ui.float.open({ + width = width, + height = height, + buffer = buf, + enter = opts.enter, + }) + float:listen("close", on_close) + win = float.win_id + end + async.api.nvim_buf_set_keymap(buf, "n", "q", "", { noremap = true, silent = true, callback = function() - pcall(vim.api.nvim_win_close, win.win_id, true) + pcall(vim.api.nvim_win_close, win, true) end, }) - win:listen("close", function() - pcall(vim.api.nvim_buf_delete, buf, { force = true }) - pcall(vim.fn.chanclose, chan) - win = nil - end) end ----@param client neotest.Client -local init = function(client) +---@tag neotest.output + +---@brief [[ +--- A consumer that displays the output of test results. +---@brief ]] +local neotest = {} +neotest.output = {} + +---@type neotest.Client +local client + +local init = function() if config.output.open_on_run then client.listeners.results = function(_, results) local cur_pos = async.fn.getpos(".") @@ -69,66 +103,58 @@ local init = function(client) end end end - return { - open = function(opts) - opts = opts or {} - if win then - if opts.short ~= short_opened then - win:close() - else - if pcall(win.jump_to, win) then - return - end - opts.enter = true - end - end - async.run(function() - local tree, adapter_id - if not opts.position_id then - local file_path = vim.fn.expand("%:p") - local row = vim.fn.getbufinfo(file_path)[1].lnum - 1 - tree, adapter_id = client:get_nearest(file_path, row, opts) - else - tree, adapter_id = client:get_position(opts.position_id, opts) - end - if not tree then - lib.notify("No tests found in file", "warn") - return - end - local result = client:get_results(adapter_id)[tree:data().id] - if not result then - lib.notify("No output for " .. tree:data().name) - return - end - open_output(result, opts) - end) - end, - } end ----@tag neotest.output -local neotest = {} -neotest.output = {} - ----@brief [[ ---- A consumer that displays the output of test results. ----@brief ]] - ---Open the output of a test result ---
 --->
 ---lua require("neotest").output.open({ enter = true })
 ---
---@param opts table +---@field open_win function: Function that takes a table with width and height keys and opens a window for the output. If a window ID is not returned, the current window will be used ---@field short boolean: Show shortened output ---@field enter boolean: Enter output window ---@field position_id string: Open output for position with this ID, opens nearest position if not given ---@field adapter string: Adapter ID, defaults to first found with matching position -function neotest.output.open(opts) end +function neotest.output.open(opts) + opts = opts or {} + if win then + if opts.short ~= short_opened then + pcall(vim.api.nvim_win_close, win, true) + else + if pcall(vim.api.nvim_set_current_win, win) then + return + end + opts.enter = true + end + end + async.run(function() + local tree, adapter_id + if not opts.position_id then + local file_path = vim.fn.expand("%:p") + local row = vim.fn.getbufinfo(file_path)[1].lnum - 1 + tree, adapter_id = client:get_nearest(file_path, row, opts) + else + tree, adapter_id = client:get_position(opts.position_id, opts) + end + if not tree then + lib.notify("No tests found in file", "warn") + return + end + local result = client:get_results(adapter_id)[tree:data().id] + if not result then + lib.notify("No output for " .. tree:data().name) + return + end + open_output(result, opts) + end) +end neotest.output = setmetatable(neotest.output, { - __call = function(_, ...) - return init(...) + __call = function(_, client_) + client = client_ + init() + return neotest.output end, })