π A universal, intelligent code runner for Neovim
Automatically detects file types and executes code with the appropriate command.
Perfect for competitive programming, learning, and quick prototyping!
- Multi-language support: C, C++, Python, JavaScript, TypeScript, Go, Rust, Java, Lua, Ruby, Perl, PHP, Shell scripts, R, Julia, Haskell, Swift, Kotlin, Dart, Elixir, Nim, Zig, OCaml, Scala, D, and more!
- Smart detection: Automatically determines the correct runner based on file type
- Compiled languages: Built-in compilation support with optimization profiles
- Interpreted languages: Direct execution support
- Intelligent terminal management: Clean terminal handling - closes previous terminal before creating new one (no stacking!)
- Binary existence check: Prompts to build if binary is missing before running
- Detailed error reporting: Captures and displays compiler stdout/stderr for better debugging
- Flexible terminals: Run in bottom split or floating terminal
- Test runner: Run multiple test cases from a
tests/directory - Input/Output handling: Support for
input.txtandoutput.txtredirection - Optimization profiles: Cycle through different compiler optimization flags (Debug, O2, Ofast)
- Execution timing: Automatically tracks and displays execution time
- Watch mode: Auto-run code on file save
- Run history: Keep track of recent executions with timestamps
- Clean builds: Easy cleanup of build artifacts, optional auto-cleanup after run
- Highly configurable: Easy to add new languages or customize existing ones
Using lazy.nvim
{
'samonide/runner.nvim',
config = function()
require('runner').setup({
-- Your custom configuration here (optional)
})
end,
keys = {
{ '<leader>cr', '<cmd>RunCode<cr>', desc = 'Run code' },
{ '<leader>cb', '<cmd>RunBuild<cr>', desc = 'Build only' },
{ '<leader>ce', '<cmd>RunLast<cr>', desc = 'Run last build' },
{ '<leader>ci', '<cmd>RunWithInput<cr>', desc = 'Run with input.txt' },
{ '<leader>ct', '<cmd>RunFloat<cr>', desc = 'Run in floating terminal' },
{ '<leader>ctt', '<cmd>RunTests<cr>', desc = 'Run all tests' },
{ '<leader>co', '<cmd>RunProfile<cr>', desc = 'Cycle optimization profile' },
{ '<leader>cw', '<cmd>RunWatch<cr>', desc = 'Toggle watch mode' },
{ '<leader>ch', '<cmd>RunHistory<cr>', desc = 'Show run history' },
{ '<leader>cc', '<cmd>RunClean<cr>', desc = 'Clean build directory' },
{ '<C-A-n>', '<cmd>RunIOFiles<cr>', desc = 'Run with input.txt -> output.txt' },
},
}Using packer.nvim
use {
'samonide/runner.nvim',
config = function()
require('runner').setup()
end
}Using vim-plug
Plug 'samonide/runner.nvim'
lua << EOF
require('runner').setup()
EOF| Command | Description |
|---|---|
:RunCode |
Compile (if needed) and run the current file. Checks for binary existence and prompts to build if missing |
:RunFile |
Alias for :RunCode |
:RunBuild |
Build/compile only (no execution) |
:RunLast |
Run the last compiled executable (without recompiling) |
:RunWithInput |
Run with input.txt as stdin |
:RunFloat |
Run in a floating terminal window |
:RunTests |
Run all test cases from tests/ directory with pass/fail reporting |
:RunIOFiles |
Run with input.txt -> output.txt redirection |
:RunProfile |
Cycle through optimization profiles (Debug β O2 β Ofast) |
:RunWatch |
Toggle watch mode (auto-run on save) |
:RunHistory |
Show execution history with timings and timestamps |
:RunClean |
Clean build directory (removes all compiled binaries) |
<leader>cr -- Run code
<leader>cb -- Build only
<leader>ce -- Execute last build
<leader>ci -- Run with input.txt
<leader>ct -- Run in floating terminal
<leader>ctt -- Run all tests
<leader>co -- Cycle optimization profile
<leader>cw -- Toggle watch mode
<leader>ch -- Show run history
<leader>cc -- Clean build directory
<C-A-n> -- Run with input.txt -> output.txt- Install the plugin using your plugin manager (see above)
- Open any file (e.g.,
main.cpp,script.py,app.js) - Press
<leader>cror run:RunCode - Watch your code execute in a terminal split!
# Competitive Programming
1. Create solution.cpp
2. Create tests/1.in and tests/1.out
3. Press <leader>cr to run
4. Press <leader>ctt to test all cases
5. Press <leader>co to optimize
```ader>ctt -- Run all tests
<leader>co -- Cycle optimization profile
<C-A-n> -- Run with input.txt -> output.txtrequire('runner').setup({
-- Build directory for compiled languages
build_dir = '.build',
-- Test directory
test_dir = 'tests',
-- Input/output files
input_file = 'input.txt',
output_file = 'output.txt',
-- Show execution time after running
show_time = true,
-- Clean build artifacts after successful run (removes binary after execution)
-- Useful for competitive programming to avoid outdated binaries
clean_after_run = false,
-- Terminal configuration
terminal = {
split_height = 15,
position = 'botright',
},
-- Runners are auto-configured for many languages
-- See below for customization
})You can add or override language configurations:
require('runner').setup({
runners = {
-- Add a new language
fortran = {
type = 'compiled',
compiler = 'gfortran',
profiles = {
{ name = 'Debug', flags = '-g -Wall' },
{ name = 'Release', flags = '-O3' },
},
},
-- Override Python to use a specific version
python = {
type = 'interpreted',
command = 'python3.11 $FILE',
},
-- Override C++ profiles
cpp = {
type = 'compiled',
compiler = 'g++',
profiles = {
{ name = 'Debug', flags = '-std=c++20 -g -Wall' },
{ name = 'Contest', flags = '-std=c++20 -O2 -DLOCAL' },
{ name = 'Release', flags = '-std=c++20 -O3 -march=native' },
},
},
},
}){
type = 'interpreted',
command = 'python3 $FILE', -- $FILE is replaced with the file path
}{
type = 'compiled',
compiler = 'g++',
profiles = {
{
name = 'Profile Name',
flags = '-O2 -Wall',
},
},
}Some languages have special handling:
- Java: Uses
javacto compile andjavato run - Go: Can use
go runto compile and run in one step - Nim: Can use
nim c -rto compile and run in one step - Zig: Can use
zig runto compile and run in one step
Create a tests/ directory with test cases:
tests/
1.in # Input for test 1
1.out # Expected output for test 1
2.in # Input for test 2
2.out # Expected output for test 2
...
Run :RunTests to execute all tests and see which ones pass/fail.
- C, C++
- Rust
- Go
- Java
- Haskell
- Kotlin
- D
- Nim
- Zig
- Python
- JavaScript (Node.js)
- TypeScript (ts-node)
- Lua
- Ruby
- Perl
- PHP
- Shell scripts (bash, zsh, sh)
- R
- Julia
- Swift
- Dart
- Elixir
- OCaml
- Scala
- Write your C++ solution:
solution.cpp - Create test cases:
tests/1.in,tests/1.out, etc. - Press
<leader>crto compile and run- If binary doesn't exist, you'll be prompted to build first
- Press
<leader>cttto run all tests with pass/fail reporting - Press
<leader>coto cycle optimization profiles (Debug β O2 β Ofast) - Press
<leader>cito test withinput.txt - Press
<leader>ceto quickly run last build without recompiling
When build fails, you now get detailed compiler output:
Build failed (exit code 1):
main.cpp:5:10: error: expected ';' after expression
return 0
^
;
" Option 1: Manual cleanup
:RunClean " Removes all binaries from .build/
" Option 2: Auto cleanup after each run (in your config)
require('runner').setup({
clean_after_run = true, " Automatically removes binary after execution
}):RunWatch " Enable watch mode
" Now every time you save, code runs automatically!
:RunWatch " Toggle off when doneThe plugin intelligently manages terminals:
- Pressing
<leader>cimultiple times closes the previous terminal before opening a new one - No more terminal stacking issues!
- Clean, predictable behavior
:RunHistory " See your last 10 runs with execution times and timestampsOutput example:
π Run History (Last 10):
βββββββββββββββββββββββββββ
1. [14:23:45] solution.cpp (cpp) - 0.234s
2. [14:22:10] test.py (python) - 1.456s
3. [14:20:05] app.js (javascript) - 0.089s
For interpreted languages (Python, JavaScript, etc.), just press <leader>cr to run immediately with execution time tracking.
require('runner').setup({
runners = {
-- Add a new language
fortran = {
type = 'compiled',
compiler = 'gfortran',
profiles = {
{ name = 'Debug', flags = '-g -Wall' },
{ name = 'Release', flags = '-O3' },
},
},
-- Override existing
python = {
type = 'interpreted',
command = 'python3.11 $FILE',
},
},
-- Customize settings
show_time = true, -- Show execution time
clean_after_run = false, -- Auto-cleanup binaries after run
build_dir = '.build',
})require('runner').setup({
show_time = true, -- Always show execution time
clean_after_run = false, -- Keep binaries for quick re-runs with <leader>ce
runners = {
cpp = {
type = 'compiled',
compiler = 'g++',
profiles = {
{ name = 'Debug', flags = '-std=c++17 -g -Wall -Wextra -Wshadow -fsanitize=address,undefined' },
{ name = 'Contest', flags = '-std=c++17 -O2 -DLOCAL' },
{ name = 'Ofast', flags = '-std=c++17 -Ofast -march=native' },
},
},
},
})Create .nvim.lua in your project root:
local runner = require('runner')
runner.config.current_profile['cpp'] = 2 -- Start with O2
runner.config.build_dir = 'build'Contributions welcome! To add a new language:
- Fork the repo
- Edit
lua/runner/config.luaand add your language configuration - Test it thoroughly
- Submit a PR
For bugs or feature requests, please open an issue on GitHub.
This project utilized AI assistance for README documentation and code refactorization to improve code quality and maintainability.
MIT License - see LICENSE for details
Created by @samonide - Built with β€οΈ for developers who value speed and simplicity!
Extracted and enhanced from a competitive programming Neovim setup.