mark listing entry when details are visible
All checks were successful
tests / test (push) Successful in 10s

This commit is contained in:
2026-01-20 09:59:21 +01:00
parent 8c598002e4
commit 456a157549
4 changed files with 49 additions and 0 deletions

View File

@@ -91,6 +91,7 @@ Before running any test command, test-samurai runs `:wall` to save all buffers.
- ANSI color translation is only applied in the **Detail-Float**; the **Test-Listing-Float** shows raw text without ANSI translation. - ANSI color translation is only applied in the **Detail-Float**; the **Test-Listing-Float** shows raw text without ANSI translation.
- `<esc><esc>` hides the floating window and restores the cursor position; `TSamShowOutput` reopens it. - `<esc><esc>` hides the floating window and restores the cursor position; `TSamShowOutput` reopens it.
- If no output is captured for a test, the **Detail-Float** shows `No output captured`. - If no output is captured for a test, the **Detail-Float** shows `No output captured`.
- The active listing entry is highlighted while the **Detail-Float** is visible.
- Summary lines (`TOTAL`/`DURATION`) are appended in the listing output, including `TSamLast`. - Summary lines (`TOTAL`/`DURATION`) are appended in the listing output, including `TSamLast`.
## Runner architecture ## Runner architecture

View File

@@ -73,6 +73,7 @@ Testing-Float:
<C-c> Close Detail-Float (when focused) <C-c> Close Detail-Float (when focused)
Notes: Notes:
Active listing entry is highlighted while the Detail-Float is visible.
Buffers are saved via :wall before every test run. Buffers are saved via :wall before every test run.

View File

