Dmoj.nvim
A Neovim plugin enabling you to solve DMOJ problems.
Install / Use
/learn @shouryadixitisverycool/Dmoj.nvimREADME
dmoj.nvim
Solve DMOJ problems without leaving Neovim
</div>https://github.com/user-attachments/assets/eb2aaa3e-d8fe-4dfb-ab20-f35d0c00e6fd
📋 Table of Contents
- ✨ Features
- 📬 Requirements
- 📦 Installation
- 🔑 Authentication
- 🛠️ Configuration
- 📋 Commands
- 🚀 Usage
- 🔒 Security
- ❓ FAQ
✨ Features
- 📌 dashboard home screen for quick navigation
- 🔭 [Telescope]-powered fuzzy problem picker (with fallback for non-Telescope setups)
- 📄 problem descriptions rendered inline — no browser needed
- ⚡ submit solutions with live verdict polling and per-case results
- 🧪 local test runner — compile and run against sample cases before submitting
- 🏆 contest browser — list active/upcoming/past contests, join and leave
- 🏛️ works with dmoj.ca and any self-hosted DMOJ instance (college OJs, etc.)
📬 Requirements
- Neovim >= 0.9
curl(pre-installed on macOS and most Linux distros)- telescope.nvim (optional, but strongly recommended)
| Platform | Status | |---|---| | Linux | Fully supported | | macOS | Fully supported | | Windows | Not supported |
📦 Installation
{
"your-username/dmoj.nvim",
lazy = false,
dependencies = {
"nvim-telescope/telescope.nvim",
},
opts = {
lang = "CPP17",
},
}
For lazy-loading (only loads when launched as nvim dmoj.nvim):
{
"your-username/dmoj.nvim",
lazy = "dmoj.nvim" ~= vim.fn.argv(0, -1),
dependencies = { "nvim-telescope/telescope.nvim" },
opts = { lang = "CPP17" },
}
Manual (no plugin manager)
vim.opt.runtimepath:prepend("~/path/to/dmoj.nvim")
require("dmoj").setup({})
🔑 Authentication
DMOJ has no public submission API, so dmoj.nvim authenticates via your browser session cookie — the same approach used by leetcode.nvim.
[!WARNING] Copy the
Cookievalue from Request Headers in the Network tab, not from Application → Cookies or Response Headers.
Steps:
- Log in to your DMOJ instance in your browser
- Open DevTools (
F12) → Network tab - Reload the page and click any request to the OJ domain
- Under Request Headers, find the
Cookie:line and copy its full value- It looks like:
csrftoken=abc123; sessionid=xyz789
- It looks like:
- In Neovim, run
:Dmoj loginand paste it
Cookie stored at:
- Linux:
~/.local/share/nvim/dmoj/cookie.txt - macOS:
~/Library/Application Support/nvim/dmoj/cookie.txt
File is created with 600 permissions (readable only by you).
[!NOTE] The cookie is tied to your browser session. If you log out in the browser or the session expires, run
:Dmoj loginagain.
🛠️ Configuration
require("dmoj").setup({
base_url = "https://dmoj.ca",
lang = "CPP17",
storage_dir = vim.fn.stdpath("data") .. "/dmoj",
-- open_cmd = "xdg-open", -- auto-detected: "open" on macOS, "xdg-open" on Linux
arg = "dmoj.nvim",
keymaps = {
list = "<leader>dl",
submit = "<leader>ds",
test = "<leader>dt",
desc = "<leader>dd",
open_browser = "<leader>do",
},
})
<details>
<summary>Available language keys</summary>
| Language | Key | Local runner |
|---|---|---|
| C | C | gcc |
| C++ 03/11/14/17/20/23 | CPP03 … CPP23 | g++ |
| Python 2 | PY2 | python2 |
| Python 3 | PY3 | python3 |
| PyPy / PyPy 3 | PYPY / PYPY3 | pypy / pypy3 |
| Java 8/11/17/21 | JAVA8 … JAVA21 | javac + java |
| Rust | RUST | rustc |
| Go | GO | go run |
| Kotlin | KOTLIN | kotlinc + java -jar |
| Ruby | RUBY | ruby |
| Lua | LUA | lua |
| Perl | PERL | perl |
| PHP | PHP | php |
| Haskell | HASK | ghc |
| Mono (C#) | MONO | mcs + mono |
| Dart | DART | dart run |
| Scala | SCALA | scalac + scala |
| Swift | SWIFT | swiftc |
The local runner requires the compiler/interpreter to be on your PATH. The judge on DMOJ uses its own toolchain, so local and remote language versions may differ.
📋 Commands
| Command | Description |
|---|---|
| :Dmoj / :Dmoj menu | Open the dashboard |
| :Dmoj list | Browse problems (Telescope picker) |
| :Dmoj open <code> | Open a problem by code |
| :Dmoj contests | Browse contests |
| :Dmoj submit | Submit current buffer |
| :Dmoj submit <code> | Submit current buffer to a specific problem |
| :Dmoj run | Run locally against sample test cases |
| :Dmoj desc [code] | Show problem description |
| :Dmoj result <id> | Fetch a submission result by ID |
| :Dmoj browser | Open current problem in browser |
| :Dmoj login | Set session cookie |
| :Dmoj logout | Delete stored cookie |
| :Dmoj whoami | Check current login |
| :Dmoj refresh | Clear problem list cache |
🚀 Usage
Launch directly into the DMOJ dashboard:
nvim dmoj.nvim
Or from within Neovim: :Dmoj
Opening a problem — :Dmoj open <code> or Enter from picker:
- Opens description in a left split
- Creates/opens solution file at
<storage_dir>/solutions/<code>.<ext> - Pre-fills a language-appropriate comment header
Submitting — :Dmoj submit or <leader>ds: polls judge every 1.5s, shows floating verdict with per-case breakdown.
Local testing — :Dmoj run or <leader>dt: compiles and runs against sample cases from the description. No submission made.
Contest browser — :Dmoj contests or [c] from dashboard:
| Icon | Meaning |
|---|---|
| ★ | Currently participating |
| ● | Active |
| ◷ | Upcoming |
| ○ | Past |
From contest detail: Enter to join, Backspace to leave, q to go back.
Private/organization DMOJ instances — set base_url in config. All data is scraped via cookie auth; no API v2 dependency.
🔒 Security
- No credential exposure in
ps aux— headers and form data are written to restricted temp files (600) passed to curl via--header @file/--data @file - Cookie file
600from creation — no world-readable window - HTTPS only — no
-kflag - No credential logging — cookie never written to any buffer
❓ FAQ
"Cookie appears invalid" or :Dmoj whoami returns nothing
Log out and back in to the browser, copy the new Cookie from Request Headers, run :Dmoj login.
Problem list is empty
Run :Dmoj login first, then :Dmoj refresh.
Language not found on submit
The error lists available names from the submit page. Set lang in config to one of those.
Description shows "(Could not extract problem description)"
The HTML scraping patterns may not match your OJ's template version. Use :Dmoj browser to open in your browser instead.
Submission times out / no verdict
Plugin polls 90s max. Use :Dmoj result <id> to check manually.
"Cannot join: no CSRF token in cookie"
Run :Dmoj login to refresh your session cookie.
Works with private/organization DMOJ instances?
Yes — set base_url in config. All data is scraped via cookie auth, no API needed.
The following project is 100% written by claude and probably contains a fuck ton of security flaws and non-functioning code. This was made mostly for personal use and hasn't been tested on any device other than mine (it works on my machine bro). Proceed with caution, you have been warned.
This project is heavily inspired (straight up plagiarism at this point) by leetcode.nvim
</div>Related Skills
node-connect
352.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
