-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Description
Problem
When opening a non-file backed buffer that still matches a lsp filetype, duplicate lsp servers are started with a rootPath set to /.
For example, with emmylua_ls, opening a file named diffview:///Users/cam/Dev/neovim-dev/opencode.nvim/.git/:0:/lua/opencode/state.lua will start a duplicate emmylua_ls server and that server will start indexing / (i.e. the whole filesystem).
I traced it down and it's happening in lsp.start:
neovim/runtime/lua/vim/lsp.lua
Lines 668 to 678 in 16c8152
| function lsp.start(config, opts) | |
| opts = opts or {} | |
| local reuse_client = opts.reuse_client or reuse_client_default | |
| local bufnr = vim._resolve_bufnr(opts.bufnr) | |
| if not config.root_dir and opts._root_markers then | |
| validate('root_markers', opts._root_markers, 'table') | |
| config = vim.deepcopy(config) | |
| config.root_dir = vim.fs.root(bufnr, opts._root_markers) | |
| end |
For non-file backed buffers, vim.fs.root starts looking in the current directory and, if it matches, it returns a relative directory.
That relative directory doesn't match the checks in reuse_client_default so new servers are spawned.
The incorrect rootPath comes from Client:initialize:
neovim/runtime/lua/vim/lsp/client.lua
Lines 503 to 515 in 16c8152
| function Client:initialize() | |
| -- Register all initialized clients. | |
| all_clients[self.id] = self | |
| local config = self.config | |
| local root_uri --- @type string? | |
| local root_path --- @type string? | |
| if self.workspace_folders then | |
| root_uri = self.workspace_folders[1].uri | |
| root_path = vim.uri_to_fname(root_uri) | |
| end | |
vim.uri_to_fname translates the file://. to /. which is what the language server receives.
To fix, I think we just have to pass the return from vim.fs.root to vim.fn.fnamemodify:
config.root_dir = vim.fn.fnamemodify(vim.fs.root(bufnr, opts._root_markers), ':p:h')Steps to reproduce using "nvim -u minimal_init.lua"
minimal_init.lua
local pattern = 'lua'
local cmd = { 'emmylua_ls' }
-- Add files/folders here that indicate the root of a project
local root_markers = { '.luarc.json', '.emmyrc.json', '.luacheckrc', '.git' }
-- Change to table with settings if required
local settings = vim.empty_dict()
vim.api.nvim_create_autocmd('FileType', {
pattern = pattern,
callback = function(args)
vim.lsp.start({
name = 'emmylua_ls',
cmd = cmd,
settings = settings,
}, { _root_markers = root_markers })
end,
})Repro:
- touch
.emmyrc.json nvim -u minimal_init.lua minimal_init.lua(second arg is to load a lua file to triggeremmylua_ls):e diffview:///Users/cam/Dev/neovim-dev/opencode.nvim/.git/:0:/lua/opencode/state.lua(diffview is not required, file does not need to exist):lua print(vim.inspect(#vim.lsp.get_active_clients()))
Expected behavior
No new lsp servers should be spawned (and, even if they were, they should have the correct rootPath).
Nvim version (nvim -v)
NVIM v0.12.0-dev-1569+g16c8152229
Language server name/version
emmylua_ls 0.16.0
Operating system/version
macOS 15.6.1
Log file
https://gist.github.com/cameronr/3e9ee385af755fcbe5c2b5d333c04b0b