---
title: "cp.nvim"
slug: "cp.nvim"
date: "10/10/2025"
---

Things have changed since I last documented my competitive programming setup [here](/software/my-competitive-programming-setup.html).

# my goals

After many months of using the aforementioned `make` based setup, I had a few qualms:

- <u>I'm lazy</u>: I grew tired of copying (and mis-copying) inputs, outputs,
  etc from online judges.
- <u>I'm lazy</u>: I frequently submitted incorrect solutions after erroneously
  asserting that my outputs matched those of the sample test cases
- <u>External dependencies</u>: it unsettles me that my bare-bones setup
  required copy-pasting an entire suite of scripts
- <u>Non-native neovim experience</u>: while composition and the UNIX philosophy
  are great, there's only so much you can do with pipes and files. - Raw I/O
  files meant I couldn't see colored stdin/stdout - Fine-grained per-testcase
  I/O was suspect--isolating and running a subset of test cases required manual
  intervention

The solution was to leverage Neovim's great APIs to give me granular control over every aspect of my problem-solving experience.

# the solution: cp.nvim

The GitHub page documents the plugin well enough so I'll avoid re-hashing it here. Instead, what's more interesting to document is why I thought this was a worthwhile experience.

1. <u>Making Something Useful for Others</u>: cp.nvim is an opportunity for me
   to make my first open-source project "right"--not some side project or demo,
   but a *real*, usable tool that I'll be rolling out to the public soon. I
   consider the following in my active development of the plugin:

- Comprehensive continuous integration (_real_ testing, linting, and more)
- [LuaRocks](https://luarocks.org/) integration (the future of neovim package management)
- Concise and thorough Vimdoc documentation that communicates effectively
- Modern lua tooling: use of [busted](https://lunarmodules.github.io/busted/), [selene](https://kampfkarren.github.io/selene/) and more integrated with the neovim lua interpreter
- Sensible user defaults & extreme customization
- Proper versioning, tagging, and releases

2. <u>The Neovim Community</u>: I'm elated to finally give back to the community
   (even if no one uses this plugin). [folke](https://github.com/folke),
   [bfredl](https://github.com/bfredl), and
   [echasnovski](https://github.com/echasnovski) are my greatest inspirations as
   an open-source developer and I've had enough of taking without giving back.

- In the coming months I plan to contribute to [neovim core](https://github.com/neovim/neovim), including making `:checkhealth` asynchronous and integrating an [mdx](https://mdxjs.com/) parser.

3. <u>Learning Random things</u>: I think this plugin is *really* cool by virtue
   of its efficacy and the miscellany of knowledge I accrued in the 15k+ LOC as
   of version v0.3.0. Some things I learned include:

- <u>ANSI terminal colors and escape codes</u>: I wrote my own stateful ANSI
  escape sequence parser to map raw bytes to native neovim highlighted text
- <u>Extmarks</u>: neovim extmarks (`:h extmarks`) are extremely powerful. Here,
  I used them to apply dynamic highlighting across various components of the
  plugin but I also plan to leverage virtual text to catch compile errors in
  real-time
- <u>VIM filetypes and diffing</u>: Vim is strange and the event-based system is
  fragile. I faced filetype detection race conditions and odd side effects of
  functions (such as `:diffthis` resetting `foldcolumn`).
- <u>[LuaCATS](https://github.com/LuaCATS)</u>: apparently writing comments is
  the best way to typecheck in lua...
- <u>The (Neo)Vim event loop</u>: Scraper subprocesses spawned with
  `vim.system`. Though a powerful API, I often had to obey the event loop and
  wrap side effects with `vim.schedule` to ensure they ran after jobs finished.
  This was useful to defer UI updates.
