*cp.txt* Competitive programming plugin for Neovim Author: Barrett Ruth 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 = { debug = false, scrapers = { atcoder = true, codeforces = false, 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", }, }, hooks = { before_run = 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, }, run_panel = { diff_mode = "vim", next_test_key = "", prev_test_key = "", toggle_diff_key = "t", max_output_lines = 50, }, 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`) 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`) Per-platform scraper control. Default enables all platforms. • {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: 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. *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: `""`) Key to navigate to next test case. • {prev_test_key} (`string`, default: `""`) Key to navigate to previous test case. • {toggle_diff_key} (`string`, default: `"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, C, D, E, F, G) 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 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: (note that the diff is indeed highlighted, not the weird amalgamation of characters below) > ┌──────┬────────┬────────┬───────────┐ ┌─ Expected vs Actual ──────────────────┐ │ # │ Status │ Time │ Exit Code │ │ 45.70ms │ Exit: 0 │ ├──────┼────────┼────────┼───────────┤ ├────────────────────────────────────────┤ │ 1 │ AC │12.00ms │ 0 │ │ │ │ >2 │ WA │45.70ms │ 1 │ │ 4[-2-]{+3+} │ ├──────┴────────┴────────┴───────────┤ │ 100 │ │5 3 │ │ hello w[-o-]r{+o+}ld │ ├──────┬────────┬────────┬───────────┤ │ │ │ 3 │ AC │ 9.00ms │ 0 │ └────────────────────────────────────────┘ │ 4 │ RTE │ 0.00ms │139 (SIGUSR2)│ └──────┴────────┴────────┴───────────┘ < 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* Navigate to next test case (configurable via run_panel.next_test_key) Navigate to previous test case (configurable via run_panel.prev_test_key) t Toggle diff mode between vim and git (configurable via run_panel.toggle_diff_key) 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: