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

Native lsp handshake 2 #49

Merged
merged 11 commits into from
Oct 23, 2023
Merged

Native lsp handshake 2 #49

merged 11 commits into from
Oct 23, 2023

Conversation

pr2502
Copy link
Owner

@pr2502 pr2502 commented Oct 19, 2023

This is a rewrite of #22 using the new types I've put in. It still needs to be tested properly before I'll be happy with merging it.

Thank you @WhyNotHugo for the idea and for proving it was possible to do this!

TODO

  • Basic implementation
  • Configuration changes (we no longer use some fields)
  • Documentation (README)
  • Example minimal editor configuration for testing
    • neovim (via direct TCP)
    • helix (via the builtin proxy client)

Copy link
Contributor

@WhyNotHugo WhyNotHugo left a comment

Choose a reason for hiding this comment

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

Thanks for picking this up again!

I tested this with my existing neovim config. I expect it to not-work right away, since my config says raMultiplex, and this now needs to be lspMux.

require'lspconfig'.rust_analyzer.setup{
  cmd = vim.lsp.rpc.connect("127.0.0.1", 27631),
  init_options = {
    raMultiplex = {
      server = "rust-analyzer",
    },
  },
  settings = {
    ['rust-analyzer'] = {
        checkOnSave = {
          command = "clippy",
        },
    }
  }
}

Neovim starts, but give no indication that the LSP has rejected the connection or anything alike. ra-multiple server logs:

 INFO client{port=32894}: client connected
ERROR client{port=32894}: client error: missing `lspMux` in `initializationOptions` in `initialize` request

I think that the connection might not be closed right away when this error happens, so the client is just waiting for a response.

Anyway, I updated raMultiplex to lspMux (with the above camelCase suggestion applied), but that didn't work.

 INFO client{port=45894}: client connected
ERROR client{port=45894}: client error: parse `initialize` request params

Caused by:
    missing field `version`

After some quick debugging, it seems that what is missing here is
lspMux.version. The docs for this say:

/// If you're connecting directly from a client make sure to set the same
/// version reported by `ra-multiplex --version`.

This approach would require reconfiguring the client after
each update. I think it's a bit simpler to just expect version = 1 for now,
and only change this the day backwards-incompatible changes are introduced.

Anyway, I added version to my init_options (which now looks like this:

    init_options = {
      lsp_mux = {
        version = "0.2.2",
        server = "rust-analyzer",
      },
    },

Neovim first complains about this:

LSP[rust_analyzer] received `end` message with no corresponding `begin`

But the LSP then seeks to work fine. I'm not entirely sure what that is about.


I then tried opening other projects, but those don't work. Only opening this project works for some mysterious reason (key detail: the ra-multiplex server has as current working directory the root of this project).

 INFO instance{pid=10904}: spawned langauge server server="rust-analyzer" args=[] cwd="file:///home/hugo/src/git.sr.ht/~whynothugo/shotman"
 INFO instance{pid=10904}: initialized server
ERROR instance{pid=10904}: stderr line=[ERROR rust_analyzer::config] failed to find any projects in [AbsPathBuf("/home/hugo/src/git.sr.ht/~whynothugo/shotman")]
ERROR instance{pid=10904}: stderr line=[ERROR rust_analyzer::main_loop] FetchWorkspaceError:
ERROR instance{pid=10904}: stderr line=rust-analyzer failed to discover workspace
 INFO client{port=37310}: initialized client
ERROR instance{pid=10904}: stderr line=[ERROR rust_analyzer::main_loop] FetchWorkspaceError:
ERROR instance{pid=10904}: stderr line=rust-analyzer failed to discover workspace

Neovim shows:

LSP[rust_analyzer] Failed to discover workspace.
Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.

Failed to load workspaces.

The same happens with any other project.

Never mind this last part: this is a bug due to my sandboxing the language servers. I think that previous implementations of ra-multiplex would run the LSP with the workspace directory as cwd, but this implementation does not.

src/client.rs Outdated Show resolved Hide resolved
src/client.rs Outdated Show resolved Hide resolved
src/lsp.rs Outdated Show resolved Hide resolved
src/lsp.rs Outdated Show resolved Hide resolved
src/instance.rs Outdated Show resolved Hide resolved
- parse file paths which are URIs using the uriparse crate
- use deprecated fields as fallback for current fields
- put back changedir before spawning child
- pass proxy-client cwd as a fallback
@pr2502 pr2502 force-pushed the native-lsp-handshake-2 branch from abf8f93 to b9d9832 Compare October 20, 2023 19:57
@pr2502 pr2502 marked this pull request as ready for review October 20, 2023 21:10
@pr2502
Copy link
Owner Author

pr2502 commented Oct 20, 2023

I consider this mergeable now, if you want to test it again you're welcome, I'll wait a few days anyway. I've changed the exact protocol again, a working configuration example is in examples/neovim/init.lua now.

Also I'd like to figure out how to test the examples (at least that they successfully connect) in CI so I don't forget to update them when/if something changes again.

@pr2502 pr2502 requested a review from WhyNotHugo October 21, 2023 14:47
Copy link
Contributor

@WhyNotHugo WhyNotHugo left a comment

Choose a reason for hiding this comment

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

Seems to work fine with the same neovim setup that I mentioned above.

as the server. This can be overridden using the `--server-path` cli option with
the client subcommand or `RA_MUX_SERVER` environment variable. You can usually
configure one of these in your editor configuration. If both are specified the
cli option overrides the environment variable.
Copy link
Contributor

@WhyNotHugo WhyNotHugo Oct 20, 2023

Choose a reason for hiding this comment

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

... or via the lspMux initialisation options.

(this is non-blocking here tho).

examples/helix/config.toml Outdated Show resolved Hide resolved
examples/neovim/init.lua Outdated Show resolved Hide resolved
@WhyNotHugo
Copy link
Contributor

Seeing this error when neovim tries to connect:

 INFO client{port=48934}: client connected
ERROR client{port=48934}: client error: parse `initialize` request params

Caused by:
    missing field `method`

On 752fe68

@WhyNotHugo
Copy link
Contributor

Never mind the above; I was missing method = "connect", in my config again for some reason. What do you think of making this parameter optional (with default "connect")?

Neovim now prints this error when first connecting to the LSP:

LSP[rust_analyzer] received `end` message with no corresponding `begin`

Everything seems to work okay regardless.

@pr2502
Copy link
Owner Author

pr2502 commented Oct 23, 2023

I wonder where does that error come from because I haven't seen it with the config in this repository.

@pr2502 pr2502 merged commit 1c6857b into main Oct 23, 2023
1 check passed
@pr2502 pr2502 deleted the native-lsp-handshake-2 branch October 23, 2023 19:08
@WhyNotHugo
Copy link
Contributor

WhyNotHugo commented Oct 23, 2023

I'll debug that error when I have some spare time. It's harmless, apparently. Thanks for implementing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants