Zuzu.nvim
Neovim build system plugin
Install / Use
/learn @gitpushjoe/Zuzu.nvimREADME
https://github.com/user-attachments/assets/c0d6c5e6-1375-44a3-81f5-7481857f1e4e
🎁 Features
-
🎨 customizable build profiles
- write multiple different build scripts in one profile
- project-wide, file-specific, or even global profiles
- restrict profiles to specific filetypes/depth
- create generalized setup code to apply to all builds
-
🧠 smart profile resolution
- if multiple profiles apply to one file, zuzu will intelligently choose the best one
- allows you to create a "fallback" profile that will apply to every file for a specific language, without setup
-
✔ quickfix integration!
- view runtime errors as diagnostic messages in your source code
- jump between lines of an error traceback quickly
-
💲 hooks! (dynamic environment variables)
- built-in core hooks for things like
$file,$dir,$parent, etc. - create your own core hooks that will be always be initialized in every build
- interactive interface for editing hooks
- create hook choices to easily choose from a list of pre-defined options
- built-in core hooks for things like
-
🖥 versatile display options
- create your own display strategy (command mode, split terminal right, split terminal below, etc.)
- bind keymaps to different display strategies
- you can even run builds in the background!
-
⚡ blazingly fast (<1ms of overhead)
- build scripts are also cached to avoid writing files several times on repeated runs
-
🌐 cross-platform!
- supports Windows, Linux, MacOS, and other UNIX-based systems
Table of Contents
- Installation
- Profiles
- Hooks
- Customizing Builds
- Reflect
- Display Strategies
- API
- Benchmarks
- Highlight Groups
⚒ Installation
✅ Requirements
- neovim 0.10.0+ (but will likely work on older versions)
<details> <summary>init.lua</summary>[!Important] If you are on Windows, you will need to configure Neovim to use Powershell as its shell. Add the following to your
init.lua:
vim.o.shell = 'powershell.exe'
vim.o.shellxquote = ''
vim.o.shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command '
vim.o.shellquote = ''
vim.o.shellpipe = '| Out-File -Encoding UTF8 %s'
vim.o.shellredir = '| Out-File -Encoding UTF8 %s'
</details>
<br/>
zuzu.nvim can be installed with the usual plugin managers:
lazy.nvim
{
"gitpushjoe/zuzu.nvim",
opts = {
--- add options here
}
}
packer.nvim
use {
"gitpushjoe/zuzu.nvim",
config = function ()
require("zuzu").setup({
--- add options here
})
end
}
<br/>
⚙ Configuration
<details> <summary>Default Configuration</summary>require("zuzu").setup({
build_count = 4,
display_strategy_count = 4,
keymaps = {
build = {
{ "zu", "ZU", "zU", "Zu" },
{ "zv", "ZV", "zV", "Zv" },
{ "zs", "ZS", "zS", "Zs" },
{ "zb", "ZB", "zB", "Zb" },
},
reopen = {
"z.",
'z"',
"z:",
},
new_profile = "z+",
new_project_profile = "z/",
edit_profile = "z=",
edit_all_applicable_profiles = "z?",
edit_all_profiles = "z*",
edit_hooks = "zh",
qflist_prev = "z[",
qflist_next = "z]",
stable_toggle_qflist = "z\\",
toggle_qflist = "z|",
},
display_strategies = {
require("zuzu.display_strategies").command,
require("zuzu.display_strategies").split_terminal(
"vertical rightbelow", -- Split modifiers
true -- Use "buffer mode"
),
require("zuzu.display_strategies").split_terminal(
"horizontal rightbelow",
true
),
require("zuzu.display_strategies").background(
--- Delay between each elapsed time update in milliseconds
1000 / 8
),
},
path = {
root = require("zuzu.platform").join_path(
vim.fn.stdpath("data"),
"zuzu"
),
atlas_filename = "atlas.json",
last_stdout_filename = "stdout.txt",
-- Note: last_stderr_filename is not used on Windows
last_stderr_filename = "stderr.txt",
compiler_filename = "compiler.txt",
reflect_filename = "reflect.txt",
},
core_hooks = {
-- Note: these are actually "env:file", "env:dir", etc. on Windows
{ "file", require("zuzu.hooks").file },
{ "dir", require("zuzu.hooks").directory },
{ "parent", require("zuzu.hooks").parent_directory },
{ "base", require("zuzu.hooks").base },
{ "filename", require("zuzu.hooks").filename },
},
colors = {
reopen_stderr = require("zuzu.colors").bright_red,
reflect = require("zuzu.colors").bright_yellow,
},
zuzu_function_name = "zuzu_cmd",
prompt_on_simple_edits = false,
hook_choices_suffix = "__c",
compilers = {
-- https://vi.stackexchange.com/a/44620
{ "python3", '%A %#File "%f"\\, line %l\\, in %o,%Z %#%m' },
{ "lua", "%E%\\\\?lua:%f:%l:%m,%E%f:%l:%m" },
-- https://github.com/felixge/vim-nodejs-errorformat/blob/master/ftplugin/javascript.vim
-- Note: This will also work for bun.
{
"node",
[[%AError: %m,%AEvalError: %m,%ARangeError: %m,%AReferenceError: %m,%ASyntaxError: %m,%ATypeError: %m,%Z%*[\ ]at\ %f:%l:%c,%Z%*[\ ]%m (%f:%l:%c),%*[\ ]%m (%f:%l:%c),%*[\ ]at\ %f:%l:%c,%Z%p^,%A%f:%l,%C%m,%-G%.%#]],
},
{
"bash",
"%E%f: line %l: %m",
},
},
qflist_as_diagnostic = true,
reverse_qflist_diagnostic_order = false,
qflist_diagnostic_error_level = "WARN",
write_on_run = true,
fold_profiles_in_editor = true,
reflect = false,
newline_after_reflect = true,
newline_before_reopen = false,
enter_closes_buffer = true,
reopen_reflect = true,
})
|Key |Explanation |
|-|-|
|build_count|The number of different builds for each profile.
|display_strategy_count|The number of display strategies. The 4 strategies by default are "command-mode" :!source run.sh, split-right-terminal, and split-below-terminal, and background.
|keymaps.build|A 2D list of keymaps. The first row is mapped to the first display strategy, the second row to the second, and so on. The first keymap in each row is mapped to build #1, the second to build #2, and so on. So, for example, pressing "zV" will run the 3rd build in the current profile, with the 2nd build display style (split-right-terminal). Use "" to not bind any keymap.
|keymaps.reopen|Every time zuzu is run, its output is saved to the path.root directory at path.last_output_filename. Pressing keymap.reopen[i] will show the output from the last time zuzu was run, using display strategy #i.
|keymaps.new_profile|Creates a new profile. Sets the root to the current file and sets the depth to 0.
|keymaps.new_project_profile|Creates a new profile. Sets the root to the directory of the current file and sets the depth to -1 (any depth).
|keymaps.edit_profile|Shows the profile for the current file (the most applicable profile).
|keymaps.edit_all_applicable_profiles|Shows all applicable profiles for the current file, in order from least applicable to most.
|keymaps.edit_all_profiles|Shows all profiles.
|keymaps.edit_hooks|Opens an interactive menu for updating a hook.
|keymaps.qflist_prev|Opens the quickfix list if it's closed, and jumps to the previous error (see :cprevious).
|keymaps.qflist_next|Opens the quickfix list if it's closed, and jumps to the nextious error (see :cnext).
|keymaps.stable_toggle_qflist|Toggles the state of the quickfix list, keeping the cursor in the current window.
|keymaps.toggle_qflist|Toggles the state of the quickfix list, putting the cursor in the quickfix list. Also toggles whether quickfix diagnostics are shown/hidden.
|display_strategies|List of display strategies.
|path.root|The root directory zuzu will use to save any files its creates.
|path.atlas_filename|The filename for the atlas saved to path.root.
|path.last_stdout_filename|The filename to save the stdout to from the last time zuzu was run.
|path.last_stderr_filename|The filename to save the stderr to from the last time zuzu was run.
|path.compiler_filename|The filename to save the compiler name to from the last time zuzu was run.
|path.reflect_filename|The filename to save the source code of the build being run to. See Reflect.
|core_hooks|A list of tuples. The first item in each tuple is the name of the hook, and the second item is a callback to get the value of the hook. For example, by default, the hooks $file and $dir will be automatically initialized to the current file and directory, respectively, before every build.
|zuzu_function_name|To run a build, zuzu generates a shell file (.sh on UNIX-based, .ps1 on windows) and puts the build script in a function. This is the name of the function.
|colors.reopen_stderr|The color to display errors in when reopening the output from the last run. Cross-pl
Related Skills
node-connect
354.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
112.2kCreate 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
354.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
354.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
