Merge main into feat/io/view-togggle
Resolved conflicts: - scrapers/atcoder.py: kept defensive if tests else '' checks - scrapers/codechef.py: kept defensive if tests else '' checks - tests/test_scrapers.py: kept comprehensive validation from main - lua/cp/ui/views.lua: removed misplaced navigation code from loop
This commit is contained in:
commit
0e778a128e
7 changed files with 197 additions and 62 deletions
|
|
@ -17,8 +17,11 @@ local actions = constants.ACTIONS
|
|||
---@field problem_id? string
|
||||
---@field interactor_cmd? string
|
||||
---@field test_index? integer
|
||||
---@field test_indices? integer[]
|
||||
---@field mode? string
|
||||
---@field debug? boolean
|
||||
---@field language? string
|
||||
---@field subcommand? string
|
||||
|
||||
--- Turn raw args into normalized structure to later dispatch
|
||||
---@param args string[] The raw command-line mode args
|
||||
|
|
@ -75,7 +78,7 @@ local function parse_command(args)
|
|||
return { type = 'action', action = 'edit', test_index = test_index }
|
||||
elseif first == 'run' or first == 'panel' then
|
||||
local debug = false
|
||||
local test_index = nil
|
||||
local test_indices = nil
|
||||
local mode = 'combined'
|
||||
|
||||
if #args == 2 then
|
||||
|
|
@ -84,20 +87,39 @@ local function parse_command(args)
|
|||
elseif args[2] == 'all' then
|
||||
mode = 'individual'
|
||||
else
|
||||
local idx = tonumber(args[2])
|
||||
if not idx then
|
||||
return {
|
||||
type = 'error',
|
||||
message = ("Invalid argument '%s': expected test number, 'all', or --debug"):format(
|
||||
args[2]
|
||||
),
|
||||
}
|
||||
if args[2]:find(',') then
|
||||
local indices = {}
|
||||
for num in args[2]:gmatch('[^,]+') do
|
||||
local idx = tonumber(num)
|
||||
if not idx or idx < 1 or idx ~= math.floor(idx) then
|
||||
return {
|
||||
type = 'error',
|
||||
message = ("Invalid test index '%s' in list"):format(num),
|
||||
}
|
||||
end
|
||||
table.insert(indices, idx)
|
||||
end
|
||||
if #indices == 0 then
|
||||
return { type = 'error', message = 'No valid test indices provided' }
|
||||
end
|
||||
test_indices = indices
|
||||
mode = 'individual'
|
||||
else
|
||||
local idx = tonumber(args[2])
|
||||
if not idx then
|
||||
return {
|
||||
type = 'error',
|
||||
message = ("Invalid argument '%s': expected test number(s), 'all', or --debug"):format(
|
||||
args[2]
|
||||
),
|
||||
}
|
||||
end
|
||||
if idx < 1 or idx ~= math.floor(idx) then
|
||||
return { type = 'error', message = ("'%s' is not a valid test index"):format(idx) }
|
||||
end
|
||||
test_indices = { idx }
|
||||
mode = 'individual'
|
||||
end
|
||||
if idx < 1 or idx ~= math.floor(idx) then
|
||||
return { type = 'error', message = ("'%s' is not a valid test index"):format(idx) }
|
||||
end
|
||||
test_index = idx
|
||||
mode = 'individual'
|
||||
end
|
||||
elseif #args == 3 then
|
||||
if args[2] == 'all' then
|
||||
|
|
@ -109,6 +131,30 @@ local function parse_command(args)
|
|||
}
|
||||
end
|
||||
debug = true
|
||||
elseif args[2]:find(',') then
|
||||
local indices = {}
|
||||
for num in args[2]:gmatch('[^,]+') do
|
||||
local idx = tonumber(num)
|
||||
if not idx or idx < 1 or idx ~= math.floor(idx) then
|
||||
return {
|
||||
type = 'error',
|
||||
message = ("Invalid test index '%s' in list"):format(num),
|
||||
}
|
||||
end
|
||||
table.insert(indices, idx)
|
||||
end
|
||||
if #indices == 0 then
|
||||
return { type = 'error', message = 'No valid test indices provided' }
|
||||
end
|
||||
if args[3] ~= '--debug' then
|
||||
return {
|
||||
type = 'error',
|
||||
message = ("Invalid argument '%s': expected --debug"):format(args[3]),
|
||||
}
|
||||
end
|
||||
test_indices = indices
|
||||
mode = 'individual'
|
||||
debug = true
|
||||
else
|
||||
local idx = tonumber(args[2])
|
||||
if not idx then
|
||||
|
|
@ -126,21 +172,23 @@ local function parse_command(args)
|
|||
message = ("Invalid argument '%s': expected --debug"):format(args[3]),
|
||||
}
|
||||
end
|
||||
test_index = idx
|
||||
test_indices = { idx }
|
||||
mode = 'individual'
|
||||
debug = true
|
||||
end
|
||||
elseif #args > 3 then
|
||||
return {
|
||||
type = 'error',
|
||||
message = 'Too many arguments. Usage: :CP ' .. first .. ' [all|test_num] [--debug]',
|
||||
message = 'Too many arguments. Usage: :CP '
|
||||
.. first
|
||||
.. ' [all|test_num[,test_num...]] [--debug]',
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
type = 'action',
|
||||
action = first,
|
||||
test_index = test_index,
|
||||
test_indices = test_indices,
|
||||
debug = debug,
|
||||
mode = mode,
|
||||
}
|
||||
|
|
@ -221,9 +269,12 @@ function M.handle_command(opts)
|
|||
if cmd.action == 'interact' then
|
||||
ui.toggle_interactive(cmd.interactor_cmd)
|
||||
elseif cmd.action == 'run' then
|
||||
ui.run_io_view(cmd.test_index, cmd.debug, cmd.mode)
|
||||
ui.run_io_view(cmd.test_indices, cmd.debug, cmd.mode)
|
||||
elseif cmd.action == 'panel' then
|
||||
ui.toggle_panel({ debug = cmd.debug, test_index = cmd.test_index })
|
||||
ui.toggle_panel({
|
||||
debug = cmd.debug,
|
||||
test_index = cmd.test_indices and cmd.test_indices[1] or nil,
|
||||
})
|
||||
elseif cmd.action == 'next' then
|
||||
setup.navigate_problem(1, cmd.language)
|
||||
elseif cmd.action == 'prev' then
|
||||
|
|
|
|||
|
|
@ -274,10 +274,25 @@ local function save_all_tests()
|
|||
local is_multi_test = contest_data.problems[contest_data.index_map[problem_id]].multi_test
|
||||
or false
|
||||
|
||||
-- Generate combined test from individual test cases
|
||||
local combined_input = table.concat(
|
||||
vim.tbl_map(function(tc)
|
||||
return tc.input
|
||||
end, edit_state.test_cases),
|
||||
'\n'
|
||||
)
|
||||
local combined_expected = table.concat(
|
||||
vim.tbl_map(function(tc)
|
||||
return tc.expected
|
||||
end, edit_state.test_cases),
|
||||
'\n'
|
||||
)
|
||||
|
||||
cache.set_test_cases(
|
||||
platform,
|
||||
contest_id,
|
||||
problem_id,
|
||||
{ input = combined_input, expected = combined_expected },
|
||||
edit_state.test_cases,
|
||||
edit_state.constraints and edit_state.constraints.timeout_ms or 0,
|
||||
edit_state.constraints and edit_state.constraints.memory_mb or 0,
|
||||
|
|
|
|||
|
|
@ -405,7 +405,7 @@ function M.ensure_io_view()
|
|||
end
|
||||
end
|
||||
|
||||
function M.run_io_view(test_index, debug, mode)
|
||||
function M.run_io_view(test_indices_arg, debug, mode)
|
||||
mode = mode or 'combined'
|
||||
|
||||
local platform, contest_id, problem_id =
|
||||
|
|
@ -425,6 +425,13 @@ function M.run_io_view(test_index, debug, mode)
|
|||
return
|
||||
end
|
||||
|
||||
if mode == 'combined' then
|
||||
local test_cases = cache.get_test_cases(platform, contest_id, problem_id)
|
||||
if test_cases and #test_cases > 1 then
|
||||
mode = 'individual'
|
||||
end
|
||||
end
|
||||
|
||||
M.ensure_io_view()
|
||||
|
||||
local run = require('cp.runner.run')
|
||||
|
|
@ -447,19 +454,21 @@ function M.run_io_view(test_index, debug, mode)
|
|||
if mode == 'individual' then
|
||||
local test_state = run.get_panel_state()
|
||||
|
||||
if test_index then
|
||||
if test_index < 1 or test_index > #test_state.test_cases then
|
||||
logger.log(
|
||||
string.format(
|
||||
'Test %d does not exist (only %d tests available)',
|
||||
test_index,
|
||||
#test_state.test_cases
|
||||
),
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
return
|
||||
if test_indices_arg then
|
||||
for _, idx in ipairs(test_indices_arg) do
|
||||
if idx < 1 or idx > #test_state.test_cases then
|
||||
logger.log(
|
||||
string.format(
|
||||
'Test %d does not exist (only %d tests available)',
|
||||
idx,
|
||||
#test_state.test_cases
|
||||
),
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
return
|
||||
end
|
||||
end
|
||||
test_indices = { test_index }
|
||||
test_indices = test_indices_arg
|
||||
else
|
||||
for i = 1, #test_state.test_cases do
|
||||
test_indices[i] = i
|
||||
|
|
@ -512,6 +521,11 @@ function M.run_io_view(test_index, debug, mode)
|
|||
if mode == 'combined' then
|
||||
local combined = cache.get_combined_test(platform, contest_id, problem_id)
|
||||
|
||||
if not combined then
|
||||
logger.log('No combined test found', vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
run.load_test_cases()
|
||||
|
||||
local result = run.run_combined_test(debug)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue