Note: - When `make.enabled = false`, Make-related commands/keymaps are not created. - When `cmake.enabled = false`, CMake-related commands/keymaps are not created. - When `telescope_enhance = false`, Quickfix prefers native lists; Telescope-based pickers are not exposed.
-
To use cmake-tools as your primary CMake UI, disable Quick-c CMake/Telescope layers:
cmake.enabled = falsetelescope_enhance = false(optional: keep Quickfix native and avoid Telescope pickers)
-
To use overseer as the task runner while keeping Quick-c single-file build/run:
make.enabled = false(use overseer tasks for Make)- Keep Quick-c core: build/run/debug for single or multi-file still work.
-
Keymaps respect these toggles; existing mappings won't be injected when the feature is disabled.
中文 | English
All‑in‑one C/C++ workflow for Neovim: one‑key Build/Run/Debug (async, non‑blocking), first‑class Windows/Linux/macOS support, Make/CMake target pickers, and enhanced Quickfix/Telescope integration.
- ⚡️ Zero-setup Build/Run/Debug for single or multiple sources; remembers output names.
- 🧰 Make & CMake pickers with previews and jump-to-definition for targets.
- 🪟 Windows-friendly: PowerShell quoting, MSVC
clsupport, and robust path handling. - 🔭 Telescope-first UX: enhanced Quickfix preview with message and source context.
- 🧠 Async, non-blocking: never freezes Neovim; smart caches invalidate on file changes.
Install (lazy.nvim):
{
"AuroBreeze/quick-c",
ft = { "c", "cpp" },
config = function()
require("quick-c").setup()
end,
}Use:
<leader>cqb→ build current file<leader>cqr→ run last build<leader>cqR→ build & run<leader>cqD→ debug (codelldb + nvim-dap)<leader>cqS→ Telescope source picker (multi-select)
Optional: commands
:QuickCBuild·:QuickCRun·:QuickCBR·:QuickCDebug
| Capability | Quick-c | compiler.nvim | cmake-tools.nvim | overseer.nvim |
|---|---|---|---|---|
| Scope | C/C++ build/run/debug with Make/CMake helpers | Multi-language compile/run helpers | CMake project integration for C/C++ | General task runner/executor |
| Single-file Build/Run | Built-in, async, remembers output name | Built-in (multi-language) | Not focused on single-file | Via tasks (manual config) |
| Multi-file Build | Built-in (select sources or CLI) | Limited by language config | Handled by CMake project | Via tasks (manual) |
| Make Targets Picker | Built-in Telescope picker + preview + jump-to-definition | Not primary focus | Not primary focus | Possible via custom tasks |
| CMake Targets/Build | Built-in target picker, configure (-S/-B), view both/quickfix/terminal | — | Primary feature set | Possible (requires tasks) |
| Quickfix Enhancements | Enhanced Telescope quickfix with message + code context | Varies by compiler output | Uses CMake output; quickfix not the focus | Depends on task output parsing |
| Windows Details | PowerShell quoting, MSVC cl path, robust path handling |
Varies by setup | Supports CMake/VS env; single-file run not core | Depends on user-defined commands |
| One-plugin Workflow | Single entry for single-file/Make/CMake/debug | Single-file oriented | Project (CMake) oriented | Meta-runner; pairs with build plugins |
- 🚀 Build/Run (async):
QuickCBuild,QuickCRun,QuickCBR(build & run) - 🐞 Debug integration:
QuickCDebugvianvim-dapandcodelldb - 🌐 Cross-platform: auto select compiler (gcc/clang/cl) and runtime (PowerShell/terminal)
- 📁 Flexible output dir: default to source folder; configurable
- 🔧 Make integration: auto discover Makefiles, list targets, .PHONY prioritization, argument input with remember
- 🏗️ CMake integration: search CMakeLists,
cmake -S/-Bconfigure,cmake --buildwith target list (--target help)- View modes:
both(stream output + quickfix),quickfix,terminal - Output panel:
cmake.output.{open,height}
- View modes:
- 🔭 Telescope enhancements: built-in Makefile preview, source multi-select, quick toggle .PHONY
- 🧪 Enhanced Quickfix preview: when opening
cqf, show detailed error and source context on the right - 🧠 Smart cache invalidation: watch
Makefile/CMakeLists.txtchanges and invalidate related caches immediately (not only TTL-based), reducing unnecessary re-parsing. - 🔎 Make/CMake preview upgrades: target picker preview jumps to the selected target's definition (deferred + fallback search) and enables soft wrapping (wrap/linebreak/breakindent) for readability.
- Build:
:QuickCBuildor<leader>cqb - Run:
:QuickCRunor<leader>cqr - Build & Run:
:QuickCBRor<leader>cqR - Debug:
:QuickCDebugor<leader>cqD - When the default executable is missing,
QuickCDebugwill search for alternatives in preferred directories (e.g.,./build/bin,./out) and prompt a picker.
Multi-file:
- C:
:QuickCBuild main.c util.c - C++:
:QuickCBR src/main.cpp src/foo.cpp - Or press
<leader>cqSto open Telescope source picker- Tab multi-select (Shift+Tab backward, Ctrl+Space toggle)
- Enter to choose Build / Run / Build & Run
Note: the list shows paths relative to cwd; absolute paths are used internally.
Output name prompt & cache:
- Multi-file: always prompt; default is the last name used for the same source set
- Single-file: default to current filename (Windows adds .exe)
If the current buffer is unnamed and modified, auto-jump from diagnostics is skipped to avoid save prompts.
- gcc/g++
- clang/clang++
- MSVC cl
- Neovim 0.8+
- Telescope (optional, recommended)
- nvim-dap + codelldb (for debugging)
| Category | Command | Description | Default Keymap |
|---|---|---|---|
| Build/Run/Debug | QuickCBuild |
Build current/selected sources | <leader>cqb |
QuickCRun |
Run the last built executable | <leader>cqr |
|
QuickCBR |
Build & Run | <leader>cqR |
|
QuickCDebug |
Debug with codelldb (last built program) | <leader>cqD |
|
| Make | QuickCMake |
Choose directory and targets to run | <leader>cqM |
QuickCMakeRun [target] |
Run a specific target directly | — | |
QuickCMakeCmd |
Prompt a full make command and send to terminal | — | |
| CMake | QuickCCMake |
Open CMake target picker | <leader>cqC |
QuickCCMakeRun [target] |
Build default or specified target | <leader>cqB |
|
QuickCCMakeConfigure |
Run cmake configure (-S/-B) | <leader>cqc |
|
| Sources | — | Telescope source picker | <leader>cqS |
| Diagnostics | QuickCQuickfix |
Open quickfix (prefer Telescope) | <leader>cqf |
| Tasks | QuickCStop |
Cancel the current internal build task | <leader>cqx |
QuickCRetry |
Retry the last internal build task | <leader>cqt |
|
| Config | QuickCCompileDB |
Apply compile_commands.json (generate into source dir) | — |
QuickCCompileDBGen |
Generate compile_commands.json | — | |
QuickCCompileDBUse |
Use external compile_commands.json | — | |
| Compile DB | QuickCCompileDB |
Run by compile_commands.mode (generate/use/cmake) | — |
QuickCCompileDBGenProject |
Scan :pwd and generate for the whole project | — | |
QuickCCompileDBGenDir [dir] |
Generate for a specific directory | — | |
QuickCCompileDBGenSources |
Generate from multi-selected sources (Telescope) | — | |
QuickCCompileDBGenCMake |
Export via CMake and copy to outdir | — | |
QuickCCheck |
Validate configuration | — | |
QuickCHealth |
Health report | — | |
QuickCReload |
Reload configuration | — | |
QuickCConfig |
Print effective configuration & project path | — |
<leader>cqbbuild<leader>cqrrun<leader>cqRbuild & run<leader>cqDdebug<leader>cqMTelescope Make targets<leader>cqCCMake targets (Telescope)<leader>cqBCMake build<leader>cqcCMake configure<leader>cqSTelescope source picker<leader>cqfOpen quickfix (Telescope)<leader>cqLBuild logs (Telescope)<leader>cqxStop current internal task (single/multi-file builds only)<leader>cqtRetry last internal task (single/multi-file builds only)
- Parses gcc/clang/MSVC output to quickfix (errors & warnings)
- Auto open/jump policy:
always | error | warning | never - Prefer an enhanced Quickfix Telescope picker when available: right-side preview shows the item's message and ±3 lines of source context. Fallbacks to
telescope.builtin.quickfix, then to:copen. - If the current buffer is unnamed and modified, auto-jump is skipped to avoid save prompts.
- Note: QuickCStop/QuickCRetry only affect the plugin's internal task queue for single/multi-file builds; they do not apply to Make/CMake flows.
Quick-c supports multi-level configuration with priority from high to low:
- Project-level configuration (
.quick-c.json) - overrides global config - User configuration (
setup()parameters) - user customizations - Default configuration - plugin built-in defaults
Create a .quick-c.json file in your project root directory to customize configuration for specific projects, overriding global settings. The plugin automatically detects and applies project configuration when available.
Configuration file lookup rules:
- Only search in the current working directory (
:pwd, project root) - File name is fixed to
.quick-c.json - On directory change (
DirChanged), configuration is auto reloaded (with 400ms debounce)
Configuration format:
- JSON format
- Same structure as Lua configuration
- Support all configuration options
more details in GUIDE.
Notes:
- With
make.prefer_force = true:- If
preferis not executable, parsing will only warn and try an available make to discover targets; - Running still uses your
preferto build the command (combine withQuickCMakeCmdfor full control).
- If
- Parsing fallback: try
-pnwhen-qpreturns nothing.
Example .quick-c.json (annotated):
Minimal example:
require('quick-c').setup({
-- Optional modules: turn off to avoid overlap with other plugins
telescope_enhance = true, -- disable to turn off built-in Telescope UIs (pickers/quickfix preview)
make = { enabled = true }, -- disable to hide Make commands/keymaps
cmake = { enabled = true }, -- disable to hide CMake commands/keymaps (pickers/build/configure)
outdir = 'source',
toolchain = {
windows = { c = { 'gcc', 'cl' }, cpp = { 'g++', 'cl' } },
unix = { c = { 'gcc', 'clang' }, cpp = { 'g++', 'clang++' } },
},
-- Build timeout in milliseconds (e.g., 2 minutes)
build = { timeout_ms = 120000 },
compile = { -- It only works when you want to use custom tools. And make.prefer_force = true
prefer = { c = nil, cpp = nil }, -- such c = i686-gcc-elf
prefer_force = false,
},
make = {
prefer = { 'make', 'mingw32-make' },
cache = { ttl = 10 },
-- When true, omit `-C <cwd>` and run in the terminal's current directory
no_dash_C = false,
telescope = { choose_terminal = 'auto' },
},
diagnostics = {
quickfix = { open = 'warning', jump = 'warning', use_telescope = true },
},
-- Force a specific compiler name (useful for cross toolchains). When prefer_force = true,
-- the name is used even if not found in PATH (may fail to run; expected consequence).
compile = {
prefer = { c = 'arm-none-eabi-gcc', cpp = 'arm-none-eabi-g++' },
prefer_force = false,
},
debug = {
search = {
dirs = { './build/bin', './out' },
up = 2,
down = 2,
ignore_dirs = { '.git', 'node_modules', '.cache' },
},
concurrency = 8,
},
keymaps = {
enabled = true,
build = '<leader>cqb',
run = '<leader>cqr',
build_and_run = '<leader>cqR',
debug = '<leader>cqD',
},
})Example (trimmed):
require('quick-c').setup({
outdir = 'source',
toolchain = {
windows = { c = { 'gcc', 'cl' }, cpp = { 'g++', 'cl' } },
unix = { c = { 'gcc', 'clang' }, cpp = { 'g++', 'clang++' } },
},
-- Build timeout in milliseconds (e.g., 2 minutes)
build = { timeout_ms = 120000 },
make = {
prefer = { 'make', 'mingw32-make' },
cache = { ttl = 10 },
targets = { prioritize_phony = true },
args = { prompt = true, default = '', remember = true },
-- When true, omit `-C <cwd>` and run in the terminal's current directory
no_dash_C = false,
telescope = { choose_terminal = 'auto' },
},
diagnostics = {
quickfix = {
enabled = true,
open = 'warning', -- always | error | warning | never
jump = 'warning', -- always | error | warning | never
use_telescope = true,
},
},
debug = {
search = {
dirs = { './build/bin', './out' },
up = 2,
down = 2,
ignore_dirs = { '.git', 'node_modules', '.cache' },
},
concurrency = 8,
},
keymaps = {
enabled = true,
build = '<leader>cqb',
run = '<leader>cqr',
build_and_run = '<leader>cqR',
debug = '<leader>cqD',
make = '<leader>cqM',
sources = '<leader>cqS',
quickfix = '<leader>cqf',
},
}){
"AuroBreeze/quick-c",
ft = { "c", "cpp" },
keys = {
{ "<leader>cqb", desc = "Quick-c: Build" },
{ "<leader>cqr", desc = "Quick-c: Run" },
{ "<leader>cqR", desc = "Quick-c: Build & Run" },
{ "<leader>cqD", desc = "Quick-c: Debug" },
{ "<leader>cqM", desc = "Quick-c: Make targets (Telescope)" },
{ "<leader>cqS", desc = "Quick-c: Select sources (Telescope)" },
{ "<leader>cqf", desc = "Quick-c: Open quickfix (Telescope)" },
{ "<leader>cqx", desc = "Quick-c: Stop current task" },
{ "<leader>cqt", desc = "Quick-c: Retry last task" },
},
cmd = {
"QuickCBuild", "QuickCRun", "QuickCBR", "QuickCDebug",
"QuickCMake", "QuickCMakeRun", "QuickCMakeCmd",
"QuickCCompileDB", "QuickCCompileDBGen", "QuickCCompileDBUse",
"QuickCQuickfix", "QuickCCheck",
},
config = function()
require("quick-c").setup()
end,
}use({
'AuroBreeze/quick-c',
config = function()
require('quick-c').setup()
end,
})require('quick-c').setup({
cmake = {
enabled = true,
prefer = nil, -- cmake executable
generator = nil, -- e.g. "Ninja" | "Unix Makefiles" | ...
build_dir = 'build', -- relative to project root
view = 'both', -- 'both' | 'quickfix' | 'terminal'
output = { open = true, height = 12 },
search = { up = 2, down = 3, ignore_dirs = { '.git', 'node_modules', '.cache' } },
telescope = {
prompt_title = 'Quick-c CMake Targets',
preview = true,
max_preview_bytes = 200*1024,
max_preview_lines = 2000,
set_filetype = false,
choose_terminal = 'auto',
},
args = { prompt = true, default = '', remember = true },
configure = { extra = {}, toolchain = nil },
},
})- Terminal selection for CMake targets/build is controlled by
cmake.telescope.choose_terminal(same semantics asmake.telescope.choose_terminal):auto: if a terminal is open, show a selector; otherwise use the default strategy (BetterTerm first, fallback to native)always: always show the selectornever: always use the default strategy
- CMake export:
- set
compile_commands.mode = 'cmake'or run:QuickCCompileDBGenCMake - auto-adds
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON, copies fromcmake.build_dirtocompile_commands.outdir
- set
- Non-CMake projects:
- Scan project:
:QuickCCompileDBGenProject - Specific dir:
:QuickCCompileDBGenDir [dir] - Select sources:
:QuickCCompileDBGenSources(Telescope) - Simple path: with
mode = 'generate',:QuickCCompileDBalso works
- Scan project:
outdir options: 'source' (multi-file/project prefers project root), 'cwd', relative, or absolute.
- Both directory and target pickers include Make/CMake previews with improved Windows path compatibility.
- In the target picker, the preview is fixed to the
Makefile(selected directory) orCMakeLists.txt(project root) for performance. - Preview enhancements:
- Jump-to-definition: after selecting a target, the preview auto-scrolls to its definition in
Makefile/CMakeLists.txt. - Soft wrapping: wrap/linebreak/breakindent are enabled in preview for long lines.
- Jump-to-definition: after selecting a target, the preview auto-scrolls to its definition in
- Large files are truncated by bytes/lines; controlled by:
make.telescope.previewmake.telescope.max_preview_bytesmake.telescope.max_preview_linesmake.telescope.set_filetype- CMake preview also enables jump and wrapping by default; advanced knobs can be added similarly under
cmake.telescopeif needed.
- After selecting a Make target, commands can be sent to an opened built-in terminal, or follow the default strategy (BetterTerm first, fallback to native terminal).
- Configure via
make.telescope.choose_terminal:auto: if a terminal is open, show selector; otherwise use default strategyalways: always show selectornever: always use default strategy
- If
make.cwdis not set, the plugin searches from the current file's directory:- Up to
search.uplevels upward (default 2) - For each level, recursively downward up to
search.down(default 3) - The first directory containing
Makefile/makefile/GNUmakefileis used as cwd - Directories in
ignore_dirsare skipped (default:.git,node_modules,.cache) - Enhancement: for ignored directories, perform a one-level probe (no recursion). If a Makefile exists at the root of that ignored directory, include it as a candidate
- Up to
When multiple results are found, Telescope shows paths relative to :pwd for clarity (e.g., ./build, ./sub/dir).
- Modules
lua/quick-c/init.lua: wiring, commands, keymapslua/quick-c/config.lua: defaultslua/quick-c/util.lua: utils (platform/path/messages)lua/quick-c/terminal.lua: BetterTerm/native terminallua/quick-c/make_search.lua: async Makefile search & directory selectlua/quick-c/make.lua: choose make/parse targets/run in cwdlua/quick-c/telescope.lua: Telescope interactions (make targets, custom args, source picker)lua/quick-c/build.lua: build/run/debuglua/quick-c/cc.lua: compile_commands.jsonlua/quick-c/keys.lua: key injection
- On PowerShell, runs as
& 'path\\to\\exe'; on other shells, runs as"path\\to\\exe". - For MSVC
cl, run Neovim from a Developer Command Prompt or with VS env vars initialized.
- Requires
nvim-dapandcodelldb. :QuickCDebuglaunches with codelldb;programpoints to the last build output.
- Compiler not found: ensure
gcc/g++,clang/clang++, orclare in PATH. - Build failed without output: check
:messagesor the terminal panel for warnings/errors. - Cannot send to terminal: if BetterTerm fails, the plugin falls back to the native terminal automatically.
- Cannot run executable: build first with
:QuickCBuild; also check output directory and.exeon Windows. - No make targets found: ensure a Makefile exists and
make -qpworks in that directory; on Windows trymingw32-make.
- Where is the executable written?
- Controlled by
outdir:"source": write to the source file's directory (default)- otherwise: your custom directory (relative to
:pwdor absolute path)
- Example: with
outdir = "build/bin",a.cproduces./build/bin/a.exe(Windows) or./build/bin/a.out(Unix). - If
QuickCRun/QuickCDebugcannot find the program: verifyoutdiror add your artifact directory todebug.search.dirs(e.g.,./build/bin).
- Controlled by
Contributions are welcome! Please read:
- Contribution Guide: markdown/en/CONTRIBUTING_GUIDE.en.md
See Release.md
{ // Output directory: "source" means write to the same folder as the source file; custom path is supported "outdir": "build", // Toolchain priority (per platform, per language); picks the first executable "toolchain": { "windows": { "c": ["gcc", "cl"], "cpp": ["g++", "cl"] }, "unix": { "c": ["gcc", "clang"], "cpp": ["g++", "clang++"] } }, // compile_commands.json for LSP (e.g., clangd) "compile_commands": { "mode": "generate", // generate | use "outdir": "build" // where to write; "source" writes to the source file's directory // "use_path": "./compile_commands.json" // when mode = use, copy from this path }, // Diagnostics collection into quickfix "diagnostics": { "quickfix": { "open": "warning", // always | error | warning | never "jump": "warning", // always | error | warning | never "use_telescope": true // prefer Telescope quickfix if available } }, // Make settings "make": { // Preferred make program: string or list; on Windows often ["make", "mingw32-make"] "prefer": ["make", "mingw32-make"], // Force using the preferred value even if not found in PATH or file missing // e.g., { "prefer": "make", "prefer_force": true } "prefer_force": false, // Optional wrapper (planned): run via WSL on Windows, e.g., "wsl" // "wrapper": "wsl", // Fixed working directory used for -C // Note: the directory must exist; otherwise it falls back to the start dir with a warning // If it has no Makefile, the plugin will search downward within this directory (depth = search.down) "cwd": ".", // Search strategy (used when cwd is not set, or cwd requires searching within it) "search": { "up": 2, // go up at most this many levels (bounded by :pwd) "down": 3, // per-level downward recursion depth "ignore_dirs": [".git", "node_modules", ".cache"] // directories to skip // Enhancement: even for ignored dirs, perform a one-level probe; if a Makefile exists at the root, include it }, // Telescope display "telescope": { "prompt_title": "Project Build Targets" }, // Target cache: reuse results within TTL when Makefile unchanged under the same cwd "cache": { "ttl": 10 }, // Extra make args (e.g., -j4 VAR=1), remember last input per cwd "args": { "prompt": true, "default": "-j4", "remember": true } }, // Debug executable discovery when the default path is missing "debug": { "search": { "dirs": ["./build/bin", "./out"], // preferred directories; fall back to up/down if absent "up": 2, // limit upward search within :pwd "down": 2, // downward breadth-first depth "ignore_dirs": [".git", "node_modules", ".cache"], }, "concurrency": 8, // parallel fs_scandir concurrency }, // Compiler preference and force mode (similar to make.prefer_force) "compile": { "prefer": { "c": "arm-none-eabi-gcc", "cpp": "arm-none-eabi-g++" }, "prefer_force": false }, // Default keymaps (customizable/disable-able); injected only when keymaps.enabled != false "keymaps": { "build": "<leader>cb", "run": "<leader>cr", "build_and_run": "<leader>cR", "debug": "<leader>cD", "make": "<leader>cM", "sources": "<leader>cS", "quickfix": "<leader>cf" // When you change/disable a key, old default mappings are automatically unmapped by default // Set `unmap_defaults = false` to keep them } }