Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle buffer which has multiple LSP clients available? #89

Open
lougreenwood opened this issue Feb 10, 2023 · 9 comments
Open
Labels
help wanted Extra attention is needed

Comments

@lougreenwood
Copy link

I'm noticing some weird behaviour for buffers which have multiple clients with the documentSymbolProvider capability.

Specifically, I'm using tsserver and ember language servers.

When I open any .ts or .js file with these servers I get the error nvim-navic: Failed to attach to tsserver for current buffer. Already attached to tsserver.

What is the correct way to handle this? I'm assuming that a quick and dirty way to do this would be could be to hard code in the on-attach, but I'm trying to think of a more general config which doesn't require hard coding.

Alternatively, do you see any heuristic which nvim-navic could employ to discern which client of many is the most suitable one to use? (Maybe the one with the most provided symbols or something similar?)

Thankyou!

@lougreenwood
Copy link
Author

Alternatively... considering that multiple clients might provide symbols for different parts of a file (In this case, tsserver for the "typescript" code and ember for the embedded template code), is it possible that nvim-navic might support multiple clients in future?

@SmiteshP
Copy link
Owner

SmiteshP commented Feb 11, 2023

Proper solution for this is really to just using the attach function on only one of the lsp servers. nvim-navic can make use of only one of the lsp server right now. Or you can use navic_silence global variable to silence the error messages thrown by navic, but it will still use only one of the servers.

considering that multiple clients might provide symbols for different parts of a file (In this case, tsserver for the "typescript" code and ember for the embedded template code)

Not sure I follow, one file has code from multiple languages?

is it possible that nvim-navic might support multiple clients in future?

No plans for this right now, but I would need to understand the use case for this. Because it is difficult to understand which information to use and which to discard when multiple servers are giving info, so I trust the user would make the attachments as they see fit.

@lougreenwood
Copy link
Author

lougreenwood commented Feb 11, 2023

Not sure I follow, one file has code from multiple languages?

Correct, for example, this can be seen here in the way tests are written in Ember.js:

test("should allow disabling the button", async function (assert) {
  await render(hbs`
    <SimpleButton
      @label="Hello world!"
      @isDisabled={{true}}
    />
  `);
  
  let button = this.element.querySelector("button");
  assert.strictEqual(button.disabled, true);
});

https://guides.emberjs.com/release/testing/testing-tools/#toc_qunit-qunit-dom

You can see here that the file is a javascript file, but in the template literal (hbs`...` ) we have handlebars (aka glimmer) template code.

So for this code, I need 2 LSP clients, typescript & ember. The ember LSP client knows to only deal with document symbols in the hbs tagged code.

You can also see more info here: https://github.com/ember-template-imports/ember-template-imports - this is for the .gjs file format which also allows combining js with these glimmer templates.

Treesitter also supports this concept of files having multiple formats / languages: http://tree-sitter.github.io/tree-sitter/using-parsers#multi-language-documents

Also, here's some info about how VSCode handles this: https://code.visualstudio.com/api/language-extensions/embedded-languages

No plans for this right now, but I would need to understand the use case for this. Because it is difficult to understand which information to use and which to discard when multiple servers are giving info, so I trust the user would make the attachments as they see fit.

For the above use case, I would guess that something like the following would be how to handle this (bear in mind I know very little about LSP inner workings / api / implementation, so maybe some of my assumptions might be naive or incorrect):

  • for a given file, multiple lip clients can be attached
  • for a given position in the file, only one lsp client should provide symbols
    • some heuristineg / rule needed if lsp's misbehave and provide symbols?
  • nvim-navic displays the current symbol for the code currently under the cursor

@SmiteshP
Copy link
Owner

Hmm.. seems complicated 🤔

@SmiteshP SmiteshP added the help wanted Extra attention is needed label Feb 11, 2023
@unfirthman
Copy link

Hello

I had a similar error over the weekend:

Javascript Compatibility

The issue seems to have been resolved by removing redundant Javascript LSPs. Removing vtsls has me running smoothly again.

@lougreenwood
Copy link
Author

@unfirthman But it seems that in your use case, your other LSP client was redundant. In the usecase I'm describing both LSPs are useful and needed to get full symbol "discovery" for a given file.

@nyngwang
Copy link

nyngwang commented Mar 19, 2024

@kola-web What's the point of providing a wrong snippet without explanation? You still attach only one navic instance for only one of the LSPs of the current buffer. The problem they were talking about here is being able to handle multiple language servers attached to the same buffer.

@nyngwang
Copy link

nyngwang commented Mar 19, 2024

I have a similar problem recently. There is an error message saying that navic for tsserver cannot be attached because graphql lsp has occupied the only position. This is an error for me because tsserver outweighs graphql one in this case.

It will be really helpful if navic can be applied to multiple LSPs.

For some real examples I have encountered:

  1. I have a private ChatGPT program in neovim, and it's unavoidable to write multiple embedded scripts in different programming languages inside the prompt.
  2. Sometimes I need to write JS inside HTML.
  3. There are JSX syntax, CSS-in-JS, etc.

@Amar-Gill
Copy link

Amar-Gill commented Mar 26, 2024

Also relevant to this discussion is tsserver and volar 2.0 (vue-language-server).

Recommendation from the team is to attach both lsp clients to buffer: https://github.com/vuejs/language-tools?tab=readme-ov-file#community-integration

For now in my "breadcrumbs" method I just don't attach navic to the buffer for vue files.

-- allows for context aware breadcrumbs
local breadcrumbs = function(client, bufnr)
	if client.name == "volar" then
		return
	end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

5 participants