add TSamFailedOnly command and change test output within the floating window
This commit is contained in:
@@ -8,6 +8,11 @@ local state = {
|
||||
last_win = nil,
|
||||
last_buf = nil,
|
||||
last_command = nil,
|
||||
last_scope_command = nil,
|
||||
last_scope_runner = nil,
|
||||
last_scope_kind = nil,
|
||||
last_scope_exit_code = nil,
|
||||
last_scope_failures = nil,
|
||||
autocmds_set = false,
|
||||
}
|
||||
|
||||
@@ -52,6 +57,11 @@ function M.setup()
|
||||
load_runners()
|
||||
ensure_output_autocmds()
|
||||
state.last_command = nil
|
||||
state.last_scope_command = nil
|
||||
state.last_scope_runner = nil
|
||||
state.last_scope_kind = nil
|
||||
state.last_scope_exit_code = nil
|
||||
state.last_scope_failures = nil
|
||||
end
|
||||
|
||||
function M.reload_runners()
|
||||
@@ -299,12 +309,45 @@ local function run_cmd(cmd, cwd, handlers)
|
||||
})
|
||||
end
|
||||
|
||||
local function run_command(command)
|
||||
local function format_results(results)
|
||||
local lines = {}
|
||||
if type(results.passes) == "table" then
|
||||
for _, title in ipairs(results.passes) do
|
||||
table.insert(lines, "[ PASS ] - " .. title)
|
||||
end
|
||||
end
|
||||
if type(results.skips) == "table" then
|
||||
for _, title in ipairs(results.skips) do
|
||||
table.insert(lines, "[ SKIP ] - " .. title)
|
||||
end
|
||||
end
|
||||
if type(results.failures) == "table" then
|
||||
for _, title in ipairs(results.failures) do
|
||||
table.insert(lines, "[ FAIL ] - " .. title)
|
||||
end
|
||||
end
|
||||
return lines
|
||||
end
|
||||
|
||||
local function run_command(command, opts)
|
||||
local options = opts or {}
|
||||
if command and type(command.cmd) == "table" and #command.cmd > 0 then
|
||||
state.last_command = {
|
||||
cmd = vim.deepcopy(command.cmd),
|
||||
cwd = command.cwd,
|
||||
}
|
||||
if options.save_last ~= false then
|
||||
state.last_command = {
|
||||
cmd = vim.deepcopy(command.cmd),
|
||||
cwd = command.cwd,
|
||||
}
|
||||
end
|
||||
if options.track_scope then
|
||||
state.last_scope_command = {
|
||||
cmd = vim.deepcopy(command.cmd),
|
||||
cwd = command.cwd,
|
||||
}
|
||||
state.last_scope_runner = options.runner
|
||||
state.last_scope_kind = options.scope_kind
|
||||
state.last_scope_exit_code = nil
|
||||
state.last_scope_failures = nil
|
||||
end
|
||||
end
|
||||
local cmd = command.cmd
|
||||
local cwd = command.cwd or vim.loop.cwd()
|
||||
@@ -312,48 +355,126 @@ local function run_command(command)
|
||||
local header = "$ " .. table.concat(cmd, " ")
|
||||
local buf = nil
|
||||
local has_output = false
|
||||
local parser = options.output_parser
|
||||
if type(parser) == "function" then
|
||||
parser = { on_complete = parser }
|
||||
end
|
||||
local parser_state = {}
|
||||
local had_parsed_output = false
|
||||
|
||||
local output_lines = {}
|
||||
|
||||
local function collect_output(lines)
|
||||
if not lines or #lines == 0 then
|
||||
return
|
||||
end
|
||||
for _, line in ipairs(lines) do
|
||||
if line ~= nil then
|
||||
table.insert(output_lines, line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ensure_output_started()
|
||||
if not buf then
|
||||
buf = select(1, create_output_win({ header, "" }))
|
||||
end
|
||||
if not has_output then
|
||||
local cur = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
if #cur > 0 and cur[#cur] == "[running...]" then
|
||||
vim.api.nvim_buf_set_lines(buf, #cur - 1, #cur, false, {})
|
||||
end
|
||||
has_output = true
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_parsed(results)
|
||||
if not results then
|
||||
return
|
||||
end
|
||||
local lines = format_results(results)
|
||||
if #lines == 0 then
|
||||
return
|
||||
end
|
||||
ensure_output_started()
|
||||
append_lines(buf, lines)
|
||||
had_parsed_output = true
|
||||
if options.track_scope then
|
||||
if results.failures_all ~= nil then
|
||||
state.last_scope_failures = results.failures_all
|
||||
elseif results.failures ~= nil then
|
||||
state.last_scope_failures = results.failures
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
run_cmd(cmd, cwd, {
|
||||
on_start = function()
|
||||
buf = select(1, create_output_win({ header, "", "[running...]" }))
|
||||
end,
|
||||
on_stdout = function(lines)
|
||||
if not buf then
|
||||
buf = select(1, create_output_win({ header, "" }))
|
||||
end
|
||||
if not has_output then
|
||||
local cur = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
if #cur > 0 and cur[#cur] == "[running...]" then
|
||||
vim.api.nvim_buf_set_lines(buf, #cur - 1, #cur, false, {})
|
||||
if parser then
|
||||
collect_output(lines)
|
||||
if parser.on_line then
|
||||
for _, line in ipairs(lines or {}) do
|
||||
local ok_parse, results = pcall(parser.on_line, line, parser_state)
|
||||
if ok_parse then
|
||||
handle_parsed(results)
|
||||
end
|
||||
end
|
||||
end
|
||||
has_output = true
|
||||
return
|
||||
end
|
||||
ensure_output_started()
|
||||
append_lines(buf, lines)
|
||||
end,
|
||||
on_stderr = function(lines)
|
||||
if not buf then
|
||||
buf = select(1, create_output_win({ header, "" }))
|
||||
end
|
||||
if not has_output then
|
||||
local cur = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
if #cur > 0 and cur[#cur] == "[running...]" then
|
||||
vim.api.nvim_buf_set_lines(buf, #cur - 1, #cur, false, {})
|
||||
if parser then
|
||||
collect_output(lines)
|
||||
if parser.on_line then
|
||||
for _, line in ipairs(lines or {}) do
|
||||
local ok_parse, results = pcall(parser.on_line, line, parser_state)
|
||||
if ok_parse then
|
||||
handle_parsed(results)
|
||||
end
|
||||
end
|
||||
end
|
||||
has_output = true
|
||||
return
|
||||
end
|
||||
ensure_output_started()
|
||||
append_lines(buf, lines)
|
||||
end,
|
||||
on_exit = function(code)
|
||||
if not buf then
|
||||
buf = select(1, create_output_win({ header }))
|
||||
end
|
||||
if not has_output then
|
||||
local cur = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
if #cur > 0 and cur[#cur] == "[running...]" then
|
||||
vim.api.nvim_buf_set_lines(buf, #cur - 1, #cur, false, {})
|
||||
if parser and parser.on_complete then
|
||||
local output = table.concat(output_lines, "\n")
|
||||
local ok_parse, results = pcall(parser.on_complete, output, parser_state)
|
||||
if ok_parse then
|
||||
handle_parsed(results)
|
||||
end
|
||||
end
|
||||
append_lines(buf, { "", "[exit code] " .. tostring(code) })
|
||||
if parser then
|
||||
if not had_parsed_output and #output_lines > 0 then
|
||||
ensure_output_started()
|
||||
append_lines(buf, output_lines)
|
||||
elseif not has_output then
|
||||
ensure_output_started()
|
||||
end
|
||||
append_lines(buf, { "", "[exit code] " .. tostring(code) })
|
||||
else
|
||||
if not has_output then
|
||||
local cur = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
if #cur > 0 and cur[#cur] == "[running...]" then
|
||||
vim.api.nvim_buf_set_lines(buf, #cur - 1, #cur, false, {})
|
||||
end
|
||||
end
|
||||
append_lines(buf, { "", "[exit code] " .. tostring(code) })
|
||||
end
|
||||
if options.track_scope then
|
||||
state.last_scope_exit_code = code
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
@@ -405,7 +526,16 @@ function M.run_nearest()
|
||||
return
|
||||
end
|
||||
|
||||
run_command(command)
|
||||
local parser = runner.output_parser
|
||||
if type(parser) == "function" then
|
||||
parser = parser()
|
||||
end
|
||||
run_command(command, {
|
||||
track_scope = true,
|
||||
runner = runner,
|
||||
scope_kind = "nearest",
|
||||
output_parser = parser or runner.parse_results,
|
||||
})
|
||||
end
|
||||
|
||||
function M.run_file()
|
||||
@@ -428,7 +558,16 @@ function M.run_file()
|
||||
return
|
||||
end
|
||||
|
||||
run_command(command)
|
||||
local parser = runner.output_parser
|
||||
if type(parser) == "function" then
|
||||
parser = parser()
|
||||
end
|
||||
run_command(command, {
|
||||
track_scope = true,
|
||||
runner = runner,
|
||||
scope_kind = "file",
|
||||
output_parser = parser or runner.parse_results,
|
||||
})
|
||||
end
|
||||
|
||||
function M.run_all()
|
||||
@@ -451,7 +590,59 @@ function M.run_all()
|
||||
return
|
||||
end
|
||||
|
||||
run_command(command)
|
||||
local parser = runner.output_parser
|
||||
if type(parser) == "function" then
|
||||
parser = parser()
|
||||
end
|
||||
run_command(command, {
|
||||
track_scope = true,
|
||||
runner = runner,
|
||||
scope_kind = "all",
|
||||
output_parser = parser or runner.parse_results,
|
||||
})
|
||||
end
|
||||
|
||||
local function build_failed_only_command()
|
||||
if not (state.last_scope_command and type(state.last_scope_command.cmd) == "table") then
|
||||
return nil, "[test-samurai] No previous scoped test command"
|
||||
end
|
||||
|
||||
local failures = state.last_scope_failures or {}
|
||||
if #failures == 0 then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
local runner = state.last_scope_runner
|
||||
if not runner or type(runner.build_failed_command) ~= "function" then
|
||||
local name = runner and runner.name or "unknown"
|
||||
return nil, "[test-samurai] Runner does not support failed-only: " .. name
|
||||
end
|
||||
|
||||
local ok_build, command = pcall(runner.build_failed_command, state.last_scope_command, failures, state.last_scope_kind)
|
||||
if not ok_build or not command or type(command.cmd) ~= "table" or #command.cmd == 0 then
|
||||
return nil, "[test-samurai] Runner failed to build failed-only command"
|
||||
end
|
||||
|
||||
return command, nil
|
||||
end
|
||||
|
||||
function M.run_failed_only()
|
||||
if not (state.last_scope_command and type(state.last_scope_command.cmd) == "table") then
|
||||
vim.notify("[test-samurai] No previous scoped test command", vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local command, err = build_failed_only_command()
|
||||
if not command then
|
||||
if not err then
|
||||
M.run_last()
|
||||
return
|
||||
end
|
||||
vim.notify(err, vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
run_command(command, { save_last = false })
|
||||
end
|
||||
|
||||
function M.show_output()
|
||||
|
||||
Reference in New Issue
Block a user