From 80f28539993badd13a37c590b865102705936659 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Fri, 6 Mar 2026 18:26:05 -0500 Subject: [PATCH] refactor(race): replace `:CP race` subcommand with `--race` flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Race was the only command using `:CP `. Every other platform+contest command uses `:CP [flags]`. Solution: Make race a flag on contest setup: `:CP --race`. Remove `:CP race stop` — starting a new race auto-cancels any active one. Remove `(cp-race-stop)` keymap. Update tab completion for `--race`. --- lua/cp/commands/init.lua | 76 +++++++++++++++++++++++----------------- lua/cp/constants.lua | 1 - lua/cp/race.lua | 9 ++--- plugin/cp.lua | 57 +++++++++++------------------- 4 files changed, 68 insertions(+), 75 deletions(-) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index f4368ce..d28de00 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -24,6 +24,7 @@ local actions = constants.ACTIONS ---@field mode? string ---@field debug? boolean ---@field language? string +---@field race? boolean ---@field subcommand? string ---@param str string @@ -70,28 +71,6 @@ local function parse_command(args) else return { type = 'error', message = 'unknown cache subcommand: ' .. subcommand } end - elseif first == 'race' then - if args[2] == 'stop' then - return { type = 'action', action = 'race_stop', requires_context = false } - end - if not args[2] or not args[3] then - return { - type = 'error', - message = 'Usage: :CP race [--lang ]', - } - end - local language = nil - if args[4] == '--lang' and args[5] then - language = args[5] - end - return { - type = 'action', - action = 'race', - requires_context = false, - platform = args[2], - contest = args[3], - language = language, - } elseif first == 'interact' then local inter = args[2] if inter and inter ~= '' then @@ -295,6 +274,17 @@ local function parse_command(args) platform = first, contest = contest, } + elseif #args == 3 and args[3] == '--race' then + local contest = args[2] + if first == 'codeforces' then + contest = canonicalize_cf_contest(contest) + end + return { + type = 'contest_setup', + platform = first, + contest = contest, + race = true, + } elseif #args == 4 and args[3] == '--lang' then local contest = args[2] if first == 'codeforces' then @@ -306,10 +296,35 @@ local function parse_command(args) contest = contest, language = args[4], } + elseif #args == 5 then + local contest = args[2] + if first == 'codeforces' then + contest = canonicalize_cf_contest(contest) + end + local language, race = nil, false + if args[3] == '--race' and args[4] == '--lang' then + language = args[5] + race = true + elseif args[3] == '--lang' and args[5] == '--race' then + language = args[4] + race = true + else + return { + type = 'error', + message = 'Invalid arguments. Usage: :CP [--race] [--lang ]', + } + end + return { + type = 'contest_setup', + platform = first, + contest = contest, + language = language, + race = race, + } else return { type = 'error', - message = 'Invalid arguments. Usage: :CP [--lang ]', + message = 'Invalid arguments. Usage: :CP [--race] [--lang ]', } end end @@ -393,13 +408,6 @@ function M.handle_command(opts) require('cp.stress').toggle(cmd.generator_cmd, cmd.brute_cmd) elseif cmd.action == 'submit' then require('cp.submit').submit({ language = cmd.language }) - elseif cmd.action == 'race' then - if not check_platform_enabled(cmd.platform) then - return - end - require('cp.race').start(cmd.platform, cmd.contest, cmd.language) - elseif cmd.action == 'race_stop' then - require('cp.race').stop() elseif cmd.action == 'open' then local cache = require('cp.cache') cache.load() @@ -470,8 +478,12 @@ function M.handle_command(opts) if not check_platform_enabled(cmd.platform) then return end - local setup = require('cp.setup') - setup.setup_contest(cmd.platform, cmd.contest, nil, cmd.language) + if cmd.race then + require('cp.race').start(cmd.platform, cmd.contest, cmd.language) + else + local setup = require('cp.setup') + setup.setup_contest(cmd.platform, cmd.contest, nil, cmd.language) + end return end end diff --git a/lua/cp/constants.lua b/lua/cp/constants.lua index d2d306e..b227d53 100644 --- a/lua/cp/constants.lua +++ b/lua/cp/constants.lua @@ -10,7 +10,6 @@ M.ACTIONS = { 'cache', 'interact', 'edit', - 'race', 'stress', 'submit', 'open', diff --git a/lua/cp/race.lua b/lua/cp/race.lua index 5b49fc1..bbc0960 100644 --- a/lua/cp/race.lua +++ b/lua/cp/race.lua @@ -39,8 +39,7 @@ function M.start(platform, contest_id, language) return end if race_state.timer then - logger.log('Race already active. Use :CP race stop first.', { level = vim.log.levels.WARN }) - return + M.stop() end cache.load() @@ -48,7 +47,7 @@ function M.start(platform, contest_id, language) local display = constants.PLATFORM_DISPLAY_NAMES[platform] or platform local cached_countdown = cache.get_supports_countdown(platform) if cached_countdown == false then - logger.log(('%s does not support :CP race'):format(display), { level = vim.log.levels.ERROR }) + logger.log(('%s does not support --race'):format(display), { level = vim.log.levels.ERROR }) return end @@ -65,7 +64,7 @@ function M.start(platform, contest_id, language) if sc == false then cache.set_contest_summaries(platform, result.contests or {}, { supports_countdown = false }) logger.log( - ('%s does not support :CP race'):format(display), + ('%s does not support --race'):format(display), { level = vim.log.levels.ERROR } ) return @@ -138,7 +137,6 @@ end function M.stop() local timer = race_state.timer if not timer then - logger.log('No active race', { level = vim.log.levels.WARN }) return end timer:stop() @@ -149,7 +147,6 @@ function M.stop() race_state.contest_name = nil race_state.language = nil race_state.start_time = nil - logger.log('Race cancelled', { level = vim.log.levels.INFO, override = true }) end function M.status() diff --git a/plugin/cp.lua b/plugin/cp.lua index cc6a367..531a5f3 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -108,13 +108,6 @@ end, { end end return filter_candidates(candidates) - elseif args[2] == 'race' then - if require('cp.race').status().active then - return filter_candidates({ 'stop' }) - end - local candidates = { 'stop' } - vim.list_extend(candidates, platforms) - return filter_candidates(candidates) elseif args[2] == 'open' then return filter_candidates({ 'problem', 'contest', 'standings' }) elseif args[2] == 'next' or args[2] == 'prev' or args[2] == 'pick' then @@ -129,15 +122,6 @@ end, { if args[2] == 'stress' then local utils = require('cp.utils') return filter_candidates(utils.cwd_executables()) - elseif - args[2] == 'race' - and not require('cp.race').status().active - and vim.tbl_contains(platforms, args[3]) - then - local cache = require('cp.cache') - cache.load() - local contests = cache.get_cached_contest_ids(args[3]) - return filter_candidates(contests) elseif args[2] == 'cache' and args[3] == 'clear' then local candidates = vim.list_extend({}, platforms) table.insert(candidates, '') @@ -152,6 +136,9 @@ end, { cache.load() local contest_data = cache.get_contest_data(args[2], args[3]) local candidates = { '--lang' } + if not require('cp.race').status().active then + table.insert(candidates, '--race') + end if contest_data and contest_data.problems then for _, problem in ipairs(contest_data.problems) do table.insert(candidates, problem.id) @@ -160,34 +147,35 @@ end, { return filter_candidates(candidates) end elseif num_args == 5 then - if - args[2] == 'race' - and not require('cp.race').status().active - and vim.tbl_contains(platforms, args[3]) - then - return filter_candidates({ '--lang' }) - elseif args[2] == 'cache' and args[3] == 'clear' and vim.tbl_contains(platforms, args[4]) then + if args[2] == 'cache' and args[3] == 'clear' and vim.tbl_contains(platforms, args[4]) then local cache = require('cp.cache') cache.load() local contests = cache.get_cached_contest_ids(args[4]) return filter_candidates(contests) elseif vim.tbl_contains(platforms, args[2]) then - if args[4] == '--lang' then + if args[3] == '--race' then + return filter_candidates({ '--lang' }) + elseif args[4] == '--lang' then return filter_candidates(get_enabled_languages(args[2])) + elseif args[3] == '--lang' then + local candidates = {} + if not require('cp.race').status().active then + table.insert(candidates, '--race') + end + return filter_candidates(candidates) else return filter_candidates({ '--lang' }) end end elseif num_args == 6 then - if - args[2] == 'race' - and not require('cp.race').status().active - and vim.tbl_contains(platforms, args[3]) - and args[5] == '--lang' - then - return filter_candidates(get_enabled_languages(args[3])) - elseif vim.tbl_contains(platforms, args[2]) and args[5] == '--lang' then - return filter_candidates(get_enabled_languages(args[2])) + if vim.tbl_contains(platforms, args[2]) then + if args[3] == '--race' and args[4] == '--lang' then + return filter_candidates(get_enabled_languages(args[2])) + elseif args[3] == '--lang' and args[5] == '--race' then + return {} + elseif args[5] == '--lang' then + return filter_candidates(get_enabled_languages(args[2])) + end end end return {} @@ -209,6 +197,3 @@ vim.keymap.set('n', '(cp-pick)', cp_action('pick'), { desc = 'CP pick cont vim.keymap.set('n', '(cp-interact)', cp_action('interact'), { desc = 'CP interactive mode' }) vim.keymap.set('n', '(cp-stress)', cp_action('stress'), { desc = 'CP stress test' }) vim.keymap.set('n', '(cp-submit)', cp_action('submit'), { desc = 'CP submit solution' }) -vim.keymap.set('n', '(cp-race-stop)', function() - require('cp.race').stop() -end, { desc = 'CP stop race countdown' })