From e1c8c4beaf27858638106133426dadb21c5deeee Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Tue, 4 Nov 2025 21:45:45 -0500 Subject: [PATCH] feat(cli): :CP run with numbered test cases --- lua/cp/commands/init.lua | 86 +++++++++++++++++++++++++++++++--------- lua/cp/ui/views.lua | 30 +++++++------- 2 files changed, 83 insertions(+), 33 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index dc492dd..c72483e 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -75,7 +75,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 +84,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 +128,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 +169,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 +266,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 diff --git a/lua/cp/ui/views.lua b/lua/cp/ui/views.lua index c076e21..4bb99ad 100644 --- a/lua/cp/ui/views.lua +++ b/lua/cp/ui/views.lua @@ -287,7 +287,7 @@ function M.ensure_io_view() return end io_view_state.current_test_index = new_index - M.run_io_view(new_index) + M.run_io_view({ new_index }, false, 'individual') end if cfg.ui.run.next_test_key then @@ -338,7 +338,7 @@ function M.ensure_io_view() vim.api.nvim_set_current_win(solution_win) 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 = @@ -380,19 +380,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