diff --git a/.envrc b/.envrc deleted file mode 100644 index aa57334..0000000 --- a/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -VIRTUAL_ENV="$PWD/.venv" -PATH_add "$VIRTUAL_ENV/bin" -export VIRTUAL_ENV diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index bf6bcea..0000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,112 +0,0 @@ -name: ci -on: - workflow_call: - pull_request: - branches: [main] - push: - branches: [main] - -jobs: - changes: - runs-on: ubuntu-latest - outputs: - lua: ${{ steps.changes.outputs.lua }} - python: ${{ steps.changes.outputs.python }} - steps: - - uses: actions/checkout@v4 - - uses: dorny/paths-filter@v3 - id: changes - with: - filters: | - lua: - - 'lua/**' - - 'spec/**' - - 'plugin/**' - - 'after/**' - - 'ftdetect/**' - - '*.lua' - - '.luarc.json' - - 'stylua.toml' - - 'selene.toml' - python: - - 'scripts/**' - - 'scrapers/**' - - 'tests/**' - - 'pyproject.toml' - - 'uv.lock' - - lua-format: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.lua == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: JohnnyMorganz/stylua-action@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: 2.1.0 - args: --check . - - lua-lint: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.lua == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: NTBBloodbath/selene-action@v1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --display-style quiet . - - lua-typecheck: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.lua == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: mrcjkb/lua-typecheck-action@v0 - with: - checklevel: Warning - directories: lua - configpath: .luarc.json - - python-format: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.python == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v4 - - run: uv tool install ruff - - run: ruff format --check . - - python-lint: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.python == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v4 - - run: uv tool install ruff - - run: ruff check . - - python-typecheck: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.python == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v4 - - run: uv sync --dev - - run: uvx ty check . - - python-test: - runs-on: ubuntu-latest - needs: changes - if: ${{ needs.changes.outputs.python == 'true' }} - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v4 - - run: uv sync --dev - - run: uv run camoufox fetch - - run: uv run pytest tests/ -v diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 731e74b..664b33e 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -28,6 +28,7 @@ jobs: - '*.lua' - '.luarc.json' - '*.toml' + - 'vim.yaml' python: - 'scripts/**/.py' - 'scrapers/**/*.py' @@ -45,11 +46,8 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - uses: JohnnyMorganz/stylua-action@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: 2.1.0 - args: --check . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command stylua --check . lua-lint: name: Lua Lint Check @@ -58,11 +56,8 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - name: Lint with Selene - uses: NTBBloodbath/selene-action@v1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --display-style quiet . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command selene --display-style quiet . lua-typecheck: name: Lua Type Check @@ -127,15 +122,5 @@ jobs: if: ${{ needs.changes.outputs.markdown == 'true' }} steps: - uses: actions/checkout@v4 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - name: Install prettier - run: pnpm add -g prettier@3.1.0 - - name: Check markdown formatting with prettier - run: prettier --check . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command prettier --check . diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ed7be0c..34bd84f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -44,9 +44,7 @@ jobs: - uses: actions/checkout@v4 - name: Install uv uses: astral-sh/setup-uv@v4 - - name: Install dependencies with pytest + - name: Install dependencies run: uv sync --dev - - name: Fetch camoufox data - run: uv run camoufox fetch - name: Run Python tests run: uv run pytest tests/ -v diff --git a/.gitignore b/.gitignore index 45bc345..a489c55 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ __pycache__ .claude/ node_modules/ + +.envrc +.direnv/ diff --git a/.luarc.json b/.luarc.json index 3ccfeda..727793d 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,8 +1,21 @@ { - "runtime.version": "Lua 5.1", - "runtime.path": ["lua/?.lua", "lua/?/init.lua"], - "diagnostics.globals": ["vim"], - "workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"], - "workspace.checkThirdParty": false, - "completion.callSnippet": "Replace" + "runtime": { + "version": "LuaJIT", + "path": ["lua/?.lua", "lua/?/init.lua"] + }, + "diagnostics": { + "globals": ["vim"] + }, + "workspace": { + "library": [ + "$VIMRUNTIME/lua", + "${3rd}/luv/library", + "${3rd}/busted/library" + ], + "checkThirdParty": false, + "ignoreDir": [".direnv"] + }, + "completion": { + "callSnippet": "Replace" + } } diff --git a/.styluaignore b/.styluaignore new file mode 100644 index 0000000..9b42106 --- /dev/null +++ b/.styluaignore @@ -0,0 +1 @@ +.direnv/ diff --git a/README.md b/README.md index cf82417..427496d 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,12 @@ Install using your package manager of choice or via luarocks install cp.nvim ``` -## Optional Dependencies +## Dependencies -- [uv](https://docs.astral.sh/uv/) for problem scraping - GNU [time](https://www.gnu.org/software/time/) and [timeout](https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html) +- [uv](https://docs.astral.sh/uv/) or [nix](https://nixos.org/) for problem + scraping ## Quick Start diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index d6d1d73..e6c4c61 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -3,13 +3,46 @@ Author: Barrett Ruth License: Same terms as Vim itself (see |license|) +============================================================================== +CONTENTS *cp-contents* + + 1. Introduction .................................................. |cp.nvim| + 2. Requirements ........................................ |cp-requirements| + 3. Setup ........................................................ |cp-setup| + 4. Configuration ................................................ |cp-config| + 5. Commands .................................................. |cp-commands| + 6. Mappings .................................................. |cp-mappings| + 7. Language Selection .................................. |cp-lang-selection| + 8. Workflow .................................................. |cp-workflow| + 9. Workflow Example ............................................ |cp-example| + 10. Verdict Formatting ................................. |cp-verdict-format| + 11. Picker Integration .......................................... |cp-picker| + 12. Picker Keymaps ........................................ |cp-picker-keys| + 13. Panel ........................................................ |cp-panel| + 14. Interactive Mode .......................................... |cp-interact| + 15. Stress Testing .............................................. |cp-stress| + 16. Race .......................................................... |cp-race| + 17. Credentials ............................................ |cp-credentials| + 18. Submit ...................................................... |cp-submit| + 19. Submit Language Versions ......................... |cp-submit-language| + 20. Open ......................................................... |cp-open| + 21. ANSI Colors ................................................... |cp-ansi| + 22. Highlight Groups ........................................ |cp-highlights| + 23. Terminal Colors .................................... |cp-terminal-colors| + 24. Highlight Customization .......................... |cp-highlight-custom| + 25. Helpers .................................................... |cp-helpers| + 26. Statusline Integration .................................. |cp-statusline| + 27. Panel Keymaps .......................................... |cp-panel-keys| + 28. File Structure ................................................ |cp-files| + 28. Health Check ................................................ |cp-health| + ============================================================================== 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 +Supported platforms: AtCoder, CodeChef, Codeforces, CSES, Kattis, USACO ============================================================================== REQUIREMENTS *cp-requirements* @@ -19,195 +52,20 @@ REQUIREMENTS *cp-requirements* - uv package manager (https://docs.astral.sh/uv/) ============================================================================== -COMMANDS *cp-commands* +SETUP *cp-setup* -:CP *:CP* - cp.nvim uses a single :CP command with intelligent argument parsing: - - Setup Commands ~ - :CP {platform} {contest_id} [--lang {language}] - Full setup: set platform and load contest metadata. - Scrapes test cases and creates source file. - --lang: Use specific language (default: platform default) - Examples: > - :CP codeforces 1933 - :CP codeforces 1933 --lang python -< - View Commands ~ - :CP run [all|n|n,m,...] [--debug] - Run tests in I/O view (see |cp-io-view|). - Lightweight split showing test verdicts. - - Execution modes: - • :CP run Combined: single execution with all tests - (auto-switches to individual when multiple samples) - • :CP run all Individual: N separate executions - • :CP run n Individual: run test n only - • :CP run n,m,... Individual: run specific tests (e.g. nth and mth) - - --debug: Use debug build (builds to build/.dbg) - - Combined mode runs all test inputs in one execution (matching - platform behavior for multi-test problems). When a problem has - multiple independent sample test cases, :CP run auto-switches to - individual mode to run each sample separately. - - Examples: > - :CP run " Combined: all tests, one execution - :CP run all " Individual: all tests, N executions - :CP run 2 " Individual: test 2 only - :CP run 1,3,5 " Individual: tests 1, 3, and 5 - :CP run all --debug " Individual with debug build -< - :CP panel [--debug] [n] - Open full-screen test panel (see |cp-panel|). - Aggregate table with diff modes for detailed analysis. - Optional [n] focuses on specific test. - --debug: Use debug build (with sanitizers, etc.) - Examples: > - :CP panel " All tests - :CP panel --debug 3 " Test 3, debug build -< - - :CP pick [--lang {language}] - Launch configured picker for interactive - platform/contest selection. - --lang: Pre-select language for chosen contest. - Example: > - :CP pick - :CP pick --lang python -< - - :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 [--lang {language}] - Navigate to next problem in current contest. - Stops at last problem (no wrapping). - --lang: Use specific language for next problem. - By default, preserves current file's language if - enabled for the new problem, otherwise uses platform - default. - Examples: > - :CP next - :CP next --lang python -< - :CP prev [--lang {language}] - Navigate to previous problem in current contest. - Stops at first problem (no wrapping). - --lang: Use specific language for previous problem. - By default, preserves current file's language if - enabled for the new problem, otherwise uses platform - default. - Examples: > - :CP prev - :CP prev --lang cpp -< - :CP {problem_id} [--lang {language}] - Jump to problem {problem_id} in a contest. - Requires that a contest has already been set up. - --lang: Use specific language for this problem. - Examples: > - :CP B - :CP C --lang python -< - - Edit Commands ~ - :CP edit [n] - Open grid test editor showing all test cases. - Tests displayed as 2×N grid (2 rows, N columns): - • Top row: Test inputs (editable) - • Bottom row: Expected outputs (editable) - - Optional [n]: Jump cursor to test n's input buffer - - Changes saved to both cache and disk on exit, - taking effect immediately in :CP run and CLI. - - Keybindings (configurable via |EditConfig|): - q Save all and exit editor - ]t Jump to next test column - [t Jump to previous test column - gd Delete current test column - ga Add new test column at end - Normal window navigation - - Examples: > - :CP edit " Edit all tests - :CP edit 3 " Edit all, start at test 3 -< - - 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 [platform] [contest] - Clear cache data at different granularities: - • No args: Clear all cached data - • [platform]: Clear all data for a platform - • [platform] [contest]: Clear specific contest - Examples: > - :CP cache clear - :CP cache clear codeforces - :CP cache clear codeforces 1848 -< - :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" or - "build/abc324a.dbg" for debug builds) - - Example template: > - build = { 'g++', '{source}', '-o', '{binary}', '-std=c++17' } -< Would expand to: > - g++ abc324a.cpp -o build/abc324a.run -std=c++17 -< -Debug Builds ~ - *cp-debug-builds* - The --debug flag uses the debug command configuration instead of build: - - • Normal build: commands.build → outputs to build/.run - • Debug build: commands.debug → outputs to build/.dbg - - Debug builds typically include sanitizers (address, undefined behavior) to - catch memory errors, buffer overflows, and other issues. Both binaries - coexist, so you can switch between normal and debug mode without - recompiling. - - Example debug configuration: > - languages = { - cpp = { - extension = 'cc', - commands = { - build = { 'g++', '-std=c++17', '{source}', '-o', '{binary}' }, - run = { '{binary}' }, - debug = { 'g++', '-std=c++17', '-fsanitize=address,undefined', - '{source}', '-o', '{binary}' }, - } - } - } +Load cp.nvim with your package manager. For example, with lazy.nvim: >lua + { 'barrettruth/cp.nvim' } < +The plugin works automatically with no configuration required. For +customization, see |cp-config|. ============================================================================== CONFIGURATION *cp-config* -Configuration is done via `vim.g.cp_config`. Set this before using the plugin: +Configuration is done via `vim.g.cp`. Set this before using the plugin: >lua - vim.g.cp_config = { + vim.g.cp = { languages = { cpp = { extension = 'cc', @@ -235,16 +93,7 @@ Configuration is done via `vim.g.cp_config`. Set this before using the plugin: 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 = { ansi = true, @@ -269,23 +118,27 @@ Configuration is done via `vim.g.cp_config`. Set this before using the plugin: < 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'. +'languages'. All six platforms are enabled by default. User-supplied +platform entries are merged on top of the defaults — you only need to +specify what you want to change. To disable a platform entirely, set it +to `false`. -For example, to run CodeForces contests with Python by default: +For example, to run Codeforces contests with Python by default and +disable CodeChef: >lua - vim.g.cp_config = { + vim.g.cp = { platforms = { codeforces = { default_language = 'python', }, + codechef = false, }, } < Any language is supported provided the proper configuration. For example, to -run CSES problems with Rust using the single schema: +add Rust and use it by default on CSES: >lua - vim.g.cp_config = { + vim.g.cp = { languages = { rust = { extension = 'rs', @@ -307,8 +160,11 @@ run CSES problems with Rust using the single schema: Fields: ~ {languages} (table) Global language registry. Each language provides an {extension} and {commands}. - {platforms} (table) Per-platform enablement, - default language, and optional overrides. + {platforms} (table) All six platforms + are enabled by default. Each entry is merged on top + of the platform defaults — omitted fields keep their + defaults and unmentioned platforms stay enabled. Set + a platform key to `false` to disable it entirely. {hooks} (|cp.Hooks|) Hook functions called at various stages. {debug} (boolean, default: false) Show info messages. {scrapers} (string[]) Supported platform ids. @@ -317,8 +173,6 @@ run CSES problems with Rust using the single schema: Should return full filename with extension. (default: concatenates contest_id and problem_id, lowercased) {ui} (|CpUI|) UI settings: panel, diff backend, picker. - {open_url} (boolean) Open the contest & problem url in the browser - when the contest is first opened. *CpPlatform* Fields: ~ @@ -395,42 +249,355 @@ run CSES problems with Rust using the single schema: *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) - {setup_io_input} (function, optional) Called when I/O input buffer created. - function(bufnr: integer, state: cp.State) - Default: helpers.clearcol (removes line numbers/columns) - {setup_io_output} (function, optional) Called when I/O output buffer created. - function(bufnr: integer, state: cp.State) - Default: helpers.clearcol (removes line numbers/columns) + {setup} (|cp.CpSetupHooks|, optional) One-time initialization hooks. + {on} (|cp.CpOnHooks|, optional) Recurring event hooks. - Hook functions receive the cp.nvim state object (|cp.State|). See + *cp.CpSetupHooks* + Fields: ~ + {contest} (function, optional) Called once when a contest directory + is first created (not on subsequent visits). + function(state: cp.State) + {code} (function, optional) Called after the source buffer is + opened for the first time (guarded by cp_setup_done). + function(state: cp.State) + {io} (|cp.CpSetupIOHooks|, optional) I/O buffer hooks. + + *cp.CpSetupIOHooks* + Fields: ~ + {input} (function, optional) Called when the I/O input buffer is + created. function(bufnr: integer, state: cp.State) + Default: helpers.clearcol + {output} (function, optional) Called when the I/O output buffer is + created. function(bufnr: integer, state: cp.State) + Default: helpers.clearcol + + *cp.CpOnHooks* + Fields: ~ + {enter} (function, optional) Called on every BufEnter on the + solution buffer. Registered as a buffer-scoped autocmd and + fired immediately after setup.code. + function(state: cp.State) + {run} (function, optional) Called before the test panel opens. + function(state: cp.State) + {debug} (function, optional) Called before a debug run. + function(state: cp.State) + + All hook functions receive the cp.nvim state object (|cp.State|). See |lua/cp/state.lua| for available methods and fields. - The I/O buffer hooks are called once when the buffers are first created - during problem setup. Use these to customize buffer appearance (e.g., - remove line numbers, set custom options). Access helpers via: ->lua - local helpers = require('cp').helpers -< Example usage: >lua hooks = { - setup_code = function(state) - print("Setting up " .. state.get_base_name()) - print("Source file: " .. state.get_source_file()) - end, - setup_io_input = function(bufnr, state) - -- Custom setup for input buffer - vim.api.nvim_set_option_value('number', false, { buf = bufnr }) - end + setup = { + contest = function(state) + local dir = vim.fn.fnamemodify( + state.get_source_file(state.get_language()), ':h') + vim.fn.system({ 'cp', '~/.clang-format', dir .. '/.clang-format' }) + end, + code = function(state) + vim.opt_local.foldmethod = 'marker' + vim.diagnostic.enable(false) + end, + }, + on = { + enter = function(state) vim.opt_local.winbar = '' end, + run = function(state) require('config.lsp').format() end, + }, } < +============================================================================== +COMMANDS *cp-commands* + +:CP *:CP* + cp.nvim uses a single :CP command with intelligent argument parsing: + + Setup Commands ~ + :CP {platform} {contest_id} [--lang {language}] + Full setup: set platform and load contest metadata. + Scrapes test cases and creates source file. + --lang: Use specific language (default: platform default) + Examples: > + :CP codeforces 1933 + :CP codeforces 1933 --lang python +< + View Commands ~ + :CP run [all|n|n,m,...] [--debug] + Run tests in I/O view (see |cp-io-view|). + Lightweight split showing test verdicts. + + Execution modes: + • :CP run Combined: single execution with all tests + (auto-switches to individual when multiple samples) + • :CP run all Individual: N separate executions + • :CP run n Individual: run test n only + • :CP run n,m,... Individual: run specific tests (e.g. nth and mth) + + --debug: Use debug build (builds to build/.dbg) + + Combined mode runs all test inputs in one execution (matching + platform behavior for multi-test problems). When a problem has + multiple independent sample test cases, :CP run auto-switches to + individual mode to run each sample separately. + + Examples: > + :CP run " Combined: all tests, one execution + :CP run all " Individual: all tests, N executions + :CP run 2 " Individual: test 2 only + :CP run 1,3,5 " Individual: tests 1, 3, and 5 + :CP run all --debug " Individual with debug build +< + :CP panel [--debug] [n] + Open full-screen test panel (see |cp-panel|). + Aggregate table with diff modes for detailed analysis. + Optional [n] focuses on specific test. + --debug: Use debug build (with sanitizers, etc.) + Examples: > + :CP panel " All tests + :CP panel --debug 3 " Test 3, debug build +< + + :CP pick [--lang {language}] + Launch configured picker for interactive + platform/contest selection. + --lang: Pre-select language for chosen contest. + Example: > + :CP pick + :CP pick --lang python +< + + :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. + + :CP stress [generator] [brute] + Start an automated stress test loop against a + brute-force reference. Toggles off if already + running. Without arguments, auto-detects a + generator and brute script in the working + directory. See |cp-stress|. + + Navigation Commands ~ + :CP next [--lang {language}] + Navigate to next problem in current contest. + Stops at last problem (no wrapping). + --lang: Use specific language for next problem. + By default, preserves current file's language if + enabled for the new problem, otherwise uses platform + default. + Examples: > + :CP next + :CP next --lang python +< + :CP prev [--lang {language}] + Navigate to previous problem in current contest. + Stops at first problem (no wrapping). + --lang: Use specific language for previous problem. + By default, preserves current file's language if + enabled for the new problem, otherwise uses platform + default. + Examples: > + :CP prev + :CP prev --lang cpp +< + :CP {problem_id} [--lang {language}] + Jump to problem {problem_id} in a contest. + Requires that a contest has already been set up. + --lang: Use specific language for this problem. + Examples: > + :CP B + :CP C --lang python +< + + Edit Commands ~ + :CP edit [n] + Open grid test editor showing all test cases. + Tests displayed as 2×N grid (2 rows, N columns): + • Top row: Test inputs (editable) + • Bottom row: Expected outputs (editable) + + Optional [n]: Jump cursor to test n's input buffer + + Changes saved to both cache and disk on exit, + taking effect immediately in :CP run and CLI. + + Keybindings (configurable via |EditConfig|): + q Save all and exit editor + ]t Jump to next test column + [t Jump to previous test column + gd Delete current test column + ga Add new test column at end + Normal window navigation + + Examples: > + :CP edit " Edit all tests + :CP edit 3 " Edit all, start at test 3 +< + + Race Commands ~ + :CP {platform} {contest_id} --race [--lang {language}] + Start a countdown to the contest's scheduled + start time. At T=0, automatically runs: + :CP {platform} {contest_id} [--lang ...] + Examples: > + :CP atcoder abc400 --race + :CP codeforces 2100 --race --lang python +< + Credential Commands ~ + :CP login [platform] + Set or update stored credentials for a platform. + Prompts for username and password, overwriting + any previously saved credentials. + If [platform] is omitted, uses the active platform. + Examples: > + :CP login atcoder + :CP login codeforces +< + :CP logout [platform] + Remove stored credentials for a platform. + If [platform] is omitted, uses the active platform. + Examples: > + :CP logout atcoder +< + :CP {platform} signup + Open the platform's registration page in the + browser via |vim.ui.open|. Works even if + {platform} is not enabled in your config. + Examples: > + :CP atcoder signup + :CP codeforces signup +< + Submit Commands ~ + :CP submit [--lang {language}] + Submit the current solution to the online + judge. Uses stored credentials (set via + :CP login). Prompts on first use if no + credentials are saved. + --lang: Submit solution for a specific language. + + :CP open [problem|contest|standings] + Open the URL for the current problem, contest, + or standings page in the browser via + |vim.ui.open|. Defaults to "problem" if no + argument is given. Warns if the URL is not + available (e.g. CSES has no standings). + Examples: > + :CP open + :CP open contest + :CP open standings +< + 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 [platform] [contest] + Clear cache data at different granularities: + • No args: Clear all cached data + • [platform]: Clear all data for a platform + • [platform] [contest]: Clear specific contest + Examples: > + :CP cache clear + :CP cache clear codeforces + :CP cache clear codeforces 1848 +< + :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" or + "build/abc324a.dbg" for debug builds) + + Example template: > + build = { 'g++', '{source}', '-o', '{binary}', '-std=c++17' } +< Would expand to: > + g++ abc324a.cpp -o build/abc324a.run -std=c++17 +< +Debug Builds ~ + *cp-debug-builds* + The --debug flag uses the debug command configuration instead of build: + + • Normal build: commands.build → outputs to build/.run + • Debug build: commands.debug → outputs to build/.dbg + + Debug builds typically include sanitizers (address, undefined behavior) to + catch memory errors, buffer overflows, and other issues. Both binaries + coexist, so you can switch between normal and debug mode without + recompiling. + + Example debug configuration: > + languages = { + cpp = { + extension = 'cc', + commands = { + build = { 'g++', '-std=c++17', '{source}', '-o', '{binary}' }, + run = { '{binary}' }, + debug = { 'g++', '-std=c++17', '-fsanitize=address,undefined', + '{source}', '-o', '{binary}' }, + } + } + } +< + +============================================================================== +MAPPINGS *cp-mappings* + +cp.nvim provides mappings for all primary actions. These dispatch +through the same code path as |:CP|. + + *(cp-run)* +(cp-run) Run tests in I/O view. Equivalent to :CP run. + + *(cp-panel)* +(cp-panel) Open full-screen test panel. Equivalent to :CP panel. + + *(cp-edit)* +(cp-edit) Open the test case editor. Equivalent to :CP edit. + + *(cp-next)* +(cp-next) Navigate to the next problem. Equivalent to :CP next. + + *(cp-prev)* +(cp-prev) Navigate to the previous problem. Equivalent to :CP prev. + + *(cp-pick)* +(cp-pick) Launch the contest picker. Equivalent to :CP pick. + + *(cp-interact)* +(cp-interact) Open interactive mode. Equivalent to :CP interact. + + *(cp-stress)* +(cp-stress) Run stress test loop. Equivalent to :CP stress. + + *(cp-submit)* +(cp-submit) Submit current solution. Equivalent to :CP submit. + + *(cp-open)* +(cp-open) Open current problem URL in browser. Equivalent to :CP open. + +Example configuration: >lua + vim.keymap.set('n', 'cr', '(cp-run)') + vim.keymap.set('n', 'cp', '(cp-panel)') + vim.keymap.set('n', 'ce', '(cp-edit)') + vim.keymap.set('n', 'cn', '(cp-next)') + vim.keymap.set('n', 'cN', '(cp-prev)') + vim.keymap.set('n', 'cc', '(cp-pick)') + vim.keymap.set('n', 'ci', '(cp-interact)') + vim.keymap.set('n', 'cs', '(cp-stress)') + vim.keymap.set('n', 'cu', '(cp-submit)') + +< + ============================================================================== LANGUAGE SELECTION *cp-lang-selection* @@ -508,6 +675,41 @@ URL format: https://cses.fi/problemset/task/{problem_id} Usage examples: > :CP cses dynamic_programming " Set up all problems in dp category +CodeChef ~ + *cp-codechef* +URL format: https://www.codechef.com/{contest_id}/problems/{problem_id} + +The contest_id is the contest code from the URL (e.g. START209). + +Usage examples: > + :CP codechef START209 " Set up codechef.com/START209 + +USACO ~ + *cp-usaco* +URL format: https://usaco.org/index.php?page=viewproblem2&cpid={cpid} + +The contest_id combines the abbreviated month, two-digit year, and division +in lowercase, joined by underscores (e.g. dec24_gold, feb23_silver). + +Usage examples: > + :CP usaco dec24_gold " Set up December 2024 Gold division + :CP usaco feb23_silver " Set up February 2023 Silver division + +Kattis ~ + *cp-kattis* +Kattis supports single-problem and full-contest modes. + +Single problem — the contest_id is the problem slug from the URL: +URL format: https://open.kattis.com/problems/{slug} + +Full contest — the contest_id is the contest ID from the URL. All problems +are set up at once with :CP next/:CP prev navigation: +URL format: https://open.kattis.com/contests/{id} + +Usage examples: > + :CP kattis primesieve " Single problem + :CP kattis t8tnpe " Full contest (all problems, A–H navigation) + ============================================================================== COMPLETE WORKFLOW EXAMPLE *cp-example* @@ -542,7 +744,9 @@ Example: Setting up and solving AtCoder contest ABC324 :CP < Automatically restores abc323 contest context -8. Submit solutions on AtCoder website +8. Submit solution: > + :CP submit +< Uses stored credentials and submits to AtCoder. ============================================================================== I/O VIEW *cp-io-view* @@ -612,9 +816,9 @@ While in the I/O view buffers, use the configured keymaps to cycle through tests Buffer Customization ~ -Use the setup_io_input and setup_io_output hooks (see |cp.Hooks|) to customize -buffer appearance. By default, line numbers and columns are removed via -helpers.clearcol (see |cp-helpers|). +Use the hooks.setup.io.input and hooks.setup.io.output hooks (see |cp.Hooks|) +to customize buffer appearance. By default, line numbers and columns are +removed via helpers.clearcol (see |cp-helpers|). ============================================================================== VERDICT FORMATTING *cp-verdict-format* @@ -753,6 +957,144 @@ When using :CP interact {interactor}, the interactor must be executable Keymaps ~ Close the terminal and restore the previous layout. +============================================================================== +STRESS TESTING *cp-stress* + +Start an automated stress test loop to find inputs where your solution +disagrees with a brute-force reference. + +:CP stress [generator] [brute] + Start the stress loop. Toggles off if the loop is already running. + {generator} Generator script path (default: auto-detected). + {brute} Brute-force solution path (default: auto-detected). + Auto-detection looks for files named gen.* and brute.* in the CWD. + + The stress panel opens and streams results for each iteration. + On a mismatch, the failing input is displayed in the panel. + +Keymaps ~ + Close the stress panel and restore the previous layout. + +============================================================================== +RACE *cp-race* + +Count down to a contest's start time and automatically run setup at T=0. + +:CP {platform} {contest_id} --race [--lang {language}] + Start a countdown timer. At T=0, automatically runs: + :CP {platform} {contest_id} [--lang {language}] + Examples: > + :CP atcoder abc400 --race + :CP codeforces 2100 --race --lang python +< +Starting a new race while one is active automatically cancels the previous one. + +Statusline integration: see |cp-race-status|. + +============================================================================== +CREDENTIALS *cp-credentials* + +Manage stored login credentials for platform submission. + +Credentials are stored under _credentials in the main cache file +(stdpath('data')/cp-nvim.json). Use :CP cache read to inspect them. + +:CP login [platform] + Set or update credentials for a platform. Prompts for username + and password, overwriting any previously saved values. + Omit [platform] to use the currently active platform. + +:CP logout [platform] + Remove stored credentials for a platform. + Omit [platform] to use the currently active platform. + +:CP {platform} signup + Open the platform's account registration page in the browser via + |vim.ui.open|. Works even if {platform} is not enabled in your + config. {platform} is one of: atcoder, codechef, codeforces, cses, + kattis, usaco. + +============================================================================== +SUBMIT *cp-submit* + +Submit the current solution to the online judge. + +:CP submit [--lang {language}] + Submit the current solution. Uses stored credentials (set via + :CP login). Prompts on first use if no credentials are saved. + --lang: Override the language to submit. + + Platform support: + AtCoder Fully implemented. + Codeforces Fully implemented. + CSES Fully implemented. + Kattis Fully implemented. + USACO Fully implemented. + CodeChef Not yet implemented. + + See |cp-submit-language| for configuring the language version + (e.g. C++20 instead of C++17). + +============================================================================== +SUBMIT LANGUAGE VERSIONS *cp-submit-language* + +When submitting, cp.nvim selects a language version for the platform. +The default is C++17 for cpp and Python 3 for python. + +Configuring a version ~ + +Set {version} globally or per-platform: +>lua + languages = { + cpp = { version = "c++20", ... }, + }, + platforms = { + atcoder = { + overrides = { cpp = { version = "c++23" } }, + }, + }, +< +Available versions per platform ~ + + Platform cpp python + AtCoder c++23 python3 + Codeforces c++17 python3 + CSES c++17 python3 + Kattis c++17/20/23 python3 + USACO c++17/20/23 python3 + CodeChef c++17 python3 + +Using a raw platform ID ~ + +If your preferred version is not listed, you can bypass version +lookup by setting {submit_id} to the raw platform language ID: +>lua + platforms = { + codeforces = { + overrides = { cpp = { submit_id = "91" } }, + }, + }, +< +To find the raw ID, open the platform's submit page in your browser, +inspect the language dropdown, and copy the