Search code examples
neovimclangdnvim-lspconfig

Is it possible to override or augment neovim's LSP configuration via a workspace config file?


I am using Neovim for C++ development (currently AstroNvim, and previously used LazyVim), and like it a lot. Usually I do not have any issues with the defaults for nvim-lspconfig and mason - the standard clangd server downloaded by mason from the official LLVM release is working fine.

But when it comes to ESP32 development, the official LLVM release does not recognize the xtensa*-*-elf target triplet. This prevents it from properly parsing the source files and whatever else is in compile_commands.json, so I need to use Espressif's own clang release, and always have to tweak my configuration to force something like:

-- nvim-lspconfig.lua
return {
  {
    "neovim/nvim-lspconfig",
    opts = {
      servers = {
        clangd = {},
        -- whatever other language servers you want
      },
      setup = {
        clangs = function(_, opts)
          opts.cmd = "~/.espressif/tools/esp-clang/bin/clangd"
        end
      },
    },
  },
}

Over time this gets really annoying, especially if I need to switch back and forth before a project is complete.

So the question is, is there a way to override the global Neovim LSP configuration using some project-specific dotfile, which is recognized and parsed automatically when I start the editor inside the project's workspace? Something like .editorconfig, but for lua-style configuration, which can "help" the lazy plugin manager configure the language servers with project-specific settings. If such mechanism exists via built-in functionality, or provided by some plugin, please also provide some hint as to how lspconfig settings can be overridden, specifically setting the clangd executable path (if it differs from the way I showed in the sample above). Thanks!


Solution

  • Yes, it should be possible with the nvim-config-local plugin. https://github.com/klen/nvim-config-local

    Add this to the plugins folder:

    return {
      "klen/nvim-config-local",
      config = function()
        require("config-local").setup({
          -- Default options (optional)
    
          -- Config file patterns to load (lua supported)
          config_files = { ".clangd.lua", ".nvim.lua", ".nvimrc", ".exrc" },
    
          -- Where the plugin keeps files data
          hashfile = vim.fn.stdpath("data") .. "/config-local",
    
          autocommands_create = true, -- Create autocommands (VimEnter, DirectoryChanged)
          commands_create = true, -- Create commands (ConfigLocalSource, ConfigLocalEdit, ConfigLocalTrust, ConfigLocalIgnore)
          silent = false, -- Disable plugin messages (Config loaded/ignored)
          lookup_parents = false, -- Lookup config files in parent directories
        })
      end,
    }
    

    Then in your project root directory, create a file .clangd.nvim with this content:

    require("lspconfig").clangd.setup({
        cmd = {
            "~/.espressif/tools/esp-clang/bin/clangd",
            "--pretty",
            "--header-insertion=iwyu",
            -- "--background-index",
            -- "--suggest-missing-includes",
            "--query-driver=/path/to/toolchain/bin/",
            "-j=40",
            "--pch-storage=memory",
            "--clang-tidy",
            "--compile-commands-dir=.",
        },
        filetypes = { "c", "cpp", "objc", "objcpp", "cuda", "proto" },
    })
    

    Tested with LazyVim (but not with your specific ESP32 clangd though):

    $ nvim --version
    NVIM v0.9.1
    Build type: Release
    LuaJIT 2.1.0-beta3
    
    $ cat /etc/issue
    Linux Mint 21.1 Vera \n \l