Skip to content

Latest commit

 

History

History
253 lines (194 loc) · 8.42 KB

File metadata and controls

253 lines (194 loc) · 8.42 KB

Version Tests Last Commit Neovim License

ESP32.nvim

ESP32.nvim provides an ESP-IDF workflow for Neovim and LazyVim: build, flash, monitor, configure, select targets, and use Espressif's clangd without leaving the editor.

✨ Features

  • 🛠️ Run ESP-IDF build, flash, monitor, menuconfig, clean, and reconfigure tasks
  • 🔌 Select serial ports on macOS and Linux and reuse the last selection
  • 🎯 Select any target supported by the active ESP-IDF installation
  • 🧠 Detect Espressif's clangd and configure it for the project
  • 🔎 Detect missing or GCC-generated compilation databases
  • 🔄 Restart project clangd clients after reconfigure and target changes
  • 📋 Inspect the active environment, clangd command, and build database with :ESPInfo

Requirements

  • Neovim 0.11 or newer
  • An activated ESP-IDF environment
  • Espressif's esp-clang tool (optional in ESP-IDF, required for this LSP workflow)
  • snacks.nvim (installed automatically by lazy.nvim)

ESP-IDF Installation Manager is the recommended upstream installer. See ESP-IDF setup for EIM, manual installation, activation, and clang toolchain details.

ESP32.nvim is an ESP-IDF clang workflow. Espressif still describes parts of the clang toolchain as under development, so some projects or components that build with GCC may not yet build with clang. See project compatibility.

Quick start

1. Install the plugin

lazy.nvim

{
  "Aietes/esp32.nvim",
}

With lazy.nvim's standard package support, the repository's lazy.lua spec:

  • installs the required snacks.nvim dependency
  • calls require("esp32").setup() with build_dir = "build.clang"
  • provides the default keymaps
  • adds the ESP32 which-key group when which-key.nvim is already installed

It does not configure clangd; complete step 2 below.

For native vim.pack and other plugin managers, see Installation methods.

2. Connect the LSP

⚠️ Attention: Installing ESP32.nvim does not configure clangd automatically. Complete the LSP setup below to enable completion, diagnostics, hover, and go-to-definition.

Choose the setup that matches your configuration.

For LazyVim:

{
  "neovim/nvim-lspconfig",
  opts = function(_, opts)
    opts.servers = opts.servers or {}
    opts.servers.clangd = require("esp32").lsp_config()
  end,
}

For plain Neovim 0.11+:

vim.lsp.config("clangd", require("esp32").lsp_config())
vim.lsp.enable("clangd")

If you do not use lazy.nvim, install and configure snacks.nvim, then call require("esp32").setup() before enabling the LSP.

See LSP configuration for clangd detection, nested project roots, non-ESP C/C++ projects, and advanced toolchains.

3. Start in an activated environment

Activate the intended ESP-IDF version before launching Neovim:

source ~/.espressif/tools/activate_idf_vX.Y.Z.sh
cd /path/to/your/project
nvim

Replace vX.Y.Z with the installed version name. Use the activation script generated for your shell. Windows users should launch or source the EIM-generated PowerShell environment.

Alternatively, a project-local Nix/direnv setup can activate an existing ESP-IDF installation automatically whenever you enter the project directory, so Neovim inherits the environment without a manual source step.

4. Generate the clang database

Open a C or C++ file and run:

:ESPReconfigure

This creates the configured build directory (default: build.clang) with IDF_TOOLCHAIN=clang, then restarts clangd so it reads the new database.

5. Verify the setup

:ESPInfo

It should report an Espressif clangd, a clang-generated compile_commands.json, a working idf.py, and a populated IDF_PATH. If not, follow the troubleshooting guide.

Configuration

Override the packaged defaults in your plugin spec:

{
  "Aietes/esp32.nvim",
  opts = {
    build_dir = "build.clang",
    clangd_args = {},
    idf_cmd = nil,
  },
}
Option Default Purpose
build_dir "build.clang" Project-relative ESP-IDF build directory and clangd compilation database
clangd_args {} Extra arguments appended to the generated clangd command
idf_cmd nil idf.py executable or argv override, such as { "mise", "exec", "--", "idf.py" }

For cross-toolchain include problems, read Query-driver before adding a broad --query-driver=** rule.

Window appearance

All esp32.nvim terminal windows (build, flash, monitor, reconfigure, set-target) share the esp32_terminal snacks window style. By default they open as a float of 60% × 70% with a border that follows vim.o.winborder (rounded if unset). Size, position and border set in your snacks styles.terminal config are inherited. Adjust anything specifically for esp32.nvim — including any other window option — in your snacks.nvim config:

{
  "folke/snacks.nvim",
  opts = {
    styles = {
      esp32_terminal = {
        width = 0.9,
        height = 0.5,
        border = "double",
        position = "bottom",
      },
    },
  },
}

A borderless window (border = "none") cannot display a floating window title, so the title is shown in the winbar instead.

Commands and keymaps

The user commands are always available:

Command Action
:ESPBuild Build with the configured build directory
:ESPReconfigure Regenerate the clang build database and restart clangd
:ESPInfo Show project, toolchain, and LSP diagnostics
:ESPSetTarget Pick a supported chip target and regenerate the project

The packaged lazy.nvim spec adds:

Key Action
<leader>Rb Build
<leader>RM / <leader>Rm Pick a port and monitor / monitor with the remembered port
<leader>RF / <leader>Rf Pick a port and flash / flash with the remembered port
<leader>Rc Open menuconfig
<leader>RC Clean
<leader>Rr Reconfigure
<leader>Ri Show project info
<leader>Rt Set target

Override a key through your own lazy.nvim spec:

{
  "Aietes/esp32.nvim",
  keys = {
    {
      "<leader>em",
      function()
        require("esp32").pick("monitor")
      end,
      desc = "ESP32: Pick & Monitor",
    },
  },
}

Commands open in a floating terminal. Press Ctrl + ] to stop the process and close it. Pressing q hides a monitor terminal without stopping it, so the same command can reattach later.

:ESPSetTarget follows idf.py set-target: it clears the build directory, regenerates sdkconfig, and saves the previous configuration as sdkconfig.old.

Documentation

License

MIT License © 2026 Aietes