Problem: `setup_problem` explicitly set `swapfile = true` on
provisional buffers, overriding the user's global `noswapfile` setting.
The resulting `.swp` files triggered E325 warnings on subsequent `:e`
calls — especially during the restore path, which redundantly re-opened
the current buffer.
Solution: remove the `swapfile` override so the user's setting is
respected, and skip the `:e` call when the current buffer already
matches the target source file.
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.
Problem: the hooks API conflated distinct lifecycle scopes under a flat
table with inconsistent naming (setup_code, before_run, setup_io_input),
making it hard to reason about when each hook fires.
Solution: introduce two namespaces — hooks.setup.{contest,code,io} for
one-time initialization and hooks.on.{enter,run,debug} for recurring
events. hooks.setup.contest fires once when a contest dir is newly
created; hooks.on.enter is registered as a buffer-scoped BufEnter
autocmd and fires immediately after setup.code. The provisional buffer
setup_code callsite is removed as it ran on an unresolved temp buffer.
Problem: after apply_template writes a file's content to the buffer,
cursor positioning was left entirely to the user's setup_code hook,
forcing everyone to reimplement the same placeholder-stripping logic.
Solution: add an optional templates.cursor_marker config key. When set,
apply_template scans the written lines for the marker, strips it, and
positions the cursor there via bufwinid so it works in both the
provisional and existing-file paths.
Problem: new solution files were always created empty, requiring users
to manually paste boilerplate or rely on editor snippets that fire
outside cp.nvim's control.
Solution: add an optional template field to the language config. When
set to a file path, its contents are written into every newly created
solution buffer before the setup_code hook runs. Existing files are
never overwritten.
Problem: vim.loop is deprecated since Neovim 0.10 in favour of vim.uv.
Five call sites across scraper.lua, setup.lua, utils.lua, and health.lua
still referenced the old alias.
Solution: replace every vim.loop reference with vim.uv directly.
Also fix contest-change detection so URL open logic triggers when either platform or contest changes. This makes :CP next/:CP prev and problem jumps open the correct page when open_url is enabled.
Co-authored-by: Codex <noreply@openai.com>
Problem: when opening a contest for the first time (metadata not
cached), the setup_code hook fired before state.set_language() was
called, causing state.get_language() to return nil inside the hook.
Solution: call state.set_language(lang) before the hook in the
provisional-buffer branch of setup_contest(). The value is already
computed at that point and is identical to what setup_problem() sets
later, so the early write is idempotent.