Commit graph

63 commits

Author SHA1 Message Date
Barrett Ruth
1ac521a126
fix: language version IDs, cache crash, and stress session restore (#352)
## Problem

Codeforces language version IDs were wrong (pointed at old compiler
versions), `LANGUAGE_VERSIONS` was incomplete for most platforms, the
contest picker crashed when `supports_countdown` was stored as a
non-table entry, and `:CP stress` restored a broken IO view on exit.

## Solution

Correct CF `programTypeId` values and default to C++20. Add
`LANGUAGE_VERSIONS` entries for all six platforms. Guard
`get_contest_summaries` against non-table cache entries. Call
`ensure_io_view()` after stress session restore. Shorten the stress
terminal buffer name to a readable `term://stress.py` format.
2026-03-06 20:22:28 -05:00
Barrett Ruth
58b6840815
feat: race countdown support and language version selection (#346)
## Problem

Two gaps in the plugin: (1) contest pickers have no way to know whether
a contest supports countdown (race), so the UI can't surface that
affordance; (2) `:CP submit` hardcodes a single language ID per platform
with no way to choose C++ standard or override the platform ID.

## Solution

**Race countdown** (`4e709c8`): Add `supports_countdown` boolean to
`ContestListResult` and wire it through CSES/USACO scrapers, cache, race
module, and pickers.

**Language version selection** (`b90ac67`): Add `LANGUAGE_VERSIONS` and
`DEFAULT_VERSIONS` tables in `constants.lua`. Config gains `version` and
`submit_id` fields validated at setup time. `submit.lua` resolves the
effective config to a platform ID (priority: `submit_id` > `version` >
default). Helpdocs add `*cp-submit-language*` section. Tests cover
`LANGUAGE_IDS` completeness.
2026-03-06 18:18:21 -05:00
Barrett Ruth
ba5ae8df69
fix(kattis): fix nil display_name in contest picker (#332)
## Problem

`ContestSummary.display_name` defaults to `None`, which serializes to
JSON `null` → Lua `vim.NIL`. The contest picker displayed "vim.NIL" for
every entry. Additionally, `start_time` was always stored even when
null, because `vim.NIL` is truthy in Lua.

## Solution

Pass `display_name=name` explicitly in `_parse_contests_page` so JSON
never emits `null`. In `cache.lua` `set_contest_summaries`, coerce
`display_name` via a `~= vim.NIL` guard and apply the same guard before
storing `start_time`.
2026-03-06 13:25:17 -05:00
Barrett Ruth
7bf4cf2538
feat(commands): implement :CP open [problem|contest|standings] (#319)
## Problem

There was no way to open a problem, contest, or standings page in the
browser from within the plugin.

## Solution

Add `contest_url` and `standings_url` to `MetadataResult` and persist
them in the cache. Add `cache.get_open_urls` to resolve all three URLs.
Wire up `:CP open [problem|contest|standings]` in `commands/init.lua`
to call `vim.ui.open`, warning when a URL is unavailable (e.g. CSES
has no standings). Closes #315.
2026-03-05 19:16:05 -05:00
Barrett Ruth
1bc0aa41b6
refactor(cache): nest credentials under platform namespace (#293)
## Problem

Credentials lived in a top-level `_credentials` namespace, requiring
special
preservation logic in `clear_all()` and a separate key hierarchy from
the
platform data they belong to.

## Solution

Move credentials from `_credentials.<platform>` to
`<platform>._credentials`.
Migrate v1 caches on load, skip underscore-prefixed keys when
enumerating
contest IDs and summaries, and simplify `clear_all()` now that no
special
preservation is needed.

Stacked on #292.
2026-03-04 13:37:22 -05:00
a04702d87c refactor: replace :CP login with :CP credentials subcommand
Problem: :CP login was a poor API — no way to clear credentials without
raw Lua, and the single command didn't scale to multiple operations.

Solution: replace login with a :CP credentials subcommand following the
same pattern as :CP cache. :CP credentials set [platform] prompts and
saves; :CP credentials clear [platform] removes one or all platforms.
Add cache.clear_credentials(), rename login.lua to credentials.lua,
update parse/dispatch/tab-complete, and rewrite vimdoc accordingly.
2026-03-03 16:46:07 -05:00
a08d1f0c5e refactor(submit): consolidate credentials into main cache file
Problem: credentials were stored in a separate file,
cp-nvim-credentials.json, alongside the main cp-nvim.json cache.
Two files for one plugin's persistent state was unnecessary.

Solution: add get_credentials/set_credentials to cache.lua, storing
credentials under _credentials[platform] in the shared cache. Update
clear_all() to preserve _credentials across cache wipes. Remove the
separate file, load_credentials, and save_credentials from submit.lua.
2026-03-03 16:24:12 -05:00
de5a20c567 fix: resolve typecheck errors in cache, atcoder, cses, and usaco
Problem: lua typecheck flagged missing start_time field on ContestSummary;
ty flagged BeautifulSoup Tag/NavigableString union on csrf_input.get(),
a 3-tuple unpack where _extract_problem_info now returns 4 values in
cses.py, and an untyped list assignment in usaco.py.

Solution: add start_time? to ContestSummary LuaDoc, guard csrf_input
with hasattr check and type: ignore, unpack precision from
_extract_problem_info in cses.py callers, and use cast() in usaco.py.
2026-03-03 15:09:41 -05:00
90bd13580b feat(scraper): add precision extraction, start_time, and submit support
Problem: problem pages contain floating-point precision requirements and
contest start timestamps that were not being extracted or stored. The
submit workflow also needed a foundation in the scraper layer.

Solution: add extract_precision() to base.py and propagate through all
scrapers into cache. Add start_time to ContestSummary and extract it
from AtCoder and Codeforces. Add SubmitResult model, abstract submit()
method, submit CLI case with get_language_id() resolution, stdin/env_extra
support in run_scraper, and a full AtCoder submit implementation; stub
the remaining platforms.
2026-03-03 15:09:41 -05:00
e685a8089f feat: add epsilon tolerance for floating-point output comparison
Problem: output comparison used exact string equality after whitespace
normalisation, causing correct solutions to fail on problems where
floating-point answers are accepted within a tolerance (e.g. 1e-6).

Solution: add an optional ui.panel.epsilon config value. When set,
actual and expected output are compared token-by-token: numeric tokens
are compared with math.abs(a - b) <= epsilon, non-numeric tokens fall
back to exact string equality. Per-problem epsilon can also be stored
in the cache and takes precedence over the global default.
2026-02-26 23:00:35 -05:00
d274e0c117 fix(cache): replace stale M._cache field with get_raw_cache accessor
Problem: M._cache = cache_data captured the initial empty table reference
at module load time. After M.load() reassigns cache_data to the decoded
JSON, M._cache is permanently stale and returns the wrong table.

Solution: remove the field assignment and expose get_raw_cache() which
closes over cache_data and always returns the current table.
2026-02-26 22:46:06 -05:00
d3ac300ea0 fix(cache): remove unused logger import
Problem: the logger import became unused after replacing the error log
with a silent cache wipe.

Solution: drop the require.
2026-02-22 22:19:51 -05:00
db5bd791f9 fix(cache): invalidate stale cache on version mismatch
Problem: after an install or update, the on-disk cache may contain data
written by an older version of the plugin whose format no longer matches
what the current code expects.

Solution: embed a CACHE_VERSION in every saved cache file. On load, if
the stored version is missing or differs from the current one, wipe the
cache and rewrite it. Corrupt (non-decodable) cache files are handled
the same way instead of only logging an error.
2026-02-22 22:19:51 -05:00
Barrett Ruth
96c01bf796 cleanup 2025-11-04 23:47:06 -05:00
Barrett Ruth
aab211902e feat: multi-test case view 2025-11-04 21:32:40 -05:00
Barrett Ruth
fef73887e4 feat(io): multi-test case view 2025-11-04 08:15:08 -05:00
Barrett Ruth
9d848eba22 feat: improve autocomplete 2025-10-24 01:44:06 -04:00
c0e175d84b feat(config): open url option 2025-10-12 16:19:02 -04:00
cedcd82367 fix: write interaction into cache 2025-10-05 13:50:14 -04:00
d2bde9bad8 fix(config): better file org 2025-10-04 19:54:53 -04:00
a76d228e3f feat(doc): update for new config 2025-10-04 19:04:49 -04:00
17b5e0a52b make cache resilient 2025-10-04 16:15:26 -04:00
3fbbfa9423 normalize scraper behavior 2025-10-04 16:13:04 -04:00
18dbcd43d2 fix(cache): contest override 2025-10-04 12:48:57 -04:00
1520939d4b some refactors 2025-10-03 14:34:49 -04:00
d9537e72ba many fixes 2025-10-02 22:35:30 -04:00
1974addbd2 fix(lua): bunch of typing 2025-10-02 14:18:26 -04:00
057b0890c2 fix: remove unused function 2025-10-02 13:56:38 -04:00
91e6fbe455 fix caching 2025-10-02 10:18:29 -04:00
6b8a1e2087 more docs 2025-10-01 21:36:53 -04:00
7eb314b02c fix caching 2025-10-01 20:21:11 -04:00
e6c09a4897 fix some cachign 2025-10-01 17:08:36 -04:00
b406c0ce4e fix: synchronous problem fetch 2025-10-01 12:25:07 -04:00
7761c7c759 fix(cache): file state 2025-09-30 21:21:13 -04:00
46cd509747 fix docs and superfluous vim.validate calls 2025-09-30 20:55:29 -04:00
ae2f8b94cf feat: interactive problem finer-tuning 2025-09-27 10:05:58 -04:00
170021af8e no more ttl 2025-09-24 20:46:43 -04:00
bcbcc4365f remove ttl 2025-09-24 20:16:33 -04:00
f3666a30be fix(ci): lint 2025-09-23 12:28:53 -04:00
8df8c16a72 fix(ci): selene lint 2025-09-23 12:25:53 -04:00
8a9bc7434f fix: remove comments 2025-09-23 10:22:02 -04:00
e171017ab0 fixup 2025-09-23 09:42:45 -04:00
ba81df2266 fix(cache): expiry 2025-09-22 16:50:14 -04:00
039fad1614 fix(cache): cache contest data indefinitely 2025-09-22 16:32:52 -04:00
78fb4f8f4b feat(cache): cache clearing, updating and resetting 2025-09-21 15:08:55 -04:00
1b8365265d fix(ci): unused variables 2025-09-21 11:36:06 -04:00
a3dd6f4e1e fix(run): foldcolumn 2025-09-19 23:11:12 -04:00
c540ba3050 feat(cache): optimize cache loading 2025-09-19 20:44:45 -04:00
b219633fc1 fix(ci): undefiend variabe; 2025-09-19 20:44:25 -04:00
793063a68e feat(test_panel): integrate scraped data 2025-09-19 20:41:19 -04:00