392 lines
16 KiB
Text
392 lines
16 KiB
Text
*cp.txt* Competitive programming plugin for Neovim
|
|
|
|
Author: Barrett Ruth <br.barrettruth@gmail.com>
|
|
License: Same terms as Vim itself (see |license|)
|
|
|
|
INTRODUCTION *cp* *cp.nvim*
|
|
|
|
cp.nvim is a competitive programming plugin that automates problem setup,
|
|
compilation, and testing workflow for online judges.
|
|
|
|
Supported platforms: AtCoder, Codeforces, CSES
|
|
Supported languages: C++, Python
|
|
|
|
REQUIREMENTS *cp-requirements*
|
|
|
|
- Neovim 0.10.0+
|
|
- uv package manager (https://docs.astral.sh/uv/)
|
|
- Language runtime/compiler (g++, python3)
|
|
|
|
Optional:
|
|
- LuaSnip for template expansion (https://github.com/L3MON4D3/LuaSnip)
|
|
|
|
COMMANDS *cp-commands*
|
|
|
|
*:CP*
|
|
cp.nvim uses a single :CP command with intelligent argument parsing:
|
|
|
|
Setup Commands ~
|
|
|
|
:CP {platform} {contest_id} {problem_id} [--lang={language}]
|
|
Full setup: set platform, load contest metadata,
|
|
and set up specific problem. Scrapes test cases
|
|
and creates source file.
|
|
Example: :CP codeforces 1933 a
|
|
Example: :CP codeforces 1933 a --lang=python
|
|
|
|
:CP {platform} {contest_id} Contest setup: set platform and load contest
|
|
metadata for navigation. Caches problem list.
|
|
Example: :CP atcoder abc324
|
|
|
|
:CP {platform} Platform setup: set platform only.
|
|
Example: :CP cses
|
|
|
|
:CP {problem_id} [--lang={language}]
|
|
Problem switch: switch to different problem
|
|
within current contest context.
|
|
Example: :CP b (switch to problem b)
|
|
Example: :CP b --lang=python
|
|
|
|
Action Commands ~
|
|
|
|
:CP test [--debug] Toggle test panel for individual test case
|
|
debugging. Shows per-test results with redesigned
|
|
layout for efficient comparison.
|
|
Use --debug flag to compile with debug flags
|
|
Requires contest setup first.
|
|
|
|
Navigation Commands ~
|
|
|
|
:CP next Navigate to next problem in current contest.
|
|
Stops at last problem (no wrapping).
|
|
|
|
:CP prev Navigate to previous problem in current contest.
|
|
Stops at first problem (no wrapping).
|
|
|
|
CONFIGURATION *cp-config*
|
|
|
|
cp.nvim works out of the box. No setup required.
|
|
|
|
Optional configuration with lazy.nvim: >
|
|
{
|
|
'barrett-ruth/cp.nvim',
|
|
cmd = 'CP',
|
|
opts = {
|
|
debug = false,
|
|
scrapers = {
|
|
atcoder = true,
|
|
codeforces = false, -- disable codeforces scraping
|
|
cses = true,
|
|
},
|
|
contests = {
|
|
codeforces = {
|
|
cpp = {
|
|
compile = {
|
|
'g++', '-std=c++{version}', '-O2', '-Wall', '-Wextra',
|
|
'-DLOCAL', '{source}', '-o', '{binary}',
|
|
},
|
|
test = { '{binary}' },
|
|
debug = {
|
|
'g++', '-std=c++{version}', '-g3',
|
|
'-fsanitize=address,undefined', '-DLOCAL',
|
|
'{source}', '-o', '{binary}',
|
|
},
|
|
version = 23,
|
|
extension = "cc",
|
|
},
|
|
python = {
|
|
test = { 'python3', '{source}' },
|
|
debug = { 'python3', '{source}' },
|
|
extension = "py",
|
|
},
|
|
default_language = "cpp",
|
|
timeout_ms = 2000,
|
|
},
|
|
},
|
|
hooks = {
|
|
before_test = function(ctx) vim.cmd.w() end,
|
|
before_debug = function(ctx) ... end,
|
|
setup_code = function(ctx)
|
|
vim.wo.foldmethod = "marker"
|
|
vim.wo.foldmarker = "{{{,}}}"
|
|
vim.diagnostic.enable(false)
|
|
end,
|
|
},
|
|
test_panel = {
|
|
diff_mode = "vim", -- "vim" or "git"
|
|
toggle_key = "t", -- toggle test panel
|
|
next_test_key = "<c-n>", -- navigate to next test case
|
|
prev_test_key = "<c-p>", -- navigate to previous test case
|
|
},
|
|
diff = {
|
|
git = {
|
|
command = "git",
|
|
args = {"diff", "--no-index", "--word-diff=plain",
|
|
"--word-diff-regex=.", "--no-prefix"},
|
|
},
|
|
},
|
|
snippets = { ... }, -- LuaSnip snippets
|
|
filename = function(contest, contest_id, problem_id, config, language) ... end,
|
|
}
|
|
}
|
|
<
|
|
|
|
*cp.Config*
|
|
|
|
Fields: ~
|
|
• {contests} (`table<string,ContestConfig>`) Contest configurations.
|
|
• {hooks} (`cp.Hooks`) Hook functions called at various stages.
|
|
• {snippets} (`table[]`) LuaSnip snippet definitions.
|
|
• {debug} (`boolean`, default: `false`) Show info messages
|
|
during operation.
|
|
• {scrapers} (`table<string,boolean>`) Per-platform scraper control.
|
|
Default enables all platforms.
|
|
• {test_panel} (`TestPanelConfig`) Test panel behavior configuration.
|
|
• {diff} (`DiffConfig`) Diff backend configuration.
|
|
• {filename}? (`function`) Custom filename generation function.
|
|
`function(contest, contest_id, problem_id, config, language)`
|
|
Should return full filename with extension.
|
|
(default: concats contest_id and problem id)
|
|
|
|
*cp.ContestConfig*
|
|
|
|
Fields: ~
|
|
• {cpp} (`LanguageConfig`) C++ language configuration.
|
|
• {python} (`LanguageConfig`) Python language configuration.
|
|
• {default_language} (`string`, default: `"cpp"`) Default language when
|
|
`--lang` not specified.
|
|
• {timeout_ms} (`number`, default: `2000`) Execution timeout in
|
|
milliseconds.
|
|
|
|
*cp.LanguageConfig*
|
|
|
|
Fields: ~
|
|
• {compile}? (`string[]`) Compile command template with
|
|
`{version}`, `{source}`, `{binary}` placeholders.
|
|
• {test} (`string[]`) Test execution command template.
|
|
• {debug}? (`string[]`) Debug compile command template.
|
|
• {version}? (`number`) Language version (e.g. 20, 23 for C++).
|
|
• {extension} (`string`) File extension (e.g. "cc", "py").
|
|
• {executable}? (`string`) Executable name for interpreted languages.
|
|
|
|
*cp.TestPanelConfig*
|
|
|
|
Fields: ~
|
|
• {diff_mode} (`string`, default: `"vim"`) Diff backend: "vim" or "git".
|
|
Git provides character-level precision, vim uses built-in diff.
|
|
• {toggle_key} (`string`, default: `"t"`) Key to toggle test panel.
|
|
• {next_test_key} (`string`, default: `"<c-n>"`) Key to navigate to next test case.
|
|
• {prev_test_key} (`string`, default: `"<c-p>"`) Key to navigate to previous test case.
|
|
|
|
*cp.DiffConfig*
|
|
|
|
Fields: ~
|
|
• {git} (`DiffGitConfig`) Git diff backend configuration.
|
|
|
|
*cp.Hooks*
|
|
|
|
Fields: ~
|
|
• {before_test}? (`function`) Called before test panel opens.
|
|
`function(ctx: ProblemContext)`
|
|
• {before_debug}? (`function`) Called before debug compilation.
|
|
`function(ctx: ProblemContext)`
|
|
• {setup_code}? (`function`) Called after source file is opened.
|
|
Good for configuring buffer settings.
|
|
`function(ctx: ProblemContext)`
|
|
|
|
*ProblemContext*
|
|
|
|
Fields: ~
|
|
• {contest} (`string`) Platform name (e.g. "atcoder", "codeforces")
|
|
• {contest_id} (`string`) Contest ID (e.g. "abc123", "1933")
|
|
• {problem_id}? (`string`) Problem ID (e.g. "a", "b") - nil for CSES
|
|
• {source_file} (`string`) Source filename (e.g. "abc123a.cpp")
|
|
• {binary_file} (`string`) Binary output path (e.g. "build/abc123a.run")
|
|
• {input_file} (`string`) Test input path (e.g. "io/abc123a.cpin")
|
|
• {output_file} (`string`) Program output path (e.g. "io/abc123a.cpout")
|
|
• {expected_file} (`string`) Expected output path (e.g. "io/abc123a.expected")
|
|
• {problem_name} (`string`) Display name (e.g. "abc123a")
|
|
|
|
WORKFLOW *cp-workflow*
|
|
|
|
For the sake of consistency and simplicity, cp.nvim extracts contest/problem identifiers from
|
|
URLs. This means that, for example, CodeForces/AtCoder contests are configured by
|
|
their round id rather than round number. See below.
|
|
|
|
PLATFORM-SPECIFIC USAGE *cp-platforms*
|
|
|
|
AtCoder ~
|
|
*cp-atcoder*
|
|
URL format: https://atcoder.jp/contests/abc123/tasks/abc123_a
|
|
|
|
In terms of cp.nvim, this corresponds to:
|
|
- Platform: atcoder
|
|
- Contest ID: abc123
|
|
- Problem ID: a
|
|
|
|
Usage examples: >
|
|
:CP atcoder abc123 a " Full setup: problem A from contest ABC123
|
|
:CP atcoder abc123 " Contest setup: load contest metadata only
|
|
:CP b " Switch to problem B (if contest loaded)
|
|
:CP next " Navigate to next problem in contest
|
|
<
|
|
Codeforces ~
|
|
*cp-codeforces*
|
|
URL format: https://codeforces.com/contest/1234/problem/A
|
|
|
|
In terms of cp.nvim, this corresponds to:
|
|
- Platform: codeforces
|
|
- Contest ID: 1234
|
|
- Problem ID: a (lowercase)
|
|
|
|
Usage examples: >
|
|
:CP codeforces 1934 a " Full setup: problem A from contest 1934
|
|
:CP codeforces 1934 " Contest setup: load contest metadata only
|
|
:CP c " Switch to problem C (if contest loaded)
|
|
:CP prev " Navigate to previous problem in contest
|
|
<
|
|
CSES ~
|
|
*cp-cses*
|
|
URL format: https://cses.fi/problemset/task/1068
|
|
|
|
CSES is organized by categories rather than contests. Currently all problems
|
|
are grouped under "CSES Problem Set" category.
|
|
|
|
In terms of cp.nvim, this corresponds to:
|
|
- Platform: cses
|
|
- Contest ID: "CSES Problem Set" (category)
|
|
- Problem ID: 1068 (numeric)
|
|
|
|
Usage examples: >
|
|
:CP cses 1068 " Set up problem 1068 from CSES
|
|
:CP 1070 " Switch to problem 1070 (if CSES loaded)
|
|
:CP next " Navigate to next problem in CSES
|
|
<
|
|
COMPLETE WORKFLOW EXAMPLE *cp-example*
|
|
|
|
Example: Setting up and solving AtCoder contest ABC324
|
|
|
|
1. Browse to https://atcoder.jp/contests/abc324
|
|
2. Set up contest and load metadata: >
|
|
:CP atcoder abc324
|
|
< This caches all problems (A, B, C, D, E, F, G) for navigation
|
|
|
|
3. Start with problem A: >
|
|
:CP a
|
|
< This creates a.cc and scrapes test cases
|
|
|
|
4. Code your solution, then test: >
|
|
:CP test
|
|
< Navigate with j/k, run specific tests with <enter>
|
|
Exit test panel with q or :CP test when done
|
|
|
|
5. If needed, debug with sanitizers: >
|
|
:CP test --debug
|
|
<
|
|
6. Move to next problem: >
|
|
:CP next
|
|
< This automatically sets up problem B
|
|
|
|
6. Continue solving problems with :CP next/:CP prev navigation
|
|
7. Submit solutions on AtCoder website
|
|
|
|
Example: Quick setup for single Codeforces problem >
|
|
:CP codeforces 1933 a " One command setup
|
|
:CP test " Test immediately
|
|
<
|
|
|
|
TEST PANEL *cp-test*
|
|
|
|
The test panel provides individual test case debugging with a streamlined
|
|
layout optimized for modern screens. Shows test status with competitive
|
|
programming terminology and efficient space usage.
|
|
|
|
Activation ~
|
|
*:CP-test*
|
|
:CP test [--debug] Toggle test panel on/off. When activated,
|
|
replaces current layout with test interface.
|
|
Automatically compiles and runs all tests.
|
|
Use --debug flag to compile with debug symbols
|
|
and sanitizers. Toggle again to restore original
|
|
layout.
|
|
|
|
Interface ~
|
|
|
|
The test panel uses a redesigned two-pane layout for efficient comparison:
|
|
(note that the diff is indeed highlighted, not the weird amalgamation of
|
|
characters below) >
|
|
|
|
┌─ Tests ─────────────────────┐ ┌─ Expected vs Actual ───────────────────────┐
|
|
│ AC 1. 12ms │ │ 45ms │ Exit: 0 │
|
|
│ WA > 2. 45ms │ ├────────────────────────────────────────────┤
|
|
│ 5 3 │ │ │
|
|
│ │ │ 4[-2-]{+3+} │
|
|
│ AC 3. 9ms │ │ 100 │
|
|
│ RTE 4. 0ms │ │ hello w[-o-]r{+o+}ld │
|
|
│ │ │ │
|
|
└─────────────────────────────┘ └────────────────────────────────────────────┘
|
|
<
|
|
|
|
Status Indicators ~
|
|
|
|
Test cases use competitive programming terminology:
|
|
|
|
AC Accepted (passed)
|
|
WA Wrong Answer (output mismatch)
|
|
TLE Time Limit Exceeded (timeout)
|
|
RTE Runtime Error (non-zero exit)
|
|
|
|
Keymaps ~
|
|
*cp-test-keys*
|
|
<c-n> Navigate to next test case (configurable via test_panel.next_test_key)
|
|
<c-p> Navigate to previous test case (configurable via test_panel.prev_test_key)
|
|
q Exit test panel (restore layout)
|
|
t Toggle test panel (configurable via test_panel.toggle_key)
|
|
|
|
Diff Modes ~
|
|
|
|
Two diff backends are available:
|
|
|
|
vim Built-in vim diff (default, always available)
|
|
git Character-level git word-diff (requires git, more precise)
|
|
|
|
The git backend shows character-level changes with [-removed-] and {+added+}
|
|
markers for precise difference analysis.
|
|
|
|
Execution Details ~
|
|
|
|
Test cases are executed individually using the same compilation and
|
|
execution pipeline, but with isolated input/output for
|
|
precise failure analysis. All tests are automatically run when the
|
|
panel opens.
|
|
|
|
FILE STRUCTURE *cp-files*
|
|
|
|
cp.nvim creates the following file structure upon problem setup:
|
|
|
|
{problem_id}.{ext} " Source file (e.g. a.cc, b.py)
|
|
build/
|
|
{problem_id}.run " Compiled binary
|
|
io/
|
|
{problem_id}.cpin " Test input
|
|
{problem_id}.cpout " Program output
|
|
{problem_id}.expected " Expected output
|
|
|
|
The plugin automatically manages this structure and navigation between problems
|
|
maintains proper file associations.
|
|
|
|
SNIPPETS *cp-snippets*
|
|
|
|
cp.nvim integrates with LuaSnip for automatic template expansion. Built-in
|
|
snippets include basic C++ and Python templates for each contest type.
|
|
|
|
Snippet trigger names must EXACTLY match platform names ("codeforces" for
|
|
CodeForces, "cses" for CSES, etc.).
|
|
|
|
Custom snippets can be added via the `snippets` configuration field.
|
|
|
|
HEALTH CHECK *cp-health*
|
|
|
|
Run |:checkhealth| cp to verify your setup.
|
|
|
|
vim:tw=78:ts=8:ft=help:norl:
|