nushell/vscode-nushell-lang

Standalone LSP Server in Rust

schrieveslaach opened this issue ยท 26 comments

I came across this repo based on the announcement in Nu's changelog blog and I was keen to integrate that into my Neovim setup. However, I noticed that the LSP Server is integrated into this plugin and is based on Javascript.

I'm and others (see here) not a fan of tooling written in Javascript. Therefore, I'm wondering if it is possible to create a standalone LSP, written with the aid of lsp_server or tower-lsp, in its own repo.

Hey @schrieveslaach. We took the quickest route to get to something that provides more functionality than we currently have. I, for one, would love to see a standalone LSP, like you've mentioned. I kind of see this as a steppingstone to that. I am not well versed in LSPs, so I'd have to rely on others to lead the way but we'd welcome it.

This morning I was thinking about it and I was wondering if Nushell itself should provide an LSP backend. Maybe some sub command, such as nu language-server or something like that.

I'm imaging if this is provided and I use ctrl+o (opens your editor of choice to edit line input) my editor could start nu language-server --use-current-scope to get completions that take the current scope into account. For example, if I defined a new variable in the scope that pointed to a file and after that I typed ls into the terminal, it would be really great if the editor can suggest the variable as an argument to the ls command.

@fdncred, what do you think of integrating a language server into Nushell itself?

I think the dataframe support was removed from nu itself by default due to payload size

On my system, nu is already 50MB compared to 2MB for bash, so having a full-blown LSP implementation might bloat the binary again

That said, it's also possible that there's so much shared code between normal usage of nu and the LSP (parser, etc) that wrapping an HTTP service around it doesn't actually add much more to the final payload ๐Ÿคท

@schrieveslaach I think having a stand-alone LSP is a good idea and I'd like to see it.

@jokeyrhyme dataframe support wasn't removed from nushell, it's feature-gated now, so, only the people who want it can compile/install with it.

@fdncred that's exactly what I said

dataframe support was removed from nu itself by default

FWIW this is also blocking us from adding the nu LSP to Zed. I might take a crack at helping out at some later point :)

FWIW this is also blocking us from adding the nu LSP to Zed. I might take a crack at helping out at some later point :)

We'd love to have your help @mikayla-maki. We're currently using a LSP-lite strategy by calling into nushell with --ide-blah parameters. Zed could use this strategy as well, but it sounds like it's not what you're looking for.

Oh, so your server is implemented in nu itself? That's pretty sweet. Does that mean we just have to write a little wrapper for forwarding the LSP messages to the nu command?

Ooh, that does seem to be how it's implemented ๐Ÿ‘€ https://github.com/nushell/vscode-nushell-lang/blob/main/server/src/server.ts#L259-L277, very cool! I might try to do that tomorrow then, it's not too dissimilar from a side project I'm working on :)

yup, if you do nu --help, you'll see 5 or so --ide-something parameters. Those were all written to support our vscode integration, but it just spits out json, so it should be pretty easy to consume.

@fdncred, if the CLI options are already present, it should be possible to add an LSP crate on top of it. Or am I missing something?

I think it's just a case of there being so much work to do and only so many maintainers/volunteers

On the plus side, there's a decent amount of prior art, including this: https://github.com/IWANABETHATGUY/tower-lsp-boilerplate

@fdncred, if the CLI options are already present, it should be possible to add an LSP crate on top of it. Or am I missing something?

No, you're not missing anything really. I'm not sure our --ide-blah parameters exactly match to any LSP as I've never written an LSP. I think @jokeyrhyme is right about maintainers and time. There's also a component of, "I love to write X so I'm going to keep writing X and not Y". Open source is that way, of course.

We're definitely up for someone taking this code and building an LSP into nushell and I'm sure we'd help with it.

In fact, I was studying this code yesterday thinking the same things we're talking about. https://github.com/microsoft/qsharp/tree/main/language_service

This is really ugly code to start with, but I have hover working and should have the rest working over the next couple of hours/days depending on unexpected distractions: https://github.com/jokeyrhyme/nuls

Very happy to accept contributions, and also to donate this to the nushell project should the official folks want it

@jokeyrhyme This is cool. Can you list some steps to try things out in vscode? :)

Yeah, it needs a README

I've been testing it with https://helix-editor.com/ where you only have to give the editor the path to the language server executable and everything just works

I'll see if I can figure out VSCode

Okay, it's weirdly quite a bit more involved to get VSCode working

It'll probably have to be a fork of this extension, or a new extension: https://code.visualstudio.com/api/language-extensions/language-server-extension-guide

I've updated the README.md: https://github.com/jokeyrhyme/nuls#readme

There's a whole bunch of other stuff to do, so I won't be focusing on getting nuls working with Visual Studio Code for now (you already have this extension) :)

Eventually, someone (maybe me) will raise a PR against this official Visual Studio Code extension to make it use nuls instead directly calling nu --ide-...

Thanks for updating it and the info!

Looking forward to integrating nuls once it's ready @jokeyrhyme! :D

I wonder if it's better to have separate nu and nuls executables or if nuls should be integrated into the nu binary?

Yeah, I do wonder about this, having it all in one executable could be one way to do it

Alternatively, it might eventually be appropriate to have an architecture similar to rustc versus rust-analyzer, where there might be some code that is shared between them, some functionality that is implemented differently to optimise for interactivity, and some functionality that is definitely only in one and not the other

For example, the language server has a JSONRPC implementation and often a TCP server, things that might not be useful to most users of nu (and might never be in the feature set of nu), whilst nu can actually execute/evaluate code which is something the language server might never need to do

It probably also depends on how large the nu executable is allowed to become?

I'm just guessing, but the way it's implemented now, you have to have both of them anyway. So, why not put them together. Plus, if they're together, it's more responsive because you don't have to shell out to call nushell with parameters, you could just call those functions directly. I'm fine with this continuing on as is but I think eventually, we may want to merge them together. Perhaps adding this as a nuls crate in nushell?

I definitely do want to explore having the language server import/use the Rust code from nushell directly rather than starting a new process over and over

It'd also mean being able to bypass the current round-trip through JSON

I also thought about writing the language server in the nushell language itself, which would be kinda' awesome :)

I also thought about writing the language server in the nushell language itself, which would be kinda' awesome :)

LOL! That would be awesome!