feat(commands): implement :CP open [problem|contest|standings]
Problem: There was no way to open a problem or contest page in the browser from within the plugin; users had to manually navigate to the platform URL. Solution: Add `contest_url` and `standings_url` to `MetadataResult` and persist them via `cache.set_contest_data`. Add `cache.get_open_urls` to assemble all three URLs from cache. Wire up `:CP open` in `commands/init.lua` to call `vim.ui.open` on the resolved URL, warning when none is available (e.g. CSES standings).
This commit is contained in:
parent
cc48c901c0
commit
cc279166cb
8 changed files with 65 additions and 2 deletions
|
|
@ -10,6 +10,8 @@
|
|||
---@field name string
|
||||
---@field display_name string
|
||||
---@field url string
|
||||
---@field contest_url string
|
||||
---@field standings_url string
|
||||
|
||||
---@class ContestSummary
|
||||
---@field display_name string
|
||||
|
|
@ -148,12 +150,16 @@ end
|
|||
---@param contest_id string
|
||||
---@param problems Problem[]
|
||||
---@param url string
|
||||
function M.set_contest_data(platform, contest_id, problems, url)
|
||||
---@param contest_url string
|
||||
---@param standings_url string
|
||||
function M.set_contest_data(platform, contest_id, problems, url, contest_url, standings_url)
|
||||
vim.validate({
|
||||
platform = { platform, 'string' },
|
||||
contest_id = { contest_id, 'string' },
|
||||
problems = { problems, 'table' },
|
||||
url = { url, 'string' },
|
||||
contest_url = { contest_url, 'string' },
|
||||
standings_url = { standings_url, 'string' },
|
||||
})
|
||||
|
||||
cache_data[platform] = cache_data[platform] or {}
|
||||
|
|
@ -165,6 +171,8 @@ function M.set_contest_data(platform, contest_id, problems, url)
|
|||
problems = problems,
|
||||
index_map = {},
|
||||
url = url,
|
||||
contest_url = contest_url,
|
||||
standings_url = standings_url,
|
||||
}
|
||||
for i, p in ipairs(out.problems) do
|
||||
out.index_map[p.id] = i
|
||||
|
|
@ -174,6 +182,25 @@ function M.set_contest_data(platform, contest_id, problems, url)
|
|||
M.save()
|
||||
end
|
||||
|
||||
---@param platform string?
|
||||
---@param contest_id string?
|
||||
---@param problem_id string?
|
||||
---@return { problem: string|nil, contest: string|nil, standings: string|nil }|nil
|
||||
function M.get_open_urls(platform, contest_id, problem_id)
|
||||
if not platform or not contest_id then
|
||||
return nil
|
||||
end
|
||||
if not cache_data[platform] or not cache_data[platform][contest_id] then
|
||||
return nil
|
||||
end
|
||||
local cd = cache_data[platform][contest_id]
|
||||
return {
|
||||
problem = cd.url ~= '' and problem_id and string.format(cd.url, problem_id) or nil,
|
||||
contest = cd.contest_url ~= '' and cd.contest_url or nil,
|
||||
standings = cd.standings_url ~= '' and cd.standings_url or nil,
|
||||
}
|
||||
end
|
||||
|
||||
---@param platform string
|
||||
---@param contest_id string
|
||||
function M.clear_contest_data(platform, contest_id)
|
||||
|
|
|
|||
|
|
@ -245,6 +245,12 @@ local function parse_command(args)
|
|||
debug = debug,
|
||||
mode = mode,
|
||||
}
|
||||
elseif first == 'open' then
|
||||
local target = args[2] or 'problem'
|
||||
if not vim.tbl_contains({ 'problem', 'contest', 'standings' }, target) then
|
||||
return { type = 'error', message = 'Usage: :CP open [problem|contest|standings]' }
|
||||
end
|
||||
return { type = 'action', action = 'open', requires_context = true, subcommand = target }
|
||||
elseif first == 'pick' then
|
||||
local language = nil
|
||||
if #args >= 3 and args[2] == '--lang' then
|
||||
|
|
@ -375,6 +381,20 @@ function M.handle_command(opts)
|
|||
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()
|
||||
local urls =
|
||||
cache.get_open_urls(state.get_platform(), state.get_contest_id(), state.get_problem_id())
|
||||
local url = urls and urls[cmd.subcommand]
|
||||
if not url or url == '' then
|
||||
logger.log(
|
||||
("No URL available for '%s'"):format(cmd.subcommand),
|
||||
{ level = vim.log.levels.WARN }
|
||||
)
|
||||
return
|
||||
end
|
||||
vim.ui.open(url)
|
||||
elseif cmd.action == 'login' then
|
||||
require('cp.credentials').login(cmd.platform)
|
||||
elseif cmd.action == 'logout' then
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ M.ACTIONS = {
|
|||
'race',
|
||||
'stress',
|
||||
'submit',
|
||||
'open',
|
||||
}
|
||||
|
||||
M.PLATFORM_DISPLAY_NAMES = {
|
||||
|
|
|
|||
|
|
@ -243,7 +243,14 @@ function M.setup_contest(platform, contest_id, problem_id, language)
|
|||
contest_id,
|
||||
vim.schedule_wrap(function(result)
|
||||
local problems = result.problems or {}
|
||||
cache.set_contest_data(platform, contest_id, problems, result.url)
|
||||
cache.set_contest_data(
|
||||
platform,
|
||||
contest_id,
|
||||
problems,
|
||||
result.url,
|
||||
result.contest_url or '',
|
||||
result.standings_url or ''
|
||||
)
|
||||
local prov = state.get_provisional()
|
||||
if not prov or prov.platform ~= platform or prov.contest_id ~= contest_id then
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue