| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
When I was still in college it was common to try multiple programming languages, at that time I used vscode that with a single plugin allowed me to run many programming languages, I left the ballast that are electron apps and switched to neovim, I searched the Internet and finally i found a lot of plugins, but none of them i liked (maybe i didn't search well), so i started adding autocmds like i don't have a tomorrow, this worked fine but this is lazy (maybe it will work for you, if you only program in one or three languages maximum). So I decided to make this plugin and since the migration of my commands was very fast, it was just copy and paste and everything worked. Currently I don't test many languages anymore and work in the professional environment, but this plugin is still my swiss army knife.
vim.pack.add("https://github.com/CRAG666/code_runner.nvim")require("lazy").setup({
{ "CRAG666/code_runner.nvim", config = true },
}Tip (blazing fast startup): load the plugin on demand so it costs nothing until you actually run code. The plugin already defers its internal modules and JSON config, but lazy-loading on the commands/keys you use is the biggest win:
{
"CRAG666/code_runner.nvim",
cmd = { "RunCode", "RunFile", "RunProject", "RunClose", "CRFiletype", "CRProjects" },
-- keys = { "<leader>r" }, -- add the mappings you use
opts = {
-- your config (mode, filetype, ...) goes here
},
}use 'CRAG666/code_runner.nvim'require "paq"{ 'CRAG666/code_runner.nvim'; }Please see my config run_code.lua
Note If you want implement a new feature open an issue to know if it is worth implementing it and if there are people interested.
This plugin can be configured either in lua, with the setup function, or with json files for interopability between this plugin and the original code runner vscode plugin.
require('code_runner').setup({
filetype = {
java = {
"cd $dir &&",
"javac $fileName &&",
"java $fileNameWithoutExt"
},
python = "python3 -u",
typescript = "deno run",
rust = {
"cd $dir &&",
"rustc $fileName &&",
"$dir/$fileNameWithoutExt"
},
c = "cd $dir && gcc $fileName -o /tmp/$fileNameWithoutExt && /tmp/$fileNameWithoutExt",
},
})Warning A common mistake is using relative paths instead of absolute paths in . Use absolute paths in configurations or else the plugin won't work, in case you like to use short or relative paths you can use something like this vim.fn.expand('~/.config/nvim/project_manager.json')
Note If you want to change where the code is displayed, you need to specify the mode attribute in the setup function
-- this is a config example
require('code_runner').setup {
filetype_path = vim.fn.expand('~/.config/nvim/code_runner.json'),
project_path = vim.fn.expand('~/.config/nvim/project_manager.json')
}Note To check what modes are supported see mode parameter.
All run commands allow restart. So, for example, if you use a command that does not have hot reload, you can call a command again and it will close the previous one and start again.
Recommended mappings:
vim.keymap.set('n', '<leader>rr', ':RunCode<CR>', { noremap = true, silent = false })
vim.keymap.set('n', '<leader>rf', ':RunFile<CR>', { noremap = true, silent = false })
vim.keymap.set('n', '<leader>rft', ':RunFile tab<CR>', { noremap = true, silent = false })
vim.keymap.set('n', '<leader>rp', ':RunProject<CR>', { noremap = true, silent = false })
vim.keymap.set('n', '<leader>rc', ':RunClose<CR>', { noremap = true, silent = false })
vim.keymap.set('n', '<leader>crf', ':CRFiletype<CR>', { noremap = true, silent = false })
vim.keymap.set('n', '<leader>crp', ':CRProjects<CR>', { noremap = true, silent = false })lua functions:
require("code_runner").run_code() -- Runs based on file type, first checking if belongs to project, then if filetype mapping exists.
require("code_runner").run_from_fn() -- Run any command.
require("code_runner").run_filetype() -- Run the current file (optionally you can select an opening mode).
require("code_runner").run_project() -- Run the current project(If you are in a project otherwise you will not do anything,).
require("code_runner").run_close() -- Close runner(Doesn't work in better_term mode, use native plugin options).
require("code_runner").get_filetype_command() -- Get the current command for this filetype
require("code_runner").get_project_command() -- Get the current command for this projectThese are the configuration options you can pass to the setup function. To see the default values see: code_runner.nvim/lua/code_runner/options.
Parameters:
mode: Mode in which you want to run. Are supported: "better_term", "float", "tab", "toggleterm", "vimux", "snacks", "quickfix" (type: string)
focus: Focus on runner window. Only works on term and tab mode (type: bool)
startinsert: init in insert mode.Only works on term and tab mode (type: bool)
term: Configurations for the integrated terminal
float: Configurations for the float window
better_term: Toggle mode replacement(Install CRAG666/betterTerm.nvim)
before_run_filetype: Execute before executing a file (type: func)
filetype: If you prefer to use lua instead of json files, you can add your settings by file type here (type: table)
filetype_path: Absolute path to json file config (type: absolute paths)
project: If you prefer to use lua instead of json files, you can add your settings by project here (type: table)
project_path: Absolute path to json file config (type: absolute paths)
root_markers: Ordered list of { file, command } pairs used to auto-detect a project root when no configured project matches (type: table). See Project auto-detection.
hot_reload: Use only if not configured any hooks (type: bool), experimental feature. Its better create autocommands for the filetypes you want to hot reload.
Note The commands are run in a shell. This means that you can't run neovim commands with this.
The filetype table can take either a string, a table or a function.
-- in setup function
filetype = {
java = { "cd $dir &&", "javac $fileName &&", "java $fileNameWithoutExt" },
python = "python3 -u",
typescript = "deno run",
rust = { "cd $dir &&",
"rustc $fileName &&",
"$dir/$fileNameWithoutExt"
},
cs = function(...)
local root_dir = require("lspconfig").util.root_pattern "*.csproj"(vim.loop.cwd())
return "cd " .. root_dir .. " && dotnet run$end"
end,
},If you want to add some other language or some other command follow this structure key = commands.
Note In Json you can only pass the commands as a string
The equivalent for your json filetype file is:
{
"java": "cd $dir && javac $fileName && java $fileNameWithoutExt",
"python": "python3 -u",
"typescript": "deno run",
"rust": "cd $dir && rustc $fileName && $dir/$fileNameWithoutExt"
}Note If you don't want to use the plugin specific variables you can use vim filename-modifiers.
This uses some special keyword to that means different things. This is do mainly for be compatible with the original vscode plugin.
The available variables are the following:
If you want to add some other language or some other command follow this structure key: commands.
For compiled languages or programs that accept runtime arguments, you can prompt users interactively using function-based filetype configurations. This is particularly useful when testing programs with different inputs.
Use vim.ui.input() within a function to prompt for arguments before running:
require('code_runner').setup({
filetype = {
c = function()
vim.ui.input({ prompt = "Arguments (leave empty for none): " }, function(input)
if not input then return end
local cmd = "cd $dir && gcc $fileName -o /tmp/$fileNameWithoutExt && /tmp/$fileNameWithoutExt"
if input ~= "" then
cmd = cmd .. " " .. input
end
require("code_runner.commands").run_from_fn(cmd)
end)
end,
},
})Note: Arguments with spaces should be quoted in your input, e.g., hello world --flag="with space" will correctly parse as separate arguments with the space preserved in the quoted value.
To avoid repetition across multiple languages, extract the pattern into a helper function:
-- Define helper function before setup
local function prompt_args_runner(base_cmd)
return function()
vim.ui.input({ prompt = "Arguments (leave empty for none): " }, function(input)
if not input then return end
local cmd = base_cmd
if input ~= "" then
cmd = cmd .. " " .. input
end
require("code_runner.commands").run_from_fn(cmd)
end)
end
end
-- Use in setup
require('code_runner').setup({
filetype = {
c = prompt_args_runner("cd $dir && gcc $fileName -o /tmp/$fileNameWithoutExt && /tmp/$fileNameWithoutExt"),
cpp = prompt_args_runner("cd $dir && g++ $fileName -o /tmp/$fileNameWithoutExt && /tmp/$fileNameWithoutExt"),
java = prompt_args_runner("cd $dir && javac $fileName && java $fileNameWithoutExt"),
python = prompt_args_runner("python3 -u $file"),
rust = prompt_args_runner("cd $dir && rustc $fileName && $dir/$fileNameWithoutExt"),
},
})Given a C program that prints its arguments:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("argc = %d\n", argc);
for (int i = 0; i < argc; i++) {
printf("argv[%d] = '%s'\n", i, argv[i]);
}
return 0;
}When you run :RunFile, you'll be prompted for arguments. Example inputs and their results:
| Input | Result |
|---|---|
| hello world | 3 arguments: program, hello, world |
| --flag="with space" | 2 arguments: program, --flag=with space |
| "first arg" "second arg" | 3 arguments: program, first arg, second arg |
| (empty) | 1 argument: program (no prompt needed) |
This pattern works with all modes (toggleterm, float, tab, etc.) and leverages the plugin's variable replacement system.
There are 3 main ways to configure the execution of a project (found in the example.)
The key for each project is a pattern to match against the current filename of the buffer. The pattern is a lua patterns and needs to escape magic characters like -, ., (, etc. with a %. To match the entire path to a directory you cannot simply append /. This is due to vim.fs.normalize being used. Append /.- instead to prevent stripping of /.
Also see project parameters to correctly set your project commands.
project = {
["~/python/intel_2021_1"] = {
name = "Intel Course 2021",
description = "Simple python project",
file_name = "POO/main.py"
},
["~/deno/example"] = {
name = "ExapleDeno",
description = "Project with deno using other command",
file_name = "http/main.ts",
command = "deno run --allow-net"
},
["~/cpp/example"] = {
name = "ExapleCpp",
description = "Project with make file",
command = "make build && cd build/ && ./compiled_file"
},
["~/private/.*terraform%-prod.-/.-"] = {
name = "ExampleTerraform",
description = "All Folders in ~/private containing \"terraform-prod\"",
command = "terraform plan",
},
},{
"~/python/intel_2021_1": {
"name": "Intel Course 2021",
"description": "Simple python project",
"file_name": "POO/main.py"
},
"~/deno/example": {
"name": "ExapleDeno",
"description": "Project with deno using other command",
"file_name": "http/main.ts",
"command": "deno run --allow-net"
},
"~/cpp/example": {
"name": "ExapleCpp",
"description": "Project with make file",
"command": "make build && cd build/ && ./compiled_file"
},
"~/private/.*terrafrom%-prod.-/.-": {
"name": "ExampleTerraform",
"description": "All Folders in ~/private containing \"terraform-prod\"",
"command": "terraform plan"
}
}Warning Avoid using all the parameters at the same time. The correct way to use them is shown in the example and described above.
Note Don't forget to name your projects because if you don't do so code runner will fail as it uses the name for the buffer name
If the current file does not belong to any configured project, code runner searches upward from the file's directory for known root files and runs the associated command from that root. No configuration needed: open any file inside a Maven project (a pom.xml in the root) and :RunCode / :RunProject will run maven, without opening pom.xml first.
Priority: configured project entries > .crproject.json in the project root > root_markers (nearest ancestor first).
The defaults:
root_markers = {
{ "pom.xml", "mvn compile exec:java" },
{ "build.gradle", "./gradlew run" },
{ "Cargo.toml", "cargo run" },
{ "go.mod", "go run ." },
{ "package.json", "npm start" },
{ "Makefile", "make" },
{ "CMakeLists.txt", "cmake -B build && cmake --build build" },
}Override the list in setup() to change commands or add markers; set root_markers = {} to disable detection.
Drop a .crproject.json in your project root to define how that project is compiled/run, keeping the config with the project instead of in your Neovim setup. It accepts the same parameters as a project entry:
{
"name": "MyApp",
"command": "mvn clean package && java -jar target/app.jar",
"mode": "float"
}command is required; name, file_name, mode and watch are optional. This file always wins over root_markers.
With "watch": true the command is re-run on every write under the project root — useful for tools without a native watch mode (gcc, pandoc, ...):
{
"name": "Poster",
"command": "typst compile poster.typ",
"watch": true
}Run the project once to start watching; run it again to stop. watch also works in regular project entries.
These elements are intended to help with those commands that require more complexity. For example, implement hot reload on markup documents, quarto files, and latex using tectonic.
{
...
filetype = {
-- Using tectonic compiler
tex = function(...)
local tectonic = require('code_runner.hooks.tectonic')
require('code_runner.hooks.ui').select({
Project = function()
tectonic.build()
end,
['Project + logs'] = function()
tectonic.build('--synctex --keep-logs')
end,
Single = function()
tectonic.single('--synctex --keep-logs -Zsearch-path=/latex')
end,
})
end,
-- Enable hot reload for Quarto and open preview
quarto = function(...)
local quarto = require("code_runner.hooks.utils").create_job_runner({ label = "Quarto", stop_command = "QuartoStop" })
local root = vim.fn.expand("%:p")
quarto.start(("quarto preview %s --no-browser --port 4444"):format(root))
vim.defer_fn(function()
vim.fn.jobstart({ "xdg-open" , "http://localhost:4444" }, { detach = true })
end, 10000)
end,
markdown = function(...)
local hr_preview_pdf = require('code_runner.hooks.preview_pdf')
require('code_runner.hooks.ui').select({
Latex = function()
hr_preview_pdf.run({
command = 'pandoc',
args = { '$fileName', '-o', '$tmpFile', '-t pdf' },
preview_cmd = preview_cmd,
})
end,
Beamer = function()
hr_preview_pdf.run({
command = 'pandoc',
args = { '$fileName', '-o', '$tmpFile', '-t beamer' },
preview_cmd = preview_cmd,
})
end,
Eisvogel = function()
hr_preview_pdf.run({
command = 'bash',
args = { './build.sh' },
preview_cmd = preview_cmd,
overwrite_output = '.',
})
end,
})
end,
...
}
This module allows us to send a command to compile to pdf as well as show the result every time we save the original document.
In the above example we use the hook to compile markdown and latex files to pdf. Not only that, but we also indicate in what order the resulting pdf file will be opened. In my case it is zathura but you can use a browser if it is more comfortable for you.
It is important that you take into account that each time you save the original file, the pdf file will be generated.
These are variables used to be substituted for values according to each filename.
This example showcases how to write a hook to run ts file, print the result in a new vertical windows and reload on save. Read the comments for more info.
-- custom function to run ts file
-- and print result in a new vertical windows
local function runTsFile(fileName)
-- Check if the current file is a TypeScript file
if string.match(fileName, '%.ts$') then
-- Save the current window id
local current_win = vim.fn.win_getid()
-- Close previous terminal windows
vim.cmd 'silent! wincmd w | if &buftype ==# "terminal" | q | endif'
-- Open a vertical terminal
vim.cmd 'vsplit term://'
-- Run the TypeScript file and print the result
vim.fn.termopen('ts-node ' .. fileName)
-- Restore the focus to the original window
vim.fn.win_gotoid(current_win)
else
print 'Not a TypeScript file!'
end
end
-- hooks config
{
filetype = {
typescript = function()
local cr_au = require "code_runner.hooks.autocmd"
-- stop previous job (if has any)
cr_au.stop_job() -- CodeRunnerJobPosWrite
local fileName = vim.fn.expand '%:p'
local fn = function()
runTsFile(fileName)
end
-- run the command the first time
fn()
-- listen to bufwrite event after the first run time
cr_au.create_au_write(fn)
end,
},
}These functions could be useful if you intend to create plugins around code_runner, currently only the file type and current project commands can be accessed respectively
require("code_runner").get_filetype_command() -- get the current command for this filetype
require("code_runner").get_project_command() -- get the current command for this projectYou can directly integrate this plugin with ThePrimeagen/harpoon the way to do it is through command queries, harpoon allows the command to be sent to a terminal, below it is shown how to use harpoon term together with code_runner.nvim:
require("harpoon.term").sendCommand(1, require("code_runner.commands").get_filetype_command() .. "\n")Note If you have any ideas to improve this project, do not hesitate to make a request, if problems arise, try to solve them and publish them. Don't be so picky I did this in one afternoon
Your help is needed to make this plugin the best of its kind, be free to contribute, criticize (don't be soft) or contribute ideas. All PRs are welcome.
| Back | FazBrowse Home | New Git URL |