*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 Optional: - uv package manager (https://docs.astral.sh/uv/) - LuaSnip for template expansion (https://github.com/L3MON4D3/LuaSnip) ============================================================================== COMMANDS *cp-commands* :CP *:CP* cp.nvim uses a single :CP command with intelligent argument parsing: State Restoration ~ :CP Restore contest context from current file. Automatically detects platform, contest, problem, and language from cached state. Use this after switching files to restore your CP environment. Requires previous setup with full :CP command. 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 :CP codeforces 1933 a --lang=python < :CP {platform} {contest_id} Contest setup: set platform, load contest metadata, and scrape ALL problems in the contest. This creates source files for every problem and caches all test cases for efficient bulk setup. Opens the first problem after completion. Example: > :CP atcoder abc324 :CP codeforces 1951 < :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 :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. :CP pick Launch configured picker for interactive platform/contest/problem selection. Navigation Commands ~ :CP next Navigate to next problem in current contest. Stops at last problem (no wrapping). Navigation Commands ~ :CP prev Navigate to previous problem in current contest. Stops at first problem (no wrapping). Command Flags ~ *cp-flags* Flags can be used with setup and action commands: --lang={language} Specify language for the problem. --lang {language} Alternative syntax for language specification. Supported languages: cpp, python Example: > :CP atcoder abc324 a --lang=python :CP b --lang cpp < --debug Enable debug compilation with additional flags. Uses the `debug` command template instead of `compile`. Typically includes debug symbols and sanitizers for memory error detection. Example: > :CP run --debug < Note: Debug compilation may be slower but provides better error reporting for runtime issues. 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") • {contest} Contest identifier (e.g. "abc324", "1933") • {problem} Problem identifier (e.g. "a", "b") Example template: > compile = { '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', opts = { contests = { default = { cpp = { compile = { 'g++', '{source}', '-o', '{binary}', '-std=c++17', '-fdiagnostic-colors=always' }, test = { '{binary}' }, debug = { 'g++', '{source}', '-o', '{binary}', '-std=c++17', '-g', '-fdiagnostic-colors=always' '-fsanitize=address,undefined' }, }, python = { test = { 'python3', '{source}' }, }, }, }, snippets = {}, debug = false, scrapers = { 'atcoder', 'codeforces', 'cses' }, run_panel = { ansi = true, diff_mode = 'vim', next_test_key = '', prev_test_key = '', toggle_diff_key = '', max_output_lines = 50, }, diff = { git = { args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' }, }, }, picker = 'telescope', -- 'telescope', 'fzf-lua', or nil (disabled) } } < By default, all contests are configured to use C++ with the g++ compiler and ISO standard 17. Python is also configured with the system executable python as a non-default option. Consult lua/cp/config.lua for more information. For example, to run CodeForces contests with Python, only the following config is required: { contests = { codeforces = { default_langauge = 'python' } } } *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) List of enabled scrapers. Default: all scrapers enabled {run_panel} (|RunPanelConfig|) Test panel behavior configuration. {diff} (|DiffConfig|) Diff backend configuration. {picker} (string, optional) Picker integration: "telescope", "fzf-lua", or nil to disable. When enabled, provides :CP pick for interactive platform/contest/problem selection. {filename} (function, optional) Custom filename generation. function(contest, contest_id, problem_id, config, language) Should return full filename with extension. (default: 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[], optional) Compile command template with {source}, {binary} placeholders. {test} (string[]) Test execution command template. {debug} (string[], optional) Debug compile command template. {extension} (string) File extension (e.g. "cc", "py"). {executable} (string, optional) Executable name for interpreted languages. *cp.RunPanelConfig* Fields: ~ {ansi} (boolean, default: true) Enable ANSI color parsing and highlighting. When true, compiler output and test results display with colored syntax highlighting. When false, ANSI escape codes are stripped for plain text display. Requires vim.g.terminal_color_* to be configured for proper color display. {diff_mode} (string, default: "none") Diff backend: "none", "vim", or "git". "none" displays plain buffers without highlighting, "vim" uses built-in diff, "git" provides character-level precision. {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: "") Key to cycle through diff modes. {close_key} (string, default: "") Close the run panel/interactive terminal {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 compilation. function(state: cp.State) {setup_code} (function, optional) Called after source file is opened. Good for configuring buffer settings. 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/abc123/tasks/abc123_a Usage examples: > :CP atcoder abc324 a " Full setup: problem A from contest ABC324 :CP atcoder abc324 " Contest setup: load contest metadata only :CP b " Switch to problem B (if contest loaded) :CP next " Navigate to next problem in contest < Note: AtCoder template includes optimizations for multi-test case problems commonly found in contests. AtCoder Heuristic Contests (AHC) are excluded from the contest list as they don't have standard sample test cases. Codeforces ~ *cp-codeforces* URL format: https://codeforces.com/contest/1234/problem/A 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 < Note: Problem IDs are automatically converted to lowercase for consistency. CSES ~ *cp-cses* URL format: https://cses.fi/problemset/task/1068 Usage examples: > :CP cses dynamic_programming 1633 " Set up problem 1633 from DP category :CP cses dynamic_programming " Set up ALL problems from DP category < Note: Category name is always required. For bulk setup, omit the problem ID to scrape all problems in the 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 problems (A, B, C, D, ...), creates source files for each, downloads all test cases, and opens problem A. 3. Alternative: Set up single problem: > :CP atcoder abc324 a < This creates only a.cc and scrapes its 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 7. Continue solving problems with :CP next/:CP prev navigation 8. Switch to another file (e.g. previous contest): > :e ~/contests/abc323/a.cpp :CP < Automatically restores abc323 contest context 9. 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 contest list, bypassing cache. Useful when contest lists are outdated or incomplete ============================================================================== 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 the following table layout: > ┌─────┬────────┬──────────────┬───────────┬──────────┬─────────────┐ │ # │ 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 │ │423 │ │100 │ │hello world │ └──────────────────────────────────────────────────────────────────┘ 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 < ============================================================================== ANSI COLORS AND HIGHLIGHTING *cp-ansi* cp.nvim provides comprehensive ANSI color support and highlighting for compiler output, program stderr, and diff visualization. ============================================================================== HIGHLIGHT GROUPS *cp-highlights* Test Status Groups ~ Test cases use competitive programming terminology with color highlighting: 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 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. Basic formatting groups: CpAnsiBold Bold text formatting CpAnsiItalic Italic text formatting CpAnsiBoldItalic Combined bold and italic formatting Standard terminal colors (each supports Bold, Italic, BoldItalic variants): CpAnsiRed Standard red (terminal_color_1) CpAnsiGreen Standard green (terminal_color_2) CpAnsiYellow Standard yellow (terminal_color_3) CpAnsiBlue Standard blue (terminal_color_4) CpAnsiMagenta Standard magenta (terminal_color_5) CpAnsiCyan Standard cyan (terminal_color_6) CpAnsiWhite Standard white (terminal_color_7) CpAnsiBlack Standard black (terminal_color_0) Bright color variants: CpAnsiBrightRed Bright red (terminal_color_9) CpAnsiBrightGreen Bright green (terminal_color_10) CpAnsiBrightYellow Bright yellow (terminal_color_11) CpAnsiBrightBlue Bright blue (terminal_color_12) CpAnsiBrightMagenta Bright magenta (terminal_color_13) CpAnsiBrightCyan Bright cyan (terminal_color_14) CpAnsiBrightWhite Bright white (terminal_color_15) CpAnsiBrightBlack Bright black (terminal_color_8) Example combinations: CpAnsiBoldRed Bold red combination CpAnsiItalicGreen Italic green combination CpAnsiBoldItalicYellow Bold italic yellow combination Diff Highlighting ~ Diff visualization 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 These groups are automatically used by the git diff backend for character-level difference visualization with optimal colorscheme integration. ============================================================================== TERMINAL COLOR INTEGRATION *cp-terminal-colors* ANSI colors automatically use your terminal's color palette through Neovim's vim.g.terminal_color_* variables. This ensures compiler colors match your colorscheme without manual configuration. If your colorscheme doesn't set terminal colors, cp.nvim will warn you and ANSI colors won't display properly - set them like so: >vim let g:terminal_color_1 = '#ff6b6b' ... ============================================================================== HIGHLIGHT CUSTOMIZATION *cp-highlight-custom* You can customize any highlight group by linking to existing groups or defining custom colors: >lua -- Customize the color of "TLE" text in run panel: vim.api.nvim_set_hl(0, 'CpTestTLE', { fg = '#ffa500', bold = true }) -- ... or the ANSI colors used to display stderr vim.api.nvim_set_hl(0, 'CpAnsiRed', { fg = vim.g.terminal_color_1 or '#ef4444' }) < Place customizations in your init.lua or after the colorscheme loads to prevent them from being overridden: >lua vim.api.nvim_create_autocmd('ColorScheme', { callback = function() -- Your cp.nvim highlight customizations here vim.api.nvim_set_hl(0, 'CpTestAC', { link = 'String' }) end }) < ============================================================================== RUN PANEL 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) Cycle through diff modes: none → git → vim (configurable via run_panel.toggle_diff_key) Exit run panel/interactive terminal 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 < ============================================================================== 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}.{language} < Where {platform} is the contest platform (atcoder, codeforces, cses) and {language} is the programming language (cpp, python). Examples: > cp.nvim/atcoder.cpp cp.nvim/codeforces.python cp.nvim/cses.cpp < 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: