lightweight neovim code runner plugin that works with Snacks.nvim terminal
- Neovim (>= 0.7)
- Snacks.nvim (>= 2.11.0)
- better Terminal
- which-key (>= 3.15.0)
- custom leader key menu group name
- These both come default with lazy.nvim
With lazy.nvim
{
"dchae/canter.nvim",
opts = {}
},
Install normally, and add this line to your init.lua
:
require("canter.nvim").setup()
Pass your config table into the setup()
function or opts
if you use lazy.nvim.
opts = {
debug = false,
-- File extension to runner/interpreter mapping
runners = {},
-- Terminal configuration
terminal = {
type = "snacks", -- "snacks" or "builtin"
-- Options for built-in terminal
builtin_opts = {
position = "vsplit", -- "vsplit", "split", or "float"
escape_keymap = true, -- escape terminal mode with <Esc>
},
-- Options for Snacks.nvim terminal
snacks_opts = {
win = {
position = "bottom",
relative = "editor",
},
interactive = false,
},
},
-- Default keymaps (can be overridden)
keymaps = {
["<leader><cr><cr>"] = {
cmd = ":CanterRun<CR>",
desc = "Run current file (Auto)",
},
["<leader><cr>w"] = {
cmd = ":CanterWait<CR>",
desc = "Run current file (Wait)",
},
},
}
NOTE - does not come with runners by default, you must add your own.
runners
: table([file_extension] = runner/interpreter)
terminal
: table of options passed to terminaltype
: type of terminalbuiltin_opts
: options for built-in terminalsnacks_opts
: options for Snacks.nvim terminal
keymaps
: table of keybindings and their descriptions
opts = {
runners = {
["js"] = "node",
["rb"] = "ruby",
["py"] = "python"
},
}
"Run current file (Auto)"
- if file contains a shebang on the first line, the plugin will attempt to:
- make the file executable via
chmod
- execute the current file
- make the file executable via
- else, if the file has a corresponding runner
- execute the current file via its runner in
Snacks.terminal
- execute the current file via its runner in
"Run current file (Wait)"
- same as above, but stops before actually executing so you can add flags or confirm the command before pressing enter.
- necessarily, the terminal is interactive by default in this mode.
When using the built-in terminal in wait mode:
- Press
<Esc>
to exit terminal mode and return to normal mode (ifescape_keymap
is enabled) - Alternatively, use the default Neovim terminal escape sequence:
<C-\><C-n>
test.js
#!/usr/bin/env node
console.log("Hello, world!");
// "Hello, world!"
All keybinds can be customized in the config. The defaults are:
<Leader><CR><CR>
: Run current file (Auto)- executes current file in terminal
- default behaviour is non-interactive; file will run and then any key will dismiss terminal
<Leader><CR>w
: Run current file (Wait)- loads current file run command in terminal
- default behaviour is interactive
To customize keybinds, modify the keymaps
table in your config:
opts = {
keymaps = {
-- Override default run binding
["<leader>r"] = {
cmd = ":CanterRun<CR>",
desc = "Run current file"
},
-- Add new binding
["<leader>rw"] = {
cmd = ":CanterWait<CR>",
desc = "Run and wait"
}
}
}
- should work with native terminal when Snacks is not available
- option to autosave before running
- refactor terminal code to a separate module
- automatically scan and resolve runners for a given file extension
- prompt to set or confirm runner when new filetype is encountered
- native support for runner flags
- better compiled language support
- should be able to compile, show build result, and run with one command
- native command to toggle or undo chmod make executable
- this plugin grew out of the custom keymap script I was using, which was in turn inspired by u/linkarzu script on r/neovim