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:
Barrett Ruth 2026-03-05 19:13:06 -05:00
parent cc48c901c0
commit cc279166cb
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
8 changed files with 65 additions and 2 deletions

View file

@ -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)