ESP32 development helper for Neovim.
Designed for a smooth ESP-IDF workflow inside Neovim and LazyVim.
Uses snacks.nvim for terminal and picker UIs.
- 🧠 Automatically detects ESP-IDF-specific
clangd - 🛠 Configures
build_dir(build.clang) for IDF builds - 🖥️ Launch
idf.py monitorandidf.py flashin floating terminals - 🔎 Pick available USB serial ports dynamically
- 📋 Check project setup with
:ESPInfo - 🛠 Quickly run reconfigure with
:ESPReconfigure - ⚙️ Automatically configures
clangdfor LazyVim LSP
- ESP-IDF installed and initialized
- ESP-specific
clangdis installed viaidf_tools.py install esp-clang - ESP-specific
clangdis configured viaidf.py -B build.clang -D IDF_TOOLCHAIN=clang reconfigure(can be done via command:ESPReconfigure) - snacks.nvim (automatically installed via LazyVim dependencies)
Install via Lazy.nvim or any other plugin manager. Via Lazy.nvim:
{
"Aietes/esp32.nvim",
}
⚠️ Attention: It's critical to ensurenvim-lspconfigis configured to actually use the ESP-specificclangd. This is done in the example below by settingoptsfornvim-lspconfig.esp32.nvimprovides a working LSP configuration vialsp_config, which can be used. If you are using a different LSP setup, make sure to adjust accordingly.
{
"neovim/nvim-lspconfig",
opts = function(_, opts)
local esp32 = require("esp32")
opts.servers = opts.servers or {}
opts.servers.clangd = esp32.lsp_config()
return opts
end,
},To customize, simply set the opts as usual:
{
"Aietes/esp32.nvim",
opts = {
-- custom build dir
build_dir = "build.custom",
},
keys = {
{
-- some other keymap
"<leader>em",
function()
require("esp32").pick("monitor")
end,
desc = "ESP32: Pick & Monitor",
},
}
}Below is the default configuration:
return {
"Aietes/esp32.nvim",
name = "esp32.nvim",
dependencies = {
"folke/snacks.nvim",
},
opts = {
build_dir = "build.clang",
},
config = function(_, opts)
require("esp32").setup(opts)
end,
keys = {
{
"<leader>RM",
function()
require("esp32").pick("monitor")
end,
desc = "ESP32: Pick & Monitor",
},
{
"<leader>Rm",
function()
require("esp32").command("monitor")
end,
desc = "ESP32: Monitor",
},
{
"<leader>RF",
function()
require("esp32").pick("flash")
end,
desc = "ESP32: Pick & Flash",
},
{
"<leader>Rf",
function()
require("esp32").command("flash")
end,
desc = "ESP32: Flash",
},
{
"<leader>Rc",
function()
require("esp32").command("menuconfig")
end,
desc = "ESP32: Configure",
},
{
"<leader>RC",
function()
require("esp32").command("clean")
end,
desc = "ESP32: Clean",
},
{ "<leader>Rr", ":ESPReconfigure<CR>", desc = "ESP32: Reconfigure project" },
{ "<leader>Ri", ":ESPInfo<CR>", desc = "ESP32: Project Info" },
},
}opts = {
build_dir = "build.clang", -- directory for CMake builds (must match your clangd compile_commands.json)
}| Command | Description |
|---|---|
:ESPReconfigure |
Runs idf.py -B build.clang -D IDF_TOOLCHAIN=clang reconfigure |
:ESPInfo |
Shows ESP32 project setup info |
:ESPBuild |
Runs a build of the project |
pick |
Pick a serial port and run a command on it. |
command |
Run a command (uses last port if needed) |
Clone and install ESP-IDF:
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
./install.sh esp32c3Install the Espressif-specific clangd:
idf_tools.py install esp-clangCreate your build directory using clang:
idf.py -B build.clang -D IDF_TOOLCHAIN=clang reconfigureFrom now on, always build and flash using:
idf.py -B build.clang build
idf.py -B build.clang flash- This plugin does not install ESP-IDF automatically.
- You must either:
- Use a Nix flake (recommended, see below)
- Or manually source
~/esp/esp-idf/export.shbefore launching Neovim
- direnv or a
flake.nixis recommended for auto-loading ESP-IDF environments
Using nix is highly recommended. Use this flake.nix to create a reproducible ESP32 development environment:
{
description = "Development ESP32 C3 with ESP-IDF";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ cmake ninja dfu-util python3 ccache ];
shellHook = ''
. $HOME/esp/esp-idf/export.sh
'';
};
});
}Then use direnv with a .envrc:
touch .envrc
echo 'use flake' > .envrc
direnv allowThis will automatically load the environment when you enter the directory. ✅ Now Neovim and the plugin will inherit the full ESP-IDF toolchain environment.
MIT License © 2024 Aietes