@@ -28,6 +28,7 @@ local state = {
trigger_cursor = nil, trigger_cursor = nil,
listing_unfiltered_lines = nil, listing_unfiltered_lines = nil,
listing_filtered_kind = nil, listing_filtered_kind = nil,
detail_line = nil,
hardtime_refcount = 0, hardtime_refcount = 0,
hardtime_was_enabled = false, hardtime_was_enabled = false,
autocmds_set = false, autocmds_set = false,
@@ -37,6 +38,7 @@ local summary_ns = vim.api.nvim_create_namespace("TestSamuraiSummary")
local result_ns = vim.api.nvim_create_namespace("TestSamuraiResult") local result_ns = vim.api.nvim_create_namespace("TestSamuraiResult")
local detail_ns = vim.api.nvim_create_namespace("TestSamuraiDetailAnsi") local detail_ns = vim.api.nvim_create_namespace("TestSamuraiDetailAnsi")
local help_ns = vim.api.nvim_create_namespace("TestSamuraiHelp") local help_ns = vim.api.nvim_create_namespace("TestSamuraiHelp")
local listing_sel_ns = vim.api.nvim_create_namespace("TestSamuraiListingSelection")
local apply_border_kind local apply_border_kind
local close_container local close_container
local restore_listing_full local restore_listing_full
@@ -100,6 +102,7 @@ local function help_lines()
"", "",
"Notes:", "Notes:",
" No output captured -> shows placeholder text", " No output captured -> shows placeholder text",
" Active listing entry is highlighted while Detail-Float is visible",
" Buffers are saved via :wall before every test run", " Buffers are saved via :wall before every test run",
} }
end end
@@ -149,6 +152,7 @@ local function apply_listing_lines(buf, lines)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.api.nvim_buf_clear_namespace(buf, result_ns, 0, -1) vim.api.nvim_buf_clear_namespace(buf, result_ns, 0, -1)
vim.api.nvim_buf_clear_namespace(buf, summary_ns, 0, -1) vim.api.nvim_buf_clear_namespace(buf, summary_ns, 0, -1)
vim.api.nvim_buf_clear_namespace(buf, listing_sel_ns, 0, -1)
apply_result_highlights(buf, 0, lines) apply_result_highlights(buf, 0, lines)
apply_summary_highlights(buf, 0, lines) apply_summary_highlights(buf, 0, lines)
rebuild_result_line_map(lines) rebuild_result_line_map(lines)
@@ -382,6 +386,30 @@ local function jump_listing_and_open(kind)
end end
end end
local function clear_listing_selection()
if state.last_buf and vim.api.nvim_buf_is_valid(state.last_buf) then
vim.api.nvim_buf_clear_namespace(state.last_buf, listing_sel_ns, 0, -1)
end
state.detail_line = nil
end
local function apply_listing_selection(line)
if not (state.last_buf and vim.api.nvim_buf_is_valid(state.last_buf)) then
return
end
vim.api.nvim_buf_clear_namespace(state.last_buf, listing_sel_ns, 0, -1)
if not line then
state.detail_line = nil
return
end
local total = vim.api.nvim_buf_line_count(state.last_buf)
if line < 1 or line > total then
return
end
vim.api.nvim_buf_add_highlight(state.last_buf, listing_sel_ns, "TestSamuraiListingActive", line - 1, 0, -1)
state.detail_line = line
end
local function find_normal_window() local function find_normal_window()
for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
local cfg = vim.api.nvim_win_get_config(win) local cfg = vim.api.nvim_win_get_config(win)
@@ -534,6 +562,7 @@ local function setup_summary_highlights()
pcall(vim.api.nvim_set_hl, 0, "TestSamuraiResultSkip", { fg = skip_fg }) pcall(vim.api.nvim_set_hl, 0, "TestSamuraiResultSkip", { fg = skip_fg })
pcall(vim.api.nvim_set_hl, 0, "TestSamuraiBorderPass", { fg = pass_fg, bold = true }) pcall(vim.api.nvim_set_hl, 0, "TestSamuraiBorderPass", { fg = pass_fg, bold = true })
pcall(vim.api.nvim_set_hl, 0, "TestSamuraiBorderFail", { fg = fail_fg, bold = true }) pcall(vim.api.nvim_set_hl, 0, "TestSamuraiBorderFail", { fg = fail_fg, bold = true })
pcall(vim.api.nvim_set_hl, 0, "TestSamuraiListingActive", { link = "Visual" })
end end
local function load_runners() local function load_runners()
@@ -567,6 +596,7 @@ local function ensure_output_autocmds()
if state.detail_win and closed == state.detail_win then if state.detail_win and closed == state.detail_win then
state.detail_win = nil state.detail_win = nil
restore_listing_full() restore_listing_full()
clear_listing_selection()
hardtime_restore() hardtime_restore()
return return
end end
@@ -577,6 +607,7 @@ local function ensure_output_autocmds()
pcall(vim.api.nvim_win_close, state.detail_win, true) pcall(vim.api.nvim_win_close, state.detail_win, true)
state.detail_win = nil state.detail_win = nil
end end
clear_listing_selection()
return return
end end
end, end,
@@ -744,6 +775,7 @@ close_container = function()
pcall(vim.api.nvim_win_close, state.last_win, true) pcall(vim.api.nvim_win_close, state.last_win, true)
state.last_win = nil state.last_win = nil
end end
clear_listing_selection()
end end
local function close_container_and_restore() local function close_container_and_restore()
@@ -763,6 +795,7 @@ close_detail_float = function()
if state.detail_win and vim.api.nvim_win_is_valid(state.detail_win) then if state.detail_win and vim.api.nvim_win_is_valid(state.detail_win) then
pcall(vim.api.nvim_win_close, state.detail_win, true) pcall(vim.api.nvim_win_close, state.detail_win, true)
end end
clear_listing_selection()
end end
restore_listing_full = function() restore_listing_full = function()
@@ -1472,10 +1505,12 @@ function M.open_test_output_at_cursor()
end end
if type(output) ~= "table" or #output == 0 then if type(output) ~= "table" or #output == 0 then
open_detail_split({ "", "No output captured" }, "default") open_detail_split({ "", "No output captured" }, "default")
apply_listing_selection(line)
return return
end end
local border_kind = status and status:lower() or nil local border_kind = status and status:lower() or nil
open_detail_split(output, border_kind) open_detail_split(output, border_kind)
apply_listing_selection(line)
end end
function M.show_help() function M.show_help()
@@ -1485,6 +1520,7 @@ function M.show_help()
end end
local lines = help_lines() local lines = help_lines()
open_detail_split(lines, "default") open_detail_split(lines, "default")
clear_listing_selection()
apply_help_highlights(state.detail_buf, lines) apply_help_highlights(state.detail_buf, lines)
end end

View File

@@ -1006,6 +1006,17 @@ describe("test-samurai core (no bundled runners)", function()
local detail_buf = vim.api.nvim_get_current_buf() local detail_buf = vim.api.nvim_get_current_buf()
local detail_lines = vim.api.nvim_buf_get_lines(detail_buf, 0, -1, false) local detail_lines = vim.api.nvim_buf_get_lines(detail_buf, 0, -1, false)
assert.same({ "", "No output captured" }, detail_lines) assert.same({ "", "No output captured" }, detail_lines)
local selection_ns = vim.api.nvim_create_namespace("TestSamuraiListingSelection")
local marks = vim.api.nvim_buf_get_extmarks(listing_buf, selection_ns, 0, -1, { details = true })
assert.is_true(#marks > 0)
local highlighted = false
for _, mark in ipairs(marks) do
if mark[2] == target - 1 then
highlighted = true
break
end
end
assert.is_true(highlighted)
vim.fn.jobstart = orig_jobstart vim.fn.jobstart = orig_jobstart
end) end)