diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 6501c17..e3afa98 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -64,10 +64,12 @@ COMMANDS *cp-commands* Stops at last problem (no wrapping). - Navigation Commands ~ :CP prev Navigate to previous problem in current contest. Stops at first problem (no wrapping). + :CP {problem_id} Jump to problem {problem_id} in a contest. + Requires that a contest has already been set up. + Cache Commands ~ :CP cache clear [contest] Clear the cache data (contest list, problem diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 2b58be3..73f3338 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -14,6 +14,7 @@ local actions = constants.ACTIONS ---@field message? string ---@field contest? string ---@field platform? string +---@field problem_id? string --- Turn raw args into normalized structure to later dispatch ---@param args string[] The raw command-line mode args @@ -70,16 +71,14 @@ local function parse_command(args) end end - if state.get_platform() and state.get_contest_id() then - local cache = require('cp.cache') - cache.load() + if #args == 1 then return { - type = 'error', - message = ("invalid subcommand '%s'"):format(first), + type = 'problem_jump', + problem_id = first, } end - return { type = 'error', message = 'Unknown command or no contest context' } + return { type = 'error', message = 'Unknown command or no contest context.' } end --- Core logic for handling `:CP ...` commands @@ -113,6 +112,30 @@ function M.handle_command(opts) local picker = require('cp.commands.picker') picker.handle_pick_action() end + elseif cmd.type == 'problem_jump' then + local platform = state.get_platform() + local contest_id = state.get_contest_id() + local problem_id = cmd.problem_id + + if not (platform and contest_id) then + logger.log('No contest is currently active.', vim.log.levels.ERROR) + return + end + + local cache = require('cp.cache') + cache.load() + local contest_data = cache.get_contest_data(platform, contest_id) + + if not (contest_data and contest_data.index_map and contest_data.index_map[problem_id]) then + logger.log( + ("%s contest '%s' has no problem '%s'."):format(platform, contest_id, problem_id), + vim.log.levels.ERROR + ) + return + end + + local setup = require('cp.setup') + setup.setup_contest(platform, contest_id, problem_id) elseif cmd.type == 'cache' then local cache_commands = require('cp.commands.cache') cache_commands.handle_cache_command(cmd) diff --git a/plugin/cp.lua b/plugin/cp.lua index 193beeb..7081f15 100644 --- a/plugin/cp.lua +++ b/plugin/cp.lua @@ -23,22 +23,26 @@ end, { if num_args == 2 then local candidates = {} local state = require('cp.state') - local platform, contest_id = state.get_platform(), state.get_contest_id() + local platform = state.get_platform() + local contest_id = state.get_contest_id() + if platform and contest_id then vim.list_extend(candidates, actions) local cache = require('cp.cache') cache.load() local contest_data = cache.get_contest_data(platform, contest_id) - if contest_data and contest_data.problems then - for _, problem in ipairs(contest_data.problems) do - table.insert(candidates, problem.id) - end + + if contest_data and contest_data.index_map then + local ids = vim.tbl_keys(contest_data.index_map) + table.sort(ids) + vim.list_extend(candidates, ids) end else vim.list_extend(candidates, platforms) table.insert(candidates, 'cache') table.insert(candidates, 'pick') end + return vim.tbl_filter(function(cmd) return cmd:find(ArgLead, 1, true) == 1 end, candidates)