Skip to content

Conversation

MariaSolOs
Copy link
Member

Checking workspace folders in the input configuration in the default reuse_client implementation for vim.lsp.start.

@justinmk
Copy link
Member

Related neovim/nvim-lspconfig#3452 @glepnir

local config_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir)
or {}
for _, config_folder in ipairs(config_folders) do
for _, client_folder in ipairs(client.workspace_folders) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we'd need to handle the case somehow differently where config_folders contains workspaces not present in client.workspace_folder.

If the user provides workspace [a, b] and ends up with a client that has [a, c] that might be confusing.

We could extend the client workspace's automatically (getting [a, b, c] in ^)
Or require exact matches?

No idea what's less suprising and more convenient.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm FWIW nvim-lspconfig reuses a client as long as the name matches, so I don’t think this approach is too revolutionary.

Copy link
Member

@mfussenegger mfussenegger Nov 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reusing always if only the name matches sounds broken to me.

Say you have:

workspace/project-a/
workspace/project-b/

and you open a file within project-a the first time. That will start a client
Now you open a file in project-b, which has a different set of dependencies, but same language. If it re-used the client from project-a, you'd have a language server that can resolve dependencies of project-a but not project-b, and likely get lots of errors.


As for the workspace folders - I don't use them myself so I'm not that familiar with the common use-cases, but my understanding is that they allow you to do things like this:

workspace/project-a/
workspace/project-b/
workspace/shared/

Where project-a and project-b are independent, but both use shared.
So, if you're using a single nvim client to work on both a and b in parallel you'd likely want to have two clients, one with workspaceFolders [project-a, shared] and one with [project-b, shared].
Anything else would either lead to seeing dependencies you shouldn't, or miss dependencies you should see.

Please correct me if that's not the case.

This at least improves the situation, right?

Based on ^ I think it might make the situation worse

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reusing always if only the name matches sounds broken to me.

I'm not suggesting we do this. I just mention that this is nvim-lspconfig's approach and so I don't find the current reuse_client overly flexible in comparison.

As for workspace folders, you bring a good point. I can change the current implementation to only reuse a client when the configuration only includes folders that an existing client is already aware of.

Copy link
Member Author

@MariaSolOs MariaSolOs Nov 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LMK what you think :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvim-lspconfig reuses a client as long as the name matches,

No. The latest refactoring turned it into this. It resulted in some clients being reused that shouldn't be reused.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glepnir which refactor is that? Are you referring to neovim/nvim-lspconfig#3450?

Copy link
Member

@glepnir glepnir Dec 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I used a wrong server for testing before . I think the problem still exists. When loading multiple projects of the same language from the session. You can't know the ability of the server to be started when the second buffer is triggered. Because it may be uninitialized. That is to say, clinet.initialized is nil. You can't know whether it supports workspaceFolder. Here must wait for the initialization of the started server to be completed before deciding whether to reuse or a new instance. I think the core should handle this situation if i am wrong please correct me .

Another problem is the logic of lsoconfig reuse_client. It may not be applicable here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glepnir Please correct me if I'm wrong, but before my change this function reuses clients based on their name, prioritizing one in the same root directory but still falling back to just comparing names. The PR I made didn't change the client reuse logic at all, it merely focused on replacing start_client by start, but I can stop my contributions if they're unwelcome.

As for the issue you're describing I still don't see why on_init doesn't handle this scenario (which I already mentioned here). You can see from the editor implementation how that callback is called after initialization.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously I used a timer to wait for the first server to initialize. The refactoring removed this part. So the core better consider this case.

@justinmk
Copy link
Member

This at least improves the situation, right? So let's unblock it and can improve later if possible.

@MariaSolOs MariaSolOs force-pushed the lsp-todo branch 2 times, most recently from 3e02ae5 to d7e102f Compare November 30, 2024 18:17
@MariaSolOs
Copy link
Member Author

@justinmk @lewis6991 @mfussenegger Do you still want this? I don't want to work on a PR that won't get merged anyway.

@lewis6991
Copy link
Member

lewis6991 commented Dec 6, 2024

I approved. I don't understand this area or its impacts well enough, so I'm deferring to someone else (@mfussenegger) to merge.

@justinmk
Copy link
Member

justinmk commented Dec 6, 2024

As for workspace folders, you bring a good point. I can change the current implementation to only reuse a client when the configuration only includes folders that an existing client is already aware of.

That SGTM, any objection from @mfussenegger if that is implemented?

@MariaSolOs
Copy link
Member Author

As for workspace folders, you bring a good point. I can change the current implementation to only reuse a client when the configuration only includes folders that an existing client is already aware of.

That SGTM, any objection from @mfussenegger if that is implemented?

Note that I already added this to the PR.

@clason
Copy link
Member

clason commented Dec 7, 2024

Backport?

@lewis6991 lewis6991 merged commit c2bf09d into neovim:master Dec 7, 2024
31 checks passed
@MariaSolOs MariaSolOs deleted the lsp-todo branch December 7, 2024 16:53
@MariaSolOs
Copy link
Member Author

Backport?

Not sure. I wouldn't consider this a fix per se but more of an improvement, but I'll let others decide.

justinmk pushed a commit that referenced this pull request Dec 18, 2024
…ders #31608

Problem:
regression since #31340

`nvim -l repro.lua`:
```lua
vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls' }
vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls', root_dir = 'foo' }

-- swapped case will be ok:
-- vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls', root_dir = 'foo' }
-- vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls' }
```

Failure:
```
E5113: Error while calling lua chunk: /…/lua/vim/lsp.lua:214: bad argument #1 to
'ipairs' (table expected, got nil)
stack traceback:
        [C]: in function 'ipairs'
        /…/lua/vim/lsp.lua:214: in function 'reuse_client'
        /…/lua/vim/lsp.lua:629: in function 'start'
        repro.lua:34: in main chunk
```
mrowegawd pushed a commit to mrowegawd/neovim that referenced this pull request Jan 30, 2025
…ders neovim#31608

Problem:
regression since neovim#31340

`nvim -l repro.lua`:
```lua
vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls' }
vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls', root_dir = 'foo' }

-- swapped case will be ok:
-- vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls', root_dir = 'foo' }
-- vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls' }
```

Failure:
```
E5113: Error while calling lua chunk: /…/lua/vim/lsp.lua:214: bad argument neovim#1 to
'ipairs' (table expected, got nil)
stack traceback:
        [C]: in function 'ipairs'
        /…/lua/vim/lsp.lua:214: in function 'reuse_client'
        /…/lua/vim/lsp.lua:629: in function 'start'
        repro.lua:34: in main chunk
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants