feat: :CP test -> :CP run

This commit is contained in:
Barrett Ruth 2025-09-19 18:53:39 -04:00
parent ef3d39c7f4
commit dd6bf47684
7 changed files with 64 additions and 90 deletions

View file

@ -31,9 +31,8 @@
---@field before_debug? fun(ctx: ProblemContext)
---@field setup_code? fun(ctx: ProblemContext)
---@class TestPanelConfig
---@class RunPanelConfig
---@field diff_mode "vim"|"git" Diff backend to use
---@field toggle_key string Key to toggle test panel
---@field next_test_key string Key to navigate to next test case
---@field prev_test_key string Key to navigate to previous test case
@ -51,7 +50,7 @@
---@field debug boolean
---@field scrapers table<string, boolean>
---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string
---@field test_panel TestPanelConfig
---@field run_panel RunPanelConfig
---@field diff DiffConfig
---@class cp.UserConfig
@ -61,7 +60,7 @@
---@field debug? boolean
---@field scrapers? table<string, boolean>
---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string
---@field test_panel? TestPanelConfig
---@field run_panel? RunPanelConfig
---@field diff? DiffConfig
local M = {}
@ -79,9 +78,8 @@ M.defaults = {
debug = false,
scrapers = constants.PLATFORMS,
filename = nil,
test_panel = {
run_panel = {
diff_mode = 'vim',
toggle_key = 't',
next_test_key = '<c-n>',
prev_test_key = '<c-p>',
},
@ -108,7 +106,7 @@ function M.setup(user_config)
debug = { user_config.debug, { 'boolean', 'nil' }, true },
scrapers = { user_config.scrapers, { 'table', 'nil' }, true },
filename = { user_config.filename, { 'function', 'nil' }, true },
test_panel = { user_config.test_panel, { 'table', 'nil' }, true },
run_panel = { user_config.run_panel, { 'table', 'nil' }, true },
diff = { user_config.diff, { 'table', 'nil' }, true },
})
@ -132,31 +130,24 @@ function M.setup(user_config)
})
end
if user_config.test_panel then
if user_config.run_panel then
vim.validate({
diff_mode = {
user_config.test_panel.diff_mode,
user_config.run_panel.diff_mode,
function(value)
return vim.tbl_contains({ 'vim', 'git' }, value)
end,
"diff_mode must be 'vim' or 'git'",
},
toggle_key = {
user_config.test_panel.toggle_key,
function(value)
return type(value) == 'string' and value ~= ''
end,
'toggle_key must be a non-empty string',
},
next_test_key = {
user_config.test_panel.next_test_key,
user_config.run_panel.next_test_key,
function(value)
return type(value) == 'string' and value ~= ''
end,
'next_test_key must be a non-empty string',
},
prev_test_key = {
user_config.test_panel.prev_test_key,
user_config.run_panel.prev_test_key,
function(value)
return type(value) == 'string' and value ~= ''
end,

View file

@ -25,7 +25,7 @@ local state = {
saved_session = nil,
test_cases = nil,
test_states = {},
test_panel_active = false,
run_panel_active = false,
}
local constants = require('cp.constants')
@ -149,14 +149,14 @@ local function get_current_problem()
return filename
end
local function toggle_test_panel(is_debug)
if state.test_panel_active then
local function toggle_run_panel(is_debug)
if state.run_panel_active then
if state.saved_session then
vim.cmd(('source %s'):format(state.saved_session))
vim.fn.delete(state.saved_session)
state.saved_session = nil
end
state.test_panel_active = false
state.run_panel_active = false
logger.log('test panel closed')
return
end
@ -249,7 +249,7 @@ local function toggle_test_panel(is_debug)
end
local function update_expected_pane()
local test_state = test_module.get_test_panel_state()
local test_state = test_module.get_run_panel_state()
local current_test = test_state.test_cases[test_state.current_index]
if not current_test then
@ -262,7 +262,7 @@ local function toggle_test_panel(is_debug)
update_buffer_content(test_buffers.expected_buf, expected_lines, {})
local diff_backend = require('cp.diff')
local backend = diff_backend.get_best_backend(config.test_panel.diff_mode)
local backend = diff_backend.get_best_backend(config.run_panel.diff_mode)
if backend.name == 'vim' and current_test.status == 'fail' then
vim.api.nvim_set_option_value('diff', true, { win = test_windows.expected_win })
@ -272,7 +272,7 @@ local function toggle_test_panel(is_debug)
end
local function update_actual_pane()
local test_state = test_module.get_test_panel_state()
local test_state = test_module.get_run_panel_state()
local current_test = test_state.test_cases[test_state.current_index]
if not current_test then
@ -291,7 +291,7 @@ local function toggle_test_panel(is_debug)
if enable_diff then
local diff_backend = require('cp.diff')
local backend = diff_backend.get_best_backend(config.test_panel.diff_mode)
local backend = diff_backend.get_best_backend(config.run_panel.diff_mode)
if backend.name == 'git' then
local diff_result = backend.render(current_test.expected, current_test.actual)
@ -321,14 +321,14 @@ local function toggle_test_panel(is_debug)
end
end
local function refresh_test_panel()
local function refresh_run_panel()
if not test_buffers.tab_buf or not vim.api.nvim_buf_is_valid(test_buffers.tab_buf) then
return
end
local test_render = require('cp.test_render')
test_render.setup_highlights()
local test_state = test_module.get_test_panel_state()
local test_state = test_module.get_run_panel_state()
local tab_lines, tab_highlights = test_render.render_test_list(test_state)
update_buffer_content(test_buffers.tab_buf, tab_lines, tab_highlights)
@ -337,7 +337,7 @@ local function toggle_test_panel(is_debug)
end
local function navigate_test_case(delta)
local test_state = test_module.get_test_panel_state()
local test_state = test_module.get_run_panel_state()
if #test_state.test_cases == 0 then
return
end
@ -349,22 +349,19 @@ local function toggle_test_panel(is_debug)
test_state.current_index = 1
end
refresh_test_panel()
refresh_run_panel()
end
vim.keymap.set('n', config.test_panel.next_test_key, function()
vim.keymap.set('n', config.run_panel.next_test_key, function()
navigate_test_case(1)
end, { buffer = test_buffers.tab_buf, silent = true })
vim.keymap.set('n', config.test_panel.prev_test_key, function()
vim.keymap.set('n', config.run_panel.prev_test_key, function()
navigate_test_case(-1)
end, { buffer = test_buffers.tab_buf, silent = true })
for _, buf in pairs(test_buffers) do
vim.keymap.set('n', 'q', function()
toggle_test_panel()
end, { buffer = buf, silent = true })
vim.keymap.set('n', config.test_panel.toggle_key, function()
toggle_test_panel()
toggle_run_panel()
end, { buffer = buf, silent = true })
end
@ -382,14 +379,14 @@ local function toggle_test_panel(is_debug)
test_module.run_all_test_cases(ctx, contest_config)
end
refresh_test_panel()
refresh_run_panel()
vim.api.nvim_set_current_win(test_windows.tab_win)
state.test_panel_active = true
state.run_panel_active = true
state.test_buffers = test_buffers
state.test_windows = test_windows
local test_state = test_module.get_test_panel_state()
local test_state = test_module.get_run_panel_state()
logger.log(string.format('test panel opened (%d test cases)', #test_state.test_cases))
end
@ -556,8 +553,8 @@ function M.handle_command(opts)
end
if cmd.type == 'action' then
if cmd.action == 'test' then
toggle_test_panel(cmd.debug)
if cmd.action == 'run' then
toggle_run_panel(cmd.debug)
elseif cmd.action == 'next' then
navigate_problem(1, cmd.language)
elseif cmd.action == 'prev' then

View file

@ -12,7 +12,7 @@
---@field signal string?
---@field timed_out boolean?
---@class TestPanelState
---@class RunPanelState
---@field test_cases TestCase[]
---@field current_index number
---@field buffer number?
@ -24,8 +24,8 @@ local M = {}
local constants = require('cp.constants')
local logger = require('cp.log')
---@type TestPanelState
local test_panel_state = {
---@type RunPanelState
local run_panel_state = {
test_cases = {},
current_index = 1,
buffer = nil,
@ -227,8 +227,8 @@ function M.load_test_cases(ctx, state)
test_cases = parse_test_cases_from_files(ctx.input_file, ctx.expected_file)
end
test_panel_state.test_cases = test_cases
test_panel_state.current_index = 1
run_panel_state.test_cases = test_cases
run_panel_state.current_index = 1
logger.log(('loaded %d test case(s)'):format(#test_cases))
return #test_cases > 0
@ -239,7 +239,7 @@ end
---@param index number
---@return boolean
function M.run_test_case(ctx, contest_config, index)
local test_case = test_panel_state.test_cases[index]
local test_case = run_panel_state.test_cases[index]
if not test_case then
return false
end
@ -266,16 +266,16 @@ end
---@return TestCase[]
function M.run_all_test_cases(ctx, contest_config)
local results = {}
for i, _ in ipairs(test_panel_state.test_cases) do
for i, _ in ipairs(run_panel_state.test_cases) do
M.run_test_case(ctx, contest_config, i)
table.insert(results, test_panel_state.test_cases[i])
table.insert(results, run_panel_state.test_cases[i])
end
return results
end
---@return TestPanelState
function M.get_test_panel_state()
return test_panel_state
---@return RunPanelState
function M.get_run_panel_state()
return run_panel_state
end
return M

View file

@ -201,7 +201,7 @@ local function data_row(c, idx, tc, is_current)
return line, hi
end
---@param test_state TestPanelState
---@param test_state RunPanelState
---@return string[], table[] lines and highlight positions
function M.render_test_list(test_state)
local lines, highlights = {}, {}