cp.nvim/doc/cp.txt

394 lines
17 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 run [--debug] Toggle run 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.
Here's an example configuration with lazy.nvim: >
{
'barrett-ruth/cp.nvim',
cmd = 'CP',
opts = {
contests = {
default = {
cpp = {
compile = { 'g++', '{source}', '-o', '{binary}', '-std=c++17' },
test = { '{binary}' },
debug = { 'g++', '{source}', '-o', '{binary}', '-std=c++17', '-g', '-fsanitize=address,undefined' },
},
python = {
test = { 'python3', '{source}' },
},
},
},
snippets = {},
hooks = {
before_run = nil,
before_debug = nil,
setup_code = nil,
},
debug = false,
scrapers = { ... }, -- all scrapers enabled by default
filename = default_filename,
run_panel = {
diff_mode = 'vim',
next_test_key = '<c-n>',
prev_test_key = '<c-p>',
toggle_diff_key = '<c-t>',
max_output_lines = 50,
},
diff = {
git = {
args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' },
},
},
}
}
<
*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>`) List of enabled scrapers.
Default: all scrapers enabled
- {run_panel} (`RunPanelConfig`) 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: `default_filename` - concatenates contest_id and problem_id, lowercased)
*cp.ContestConfig*
Fields: ~
- {cpp} (`LanguageConfig`) C++ language configuration.
- {python} (`LanguageConfig`) Python language configuration.
- {default_language} (`string`, default: `"cpp"`) Default language when
`--lang` not specified.
*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.RunPanelConfig*
Fields: ~
- {diff_mode} (`string`, default: `"vim"`) Diff backend: "vim" or "git".
Git provides character-level precision, vim uses built-in diff.
- {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.
- {toggle_diff_key} (`string`, default: `"<c-t>"`) Key to toggle diff mode between vim and git.
- {max_output_lines} (`number`, default: `50`) Maximum lines of test output to display.
*cp.DiffConfig*
Fields: ~
- {git} (`DiffGitConfig`) Git diff backend configuration.
*cp.Hooks*
Fields: ~
- {before_run}? (`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, ...) for navigation
3. Start with problem A: >
:CP a
Or do both at once with:
:CP atcoder abc324 a
< This creates a.cc and scrapes test cases
4. Code your solution, then test: >
:CP run
< Navigate with j/k, run specific tests with <enter>
Exit test panel with q or :CP run when done
5. If needed, debug with sanitizers: >
:CP run --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
<
RUN PANEL *cp-run*
The run 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-run*
:CP run [--debug] Toggle run 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 run panel uses a professional table layout with precise column alignment:
(observe that the diff is indeed highlighted, not the weird amalgamation of
characters below) >
┌─────┬────────┬──────────────┬───────────┬──────────┬─────────────┐
│ # │ Status │ Runtime (ms) │ Time (ms) │ Mem (MB) │ Exit Code │
├─────┼────────┼──────────────┼───────────┼──────────┼─────────────┤
│ 1 │ AC │ 12.0 │ 2000 │ 256 │ 0 │
│> 2 │ WA │ 45.70 │ 2000 │ 256 │ 1 │
├─────┴────────┴──────────────┴───────────┴──────────┴─────────────┤
│Input: │
│5 3 │
├─────┬────────┬──────────────┬───────────┬──────────┬─────────────┤
│ 3 │ AC │ 9.0 │ 2000 │ 256 │ 0 │
│ 4 │ RTE │ 0.0 │ 2000 │ 256 │139 (SIGUSR2)│
└─────┴────────┴──────────────┴───────────┴──────────┴─────────────┘
┌──────────────────────────────────────────────────────────────────┐
│Expected vs Actual │
│4[-2-]{+3+} │
│100 │
│hello w[-o-]r{+o+}ld │
└──────────────────────────────────────────────────────────────────┘
<
Status Indicators ~
Test cases use competitive programming terminology with color highlighting:
AC Accepted (passed) - Green
WA Wrong Answer (output mismatch) - Red
TLE Time Limit Exceeded (timeout) - Orange
RTE Runtime Error (non-zero exit) - Purple
Highlight Groups ~
*cp-highlights*
cp.nvim defines the following highlight groups for status indicators:
CpTestAC Green foreground for AC status
CpTestWA Red foreground for WA status
CpTestTLE Orange foreground for TLE status
CpTestRTE Purple foreground for RTE status
CpTestPending Gray foreground for pending tests
You can customize these colors by linking to other highlight groups in your
colorscheme or by redefining them: >
vim.api.nvim_set_hl(0, 'CpTestAC', { link = 'DiffAdd' })
vim.api.nvim_set_hl(0, 'CpTestWA', { fg = '#ff0000' })
<
Keymaps ~
*cp-test-keys*
<c-n> Navigate to next test case (configurable via run_panel.next_test_key)
<c-p> Navigate to previous test case (configurable via run_panel.prev_test_key)
<c-t> Toggle diff mode between vim and git (configurable via run_panel.toggle_diff_key)
<c-q> Exit test panel and restore layout
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}.n.cpin " nth test input
{problem_id}.n.cpout " nth 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 match the following format exactly:
cp.nvim/{platform}
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: