*cp.nvim.txt* Competitive programming plugin for Neovim Author: Barrett Ruth License: Same terms as Vim itself (see |license|) ============================================================================== INTRODUCTION *cp.nvim* cp.nvim is a competitive programming plugin that automates problem setup, compilation, and testing workflow for online judges. Supported platforms (for now!): AtCoder, Codeforces, CSES ============================================================================== REQUIREMENTS *cp-requirements* - Neovim 0.10.0+ - Unix-like operating system - uv package manager (https://docs.astral.sh/uv/) ============================================================================== COMMANDS *cp-commands* :CP *:CP* cp.nvim uses a single :CP command with intelligent argument parsing: Setup Commands ~ :CP {platform} {contest_id} Full setup: set platform and load contest metadata. Scrapes test cases and creates source file. Example: > :CP codeforces 1933 < :CP {platform} {contest_id} Contest setup: set platform, load contest metadata, and scrape all test cases in the contest. Opens the first problem after completion. Example: > :CP atcoder abc324 < Action Commands ~ :CP run Toggle run panel for individual test cases. Shows per-test results with redesigned layout for efficient comparison. :CP debug Same as above but with the debug mode configured settings. :CP pick Launch configured picker for interactive platform/contest selection. :CP interact [script] Open an interactive terminal for the current problem. If an executable interactor is provided, runs the compiled binary against the source file (see *cp-interact*). Otherwise, runs the source file. Only valid for interactive problems. 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). :CP {problem_id} Jump to problem {problem_id} in a contest. Requires that a contest has already been set up. State Restoration ~ :CP Restore state from current file. Automatically detects platform, contest, problem, and language from cached state. Use this after switching files to restore your CP environment. Cache Commands ~ :CP cache clear [contest] Clear the cache data for the specified contest, or all contests if none specified. :CP cache read View the cache in a pretty-printed lua buffer. Exit with q. Template Variables ~ *cp-template-vars* Command templates support variable substitution using {variable} syntax: • {source} Source file path (e.g. "abc324a.cpp") • {binary} Output binary path (e.g. "build/abc324a.run") Example template: > build = { 'g++', '{source}', '-o', '{binary}', '-std=c++17' } < Would expand to: > g++ abc324a.cpp -o build/abc324a.run -std=c++17 < ============================================================================== CONFIGURATION *cp-config* Here's an example configuration with lazy.nvim: >lua { 'barrett-ruth/cp.nvim', cmd = 'CP', build = 'uv sync', opts = { languages = { cpp = { extension = 'cc', commands = { build = { 'g++', '-std=c++17', '{source}', '-o', '{binary}', '-fdiagnostics-color=always' }, run = { '{binary}' }, debug = { 'g++', '-std=c++17', '-fsanitize=address,undefined', '{source}', '-o', '{binary}' }, }, }, python = { extension = 'py', commands = { run = { 'python', '{source}' }, debug = { 'python', '{source}' }, }, }, }, platforms = { cses = { enabled_languages = { 'cpp', 'python' }, default_language = 'cpp', overrides = { cpp = { extension = 'cpp', commands = { build = { ... } } } }, }, atcoder = { enabled_languages = { 'cpp', 'python' }, default_language = 'cpp', }, codeforces = { enabled_languages = { 'cpp', 'python' }, default_language = 'cpp', }, }, open_url = true, debug = false, ui = { run_panel = { ansi = true, diff_mode = 'vim', max_output_lines = 50, }, diff = { git = { args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' }, }, }, picker = 'telescope', }, } } < By default, C++ (g++ with ISO C++17) and Python are preconfigured under 'languages'. Platforms select which languages are enabled and which one is the default; per-platform overrides can tweak 'extension' or 'commands'. For example, to run CodeForces contests with Python by default: >lua { platforms = { codeforces = { default_language = 'python', }, }, } < Any language is supported provided the proper configuration. For example, to run CSES problems with Rust using the single schema: >lua { languages = { rust = { extension = 'rs', commands = { build = { 'rustc', '{source}', '-o', '{binary}' }, run = { '{binary}' }, }, }, }, platforms = { cses = { enabled_languages = { 'cpp', 'python', 'rust' }, default_language = 'rust', }, }, } < *cp.Config* Fields: ~ {languages} (table) Global language registry. Each language provides an {extension} and {commands}. {platforms} (table) Per-platform enablement, default language, and optional overrides. {hooks} (|cp.Hooks|) Hook functions called at various stages. {debug} (boolean, default: false) Show info messages. {scrapers} (string[]) Supported platform ids. {filename} (function, optional) function(contest, contest_id, problem_id, config, language): string Should return full filename with extension. (default: concatenates contest_id and problem_id, lowercased) {ui} (|CpUI|) UI settings: run panel, diff backend, picker. {open_url} (boolean) Open the contest & problem url in the browser when the contest is first opened. *CpPlatform* Fields: ~ {enabled_languages} (string[]) Language ids enabled on this platform. {default_language} (string) One of {enabled_languages}. {overrides} (table, optional) Per-language overrides of {extension} and/or {commands}. *CpLanguage* Fields: ~ {extension} (string) File extension without leading dot. {commands} (|CpLangCommands|) Command templates. *CpLangCommands* Fields: ~ {build} (string[], optional) For compiled languages. Must include {source} and {binary}. {run} (string[], optional) Runtime command. Compiled: must include {binary}. Interpreted: must include {source}. {debug} (string[], optional) Debug variant; same token rules as {build} (compiled) or {run} (interpreted). *CpUI* Fields: ~ {run_panel} (|RunPanelConfig|) Test panel behavior configuration. {diff} (|DiffConfig|) Diff backend configuration. {picker} (string|nil) 'telescope', 'fzf-lua', or nil. *cp.RunPanelConfig* Fields: ~ {ansi} (boolean, default: true) Enable ANSI color parsing and highlighting. {diff_mode} (string, default: "none") Diff backend: "none", "vim", or "git". {max_output_lines} (number, default: 50) Maximum lines of test output. *cp.DiffConfig* Fields: ~ {git} (|cp.DiffGitConfig|) Git diff backend configuration. *cp.DiffGitConfig* Fields: ~ {args} (string[]) Command-line arguments for git diff. Default: { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' } • --no-index: Compare files outside git repository • --word-diff=plain: Character-level diff markers • --word-diff-regex=.: Split on every character • --no-prefix: Remove a/ b/ prefixes from output *cp.Hooks* Fields: ~ {before_run} (function, optional) Called before test panel opens. function(state: cp.State) {before_debug} (function, optional) Called before debug build/run. function(state: cp.State) {setup_code} (function, optional) Called after source file is opened. function(state: cp.State) Hook functions receive the cp.nvim state object (cp.State). See the state module documentation (lua/cp/state.lua) for available methods and fields. Example usage in hook: >lua hooks = { setup_code = function(state) print("Setting up " .. state.get_base_name()) print("Source file: " .. state.get_source_file()) end } < ============================================================================== 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/{contest_id}/tasks/{contest_id}_{problem_id} Usage examples: > :CP atcoder abc324 " Set up atcoder.jp/contests/abc324 Codeforces ~ *cp-codeforces* URL format: https://codeforces.com/contest/{contest_id}/problem/{problem_id} Usage examples: > :CP codeforces 1934 " Set up codeforces.com/contest/1934 CSES ~ *cp-cses* URL format: https://cses.fi/problemset/task/{problem_id} Usage examples: > :CP cses dynamic_programming " Set up all problems in dp category ============================================================================== COMPLETE WORKFLOW EXAMPLE *cp-example* Example: Setting up and solving AtCoder contest ABC324 1. Browse to https://atcoder.jp/contests/abc324 2. Set up entire contest (bulk setup): > :CP atcoder abc324 < This scrapes all test case data, downloads all test cases, and opens the first problem. 3. 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 4. Move to next problem: > :CP next < This automatically sets up the next problem (likely problem B) 5. Continue solving problems with :CP next/:CP prev navigation 6. Switch to another file (e.g. previous contest): > :e ~/contests/abc323/a.cpp :CP < Automatically restores abc323 contest context 7. Submit solutions on AtCoder website ============================================================================== PICKER INTEGRATION *cp-picker* When picker integration is enabled in configuration, cp.nvim provides interactive platform and contest selection using telescope.nvim or fzf-lua. :CP pick *:CP-pick* Launch configured picker for interactive problem selection. Control Flow: Select Platform → Contest → Code! Requires picker = 'telescope' or picker = 'fzf-lua' in configuration. Requires corresponding plugin (telescope.nvim or fzf-lua) to be installed. PICKER KEYMAPS *cp-picker-keys* Force refresh/update contest list. Useful when contest lists are outdated or incomplete ============================================================================== RUN PANEL *cp-run* The run panel provides individual test case debugging. Problem time/memory limit constraints are in columns Time/Mem respectively. Used time/memory are in columns Runtime/RSS respectively. Interface ~ The run panel uses the following table layout: > ┌─────┬────────┬──────────────┬───────────┬──────────┬──────────┬─────────────┐ │ # │ Status │ Runtime (ms) │ Time (ms) │ RSS (MB) │ Mem (MB) │ Exit Code │ ├─────┼────────┼──────────────┼───────────┼──────────┼──────────┼─────────────┤ │ 1 │ AC │ 12.0 │ 2000 │ 123 │ 256 │ 0 │ │ >2 │ WA │ 45.70 │ 2000 │ 100 │ 256 │ 1 │ ├─────┴────────┴──────────────┴───────────┴──────────┴──────────┴─────────────┤ │ Input: │ │ 5 3 │ ├─────┬────────┬──────────────┬───────────┬──────────┬──────────┬─────────────┤ │ 3 │ TLE │ 9.0 │ 2000 │ 256 │ 256 │ 136 (SIGBUS)│ │ 4 │ RTE │ 0.0 │ 2000 │ 256 │ 256 │139 (SIGUSR2)│ └─────┴────────┴──────────────┴───────────┴──────────┴──────────┴─────────────┘ ┌─────────────────────────────────────────────────────────────────────────────┐ │ Expected vs Actual │ │ 423 │ │ 100 │ │ hello world │ └─────────────────────────────────────────────────────────────────────────────┘ Status Indicators ~ Test cases use competitive programming terminology with color highlighting: AC Accepted (passed) WA Wrong Answer (output mismatch) TLE Time Limit Exceeded (timeout) MLE Memory Limit Exceeded Error (heuristic) RTE Runtime Error (other non-zero exit code) NA Any other state < ============================================================================== INTERACTIVE MODE *cp-interact* Run interactive problems manually or with an orchestrator. :CP interact is available for interactive problems. Test cases are ignored in interactive mode (no run panel, no diffs). When using :CP interact {interactor}, the interactor must be executable (chmod +x). Completion after :CP interact suggests executables in CWD. 1) Terminal-only ~ :CP interact Execute the current program and open an interactive terminal running it directly. Use this for manual testing. 2) Orchestrated ~ :CP interact {interactor} Execute the current program and open an interactive terminal that runs your interactor script against it. {interactor} is an executable file relative to the CWD. Example: :CP interact my-executable-interactor.py Keymaps ~ Close the terminal and restore the previous layout. ============================================================================== ANSI COLORS AND HIGHLIGHTING *cp-ansi* cp.nvim provides comprehensive ANSI color support and highlighting for compiler output, program stderr, and diff visualization. If you cannot see color highlighting in your config, it is likely due to an erroneous config. Most tools (GCC, Python, Clang, Rustc) color stdout based on whether stdout is connected to a terminal. One can usually get aorund this by leveraging flags to force colored output. For example, to force colors with GCC, alter your config as follows: >lua { commands = { build = { 'g++', '-fdiagnostics-color=always', ... } } } < ============================================================================== HIGHLIGHT GROUPS *cp-highlights* Test Status Groups ~ CpTestAC Green foreground for AC status CpTestWA Red foreground for WA status CpTestTLE Orange foreground for TLE status CpTestMLE Orange foreground for MLE status CpTestRTE Purple foreground for RTE status CpTestNA Gray foreground for remaining state ANSI Color Groups ~ cp.nvim preserves ANSI colors from compiler output and program stderr using a sophisticated parsing system. Colors are automatically mapped to your terminal colorscheme via vim.g.terminal_color_* variables. Diff Highlighting ~ The git diff backend uses Neovim's built-in highlight groups that automatically adapt to your colorscheme: DiffAdd Highlights added text in git diffs DiffDelete Highlights removed text in git diffs ============================================================================== TERMINAL COLOR INTEGRATION *cp-terminal-colors* ANSI colors automatically use the terminal's color palette through Neovim's vim.g.terminal_color_* variables. ============================================================================== HIGHLIGHT CUSTOMIZATION *cp-highlight-custom* Customize highlight groups after your colorscheme loads: >lua vim.api.nvim_create_autocmd('ColorScheme', { callback = function() vim.api.nvim_set_hl(0, 'CpTestAC', { link = 'String' }) end }) ============================================================================== RUN PANEL KEYMAPS *cp-test-keys* Navigate to next test case Navigate to previous test case t Cycle through diff modes: none → git → vim q Exit run panel and restore layout Exit interactive terminal and restore layout Diff Modes ~ Three diff backends are available: none Nothing 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. Execution Details ~ Test cases are executed individually using the same compilation and execution pipeline, but with isolated input/output for precise failure analysis. ============================================================================== FILE STRUCTURE *cp-files* cp.nvim creates the following file structure upon problem setup: > {problem_id}.{ext} " Source file 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 < ============================================================================== HEALTH CHECK *cp-health* Run |:checkhealth| cp to verify your setup. vim:tw=78:ts=8:ft=help:norl: