Debugger for LeetCode
Browse, fetch, debug and submit LeetCode problems in C#, Go, Python and Rust from VS Code — including real breakpoint debugging, which LeetCode itself puts behind a premium subscription.
Why
leetcode.vscode-leetcode handles browsing and submitting but cannot debug. wangtao0101.debug-leetcode debugs, but only C++, JavaScript and Python. This extension debugs C#, Go, Python and Rust through one workflow.
Languages
| Language |
LeetCode slug |
File |
Toolchain you provide |
VS Code extension |
Debug adapter |
| C# |
csharp |
.cs |
.NET SDK 8.0 or later |
ms-dotnettools.csharp |
coreclr |
| Go |
golang |
.go |
Go toolchain and Delve |
golang.go |
go |
| Python |
python3 |
.py |
Python 3 |
ms-python.python |
debugpy |
| Rust |
rust |
.rs |
Cargo and rustc |
vadimcn.vscode-lldb |
lldb |
Python maps to LeetCode's python3 slug rather than python, because the latter is Python 2.7 and effectively a different language.
Each language probes its toolchain and debug extension before it runs, so a missing go binary or CodeLLDB is reported as such instead of failing somewhere inside a build.
How debugging works
Opening a problem generates a harness in your workspace and runs your solution file through it. Your file is referenced rather than copied, so breakpoints bind to the file you are editing: no source mapping, no generated duplicate to keep in sync. The references are relative, so the folder survives being moved between machines or workspaces.
How that harness is built differs per language, because their toolchains do:
- C# compile-links your file into a per-problem project with
<Compile Include="..." Link="Solution.cs" />. Each problem needs its own project rather than a shared one, because every LeetCode file declares public class Solution and one project would fail with duplicate type errors. The runner uses reflection and System.Text.Json to find your class, match the test-case lines to the method parameters and invoke it.
- Python needs neither code generation nor a build step. A single harness under
.harness/python/ serves every problem.
- Go has no reflection that can call an arbitrary function, so each problem gets a statically generated call site next to a shared
internal/lcjson helper.
- Rust uses one Cargo package for the whole problems folder, adding a
[[bin]] target per problem.
Supported shapes:
| Problem shape |
Example |
Handling |
| Value and array arguments |
[1,2,3], "abc", 5 |
Deserialized to the declared parameter type |
In-place mutation, void return |
Merge Sorted Array |
First mutated argument is reported as the output |
| Linked lists |
[1,2,3,4,5] to ListNode |
Built structurally from your own ListNode declaration |
| Binary trees |
[3,9,20,null,null,15,7] to TreeNode |
Level-order build, trailing nulls trimmed |
| Design problems |
["MinStack","push",...] |
Constructor plus operation sequence replayed |
In C#, node types are detected structurally (a class exposing val and next, or left and right), so the harness works with whatever ListNode/TreeNode declaration LeetCode puts in your file.
Browsing
The tree has two branches. Study Plans shows curated lists — Top Interview 150 and LeetCode 75 by default — grouped by topic exactly as LeetCode groups them. All Problems shows the full set split by difficulty.
Change which plans appear with leetcodeDebug.studyPlans. The slug is the last path segment of the plan URL, so https://leetcode.com/studyplan/top-100-liked/ becomes top-100-liked.
Files per problem
Each problem gets a folder under <workspace>/leetcode. The solution is nested by language, while the data files sit above it and are shared:
leetcode/
.gitignore build output, matched at any depth
0088.merge-sorted-array/
0088.merge-sorted-array.testcase one JSON value per argument, per line
0088.merge-sorted-array.expected optional expected output per case
0088.merge-sorted-array.meta.json problem identifiers
csharp/0088.merge-sorted-array.cs
go/0088.merge-sorted-array.go
Because the test cases sit above the language folders, solving the same problem again in another language reuses them.
Paste failing cases into the .testcase file straight from LeetCode. When .expected has content, the runner prints PASS/FAIL per case. Blank lines and # comments are ignored in both data files.
The generated .gitignore covers target/, bin/, obj/, __pycache__/ and Delve's __debug_bin*, so build output from any of the four languages stays out of your commits.
C# language support
Without a project, C# Dev Kit treats a loose .cs file as a miscellaneous file and reports "The active document is not part of the open workspace. Not all language features will be available." The generated projects solve this, because the same project that runs your code also gives the editor full IntelliSense. Go, Python and Rust need no equivalent step.
The C# layout looks like this:
leetcode/
LeetCode.slnx solution tying the problems together
0088.merge-sorted-array/
csharp/0088.merge-sorted-array.cs
.harness/
0088.merge-sorted-array/
0088.merge-sorted-array.csproj
Runner.cs LeetCodeJson.cs LeetCodeTypes.cs
Run Set Up Language Support once to generate projects for problem files you already have. It offers to point dotnet.defaultSolution at the generated solution, which is what makes Dev Kit load it. Note that Dev Kit loads a single solution at a time, so other projects in the workspace unload while this one is active.
LeetCodeTypes.cs supplies ListNode and TreeNode. LeetCode ships those definitions commented out because its judge injects them, and uncommenting them would break your submission with duplicate type errors. The generated project therefore provides them, but only when your own file does not declare them.
Target framework
Projects target net8.0 by default, configurable through leetcodeDebug.csharp.targetFramework.
The default deliberately tracks LeetCode's judge rather than the newest SDK on your machine. Targeting a newer framework locally lets you compile language features and BCL APIs that the judge rejects, which reproduces the exact "passes locally, fails on submit" problem this extension exists to prevent.
To confirm what the judge runs, submit a solution that throws:
throw new Exception(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
The verdict reports the runtime error text, which contains the version. Adjust the setting to match, then delete leetcode/.harness/ so the projects regenerate.
Commands
| Command |
Purpose |
| Sign In / Sign Out |
Stores your session cookies in VS Code SecretStorage |
| Refresh Problem List |
Fetches and caches the problem set for 24 hours |
| Search Problems |
Filters the tree by title, slug or number |
| Open Problem In Language... |
Fetches a problem in a language other than your default |
| Show Description |
Opens the problem statement beside or below the code |
| Edit Test Cases |
Opens the .testcase file for the active solution |
| Debug Locally |
Builds the harness and starts the debugger for that language |
| Run Locally |
Runs the harness without the debugger |
| Run on LeetCode |
Judges your sample cases remotely |
| Submit |
Submits and reports the verdict |
| Set Up Language Support |
Regenerates the C# projects so Dev Kit resolves types in the solution files |
Settings
| Setting |
Default |
Purpose |
leetcodeDebug.defaultLanguage |
csharp |
Language a fetched problem is scaffolded in (csharp, go, python, rust) |
leetcodeDebug.endpoint |
leetcode.com |
Site to connect to (leetcode.cn is also supported) |
leetcodeDebug.workspaceFolder |
first workspace folder |
Where problem files are written |
leetcodeDebug.studyPlans |
Top Interview 150, LeetCode 75 |
Study plan slugs shown in the tree |
leetcodeDebug.showLockedProblems |
false |
Show premium-only problems, which cannot be fetched |
leetcodeDebug.descriptionLayout |
below |
Open the description below or beside the code |
leetcodeDebug.suppressSuggestions |
ai |
Hide suggestions while a solution file is focused (none, ai, all) |
leetcodeDebug.csharp.targetFramework |
net8.0 |
Target framework of the generated C# projects |
If a problem has no LeetCode snippet for your default language, the extension asks which of the available languages to use instead.
Upgrading from 0.1
The settings namespace was leetcodeCs.* in 0.1. The old keys still exist, are marked deprecated, and their values are copied to the new keys on activation at whichever scope you set them. Nothing is deleted, so you can remove the old entries yourself once you are happy with the result.
Requirements
Only the languages you actually use need to be installed.
- C# — .NET SDK 8.0 or later on
PATH, and the C# extension (ms-dotnettools.csharp) for the coreclr debug adapter. Newer SDKs work; the generated projects still target leetcodeDebug.csharp.targetFramework, so the matching targeting pack must be installed. C# Dev Kit additionally provides full IntelliSense through the generated solution.
- Go — the Go toolchain on
PATH plus Delve, and the Go extension (golang.go).
- Python — Python 3, and the Python extension (
ms-python.python), which supplies debugpy.
- Rust —
cargo and rustc on PATH, and CodeLLDB (vadimcn.vscode-lldb).
Installation
Install Debugger for LeetCode from the Marketplace, or build a VSIX from source:
git clone https://github.com/bindsi/leetcode-debug.git
cd leetcode-debug
npm install
npx @vscode/vsce package
code --install-extension leetcode-debug-0.3.0.vsix
Authentication
LeetCode publishes no API tokens and no OAuth flow for third parties, so signing in reuses the session your browser already holds.
Signing in
- Run LeetCode: Sign In from the Command Palette.
- Sign in to LeetCode in your browser if you have not already.
- Open developer tools, then Application > Storage > Cookies >
https://leetcode.com.
- Copy the value of
LEETCODE_SESSION (a long token) and paste it into the first prompt.
- Copy the value of
csrftoken (roughly 64 characters) and paste it into the second prompt.
Both prompts mask what you type.
The pair is checked against LeetCode before anything is stored, so a truncated or stale paste is rejected on the spot instead of surfacing much later as a failed submit. On success the extension reports which account it signed in as.
How the credentials are used
Every request sends the pair as a cookie header, plus the CSRF token as its own header:
cookie: LEETCODE_SESSION=<session>; csrftoken=<csrf>
x-csrftoken: <csrf>
referer: https://leetcode.com/problems/<slug>/
LeetCode rejects state-changing requests that lack the matching x-csrftoken header and a plausible referer, which is why both values are needed rather than the session alone.
Handling and expiry
Credentials live in VS Code SecretStorage, backed by the system keychain. They are never written to settings, workspace state, disk or the output channel, and Sign Out deletes them.
Treat LEETCODE_SESSION as a password: anyone holding it can act as you on LeetCode. Never paste it into a chat, an issue or a committed file.
Sessions expire every few weeks. The symptom is a 403, which the extension treats as an expired session: the stored cookies are discarded and a Sign In prompt is offered so the tree never keeps claiming you are signed in. Pasting fresh cookie values restores access.
What needs a session
Submitting, running on LeetCode and your per-problem solved status all require sign-in. Browsing the problem list, fetching a problem's stub and everything local, including debugging, work while signed out.
Development
npm install
npm run compile
npm test
Press F5 to launch an Extension Development Host.
Disclaimer
This is an unofficial project with no affiliation to LeetCode. It drives the same
endpoints your browser uses, with your own session, for personal practice. Problem
statements fetched through it remain the property of their owners — do not
redistribute them.
License
MIT