Neovim and Rustaceanvim With Esp Toolchain

I was trying to get cargo to use the custom esp toolchain from Espressif, but use stable for rust-analyzer because the esp toolchain does not include a rust-analyzer component.

Neovim has a built-in option to load user-defined config at the project level called excr, which can be enabled with:

vim.o.exrc = true -- enable project local config

With this enabled, the following .nvim.lua will merge the global configuration I have set for vim.g.rustaceanvim (and this is helpful because I have settings for use with the bacon-lsp as well):

local ra_settings = {
 cargo = {
  target = "xtensa-esp32s3-none-elf",
  allTargets = false,
  extraEnv = {
   RUST_TOOLCHAIN = "esp",
   RUSTUP_TOOLCHAIN = "esp",
  },
 },
}

-- Configure rustaceanvim via vim.g.rustaceanvim
local existing = vim.g.rustaceanvim
vim.g.rustaceanvim = function()
 local base = type(existing) == "function" and existing() or (type(existing) == "table" and existing or {})

 return vim.tbl_deep_extend("force", base, {
  server = {
   cmd = { "rustup", "run", "stable", "rust-analyzer" },
   extra_env = { RUSTUP_TOOLCHAIN = "stable", RUST_TOOLCHAIN = "stable" },
   default_settings = {
    ["rust-analyzer"] = ra_settings,
   },
   settings = function(project_root, default_settings)
    local base_settings = type(base.server and base.server.settings) == "function"
      and base.server.settings(project_root, default_settings)
     or (base.server and base.server.settings)
     or default_settings
     or {}
    return vim.tbl_deep_extend("force", base_settings, {
     ["rust-analyzer"] = ra_settings,
    })
   end,
  },
 })
end

-- Register in vim.lsp.config for rustaceanvim client configuration
vim.lsp.config("rust-analyzer", {
 cmd = { "rustup", "run", "stable", "rust-analyzer" },
 cmd_env = { RUSTUP_TOOLCHAIN = "stable" },
 settings = {
  ["rust-analyzer"] = ra_settings,
 },
})

Important notes

  1. Using RUST_TOOLCHAIN vs RUSTUP_TOOLCHAIN

    • The project’s rust-toolchain.toml pins the toolchain to the custom esp channel
    • When Neovim attempted to launch rust-analyzer, rustup tried to locate it inside the esp toolchain (which lacks rust-analyzer) and failed
    • rustup requires RUSTUP_TOOLCHAIN (not RUST_TOOLCHAIN) to override toolchain resolution.
  2. rust-analyzer Binary Execution Path

    • Environment variables placed inside settings["rust-analyzer"].server.extraEnv are not part of rust-analyzer’s LSP settings schema and were ignored.
    • Explicitly setting server.cmd to run rustup run stable rust-analyzer
  3. Global vim.g.rustaceanvim Configuration

    • In my ~/.config/nvim/lua/config/lsp.lua, vim.g.rustaceanvim is defined as a function
    • This lua script evaluates existing() if it is a function
  4. LSP Config Integration

    • rustaceanvim merges client settings from vim.lsp.config["rust-analyzer"] when starting up, and vim.lsp.config("rust-analyzer", ...) is updated to match the correct environment variable and command definitions
 

cmac4603

A random assortment of notes.


Categories


2026-08-29