emacs-lsp / lsp-mode

Emacs client/library for the Language Server Protocol
https://emacs-lsp.github.io/lsp-mode
GNU General Public License v3.0
4.79k stars 890 forks source link

Feature request: convenient way for users to set config generically #3686

Open michaelpj opened 2 years ago

michaelpj commented 2 years ago

We have defcustom-lsp, which is great. However, it has two problems:

  1. The server can be ahead of the client. This is pretty common: I'm not reactive enough to add new defcustom-lsps to the client as soon as they're available in the server. So then users can't set those options easily.
  2. The server can be behind the client. This is less common, but potentially problematic. If I do add new options to the client, but someone is using an old server with different options, they can have problems.

It would be nice if there was a convenient way to set "generic" config options for a server. Maybe there already is, and it just needs to be documented, but ultimately they just need a way to set key-value options for a server.

That would solve both problems: users can set the options that they know make sense for the server they're using, even if our client code doesn't expose them nicely.

yyoncho commented 2 years ago

The server can be ahead of the client. This is pretty common: I'm not reactive enough to add new defcustom-lsps to the client as soon as they're available in the server. So then users can't set those options easily.

That works:

(lsp-register-custom-settings '(("key" "literal-value")))

It would be nice if there was a convenient way to set "generic" config options for a server. Maybe there already is, and it just needs to be documented, but ultimately they just need a way to set key-value options for a server.

That is a request against lsp protocol. It was suggested in the past but I am not sure what was the outcome.

michaelpj commented 2 years ago

That works:

Okay, then maybe this is just a documentation request. I can try and put something together.

That is a request against lsp protocol. It was suggested in the past but I am not sure what was the outcome.

I think I'm mis-communicating: I don't want to set options that the server doesn't understand, I just want to be able to let the user easily shove in whatever configuration they happen to know makes sense.

yyoncho commented 2 years ago

I think I'm mis-communicating: I don't want to set options that the server doesn't understand, I just want to be able to let the user easily shove in whatever configuration they happen to know makes sense.

I don't understand - how can we do that without server cooperation?

michaelpj commented 2 years ago

I think you've already told me how to do what I want to do :)

The problem is: the server supports some configuration haskell.foo.bar, but I haven't written a defcustom-lsp for that, so the user wants to set it themselves, which is what the code you gave does, I think. So the server does support it, we just don't have a nice facade for it yet.

In the limit, you could imagine something like VSCode's settings.json where the user can really write a big structured object and get it forwarded to the server.

yyoncho commented 2 years ago

In the limit, you could imagine something like VSCode's settings.json where the user can really write a big structured object and get it forwarded to the server.

I havent tested it, but generally, you may register a shorter path and pass a map object and it will be sent to the server(that way you can pass all paths in one object). As a side note, I am planning to support settings.json.

michaelpj commented 2 years ago

I havent tested it, but generally, you may register a shorter path and pass a map object and it will be sent to the server

What happens if you have conflicting settings? e.g. if I set an object for foo and then a value for foo.bar?

yyoncho commented 2 years ago

I havent tested it, but generally, you may register a shorter path and pass a map object and it will be sent to the server

What happens if you have conflicting settings? e.g. if I set an object for foo and then a value for foo.bar?

That is what I haven't tested :)

apodolsk commented 2 months ago

Chiming in to second the request. I'm switching to lsp-mode because it solves a lot of my small eglot gripes, but I'm really feeling the absence of eglot's first-class ad-hoc LSP configuration support (https://www.gnu.org/software/emacs/manual/html_node/eglot/Project_002dspecific-configuration.html).

I think the rust-analyzer integration is a good example of the set of "blessed" vars lagging behind the implementation. There are some IMO must-have options ("don't make rust-analyzer contend on a directory lock with actual compilation"; "don't spit out a bunch of dead code warnings for your WIP project") which don't currently have pre-packaged support.

Interestingly, it seems that there's currently a mix of missing features that makes it impossible to set config generically for rust-analyzer in particular. I described my amateur investigation at https://github.com/emacs-lsp/lsp-mode/issues/4506, but tl;dr is that I think rust-analyzer requires currently-unimplemented workspace/configuration support for lsp--set-configuration to work, and lsp-rust.el seems to just ignore the lsp-register-custom-settings setup in favor of its own settings code when setting up rust-analyzer initial params.

Point of that is to say that if ad-hoc config isn't a first class documented feature, I guess it's not just hard for people to figure out how to do it, it's also hard for lsp-mode to actually keep the feature working in the first place.

mrkajetanp commented 1 month ago

As a side note, I am planning to support settings.json

I'm interested as well, any updates on this? Particularly an equivalent for eglot's Project-specific configuration mentioned by @apodolsk would be great, any other editor I tried has that and the absence makes lsp-mode effectively unusable for certain projects which just don't work without custom setup.

quasi-coherent commented 2 weeks ago

I'd like to say this is also pretty important to me. Working on many Rust projects with wildly different properties and no easy way to define ideal settings custom to each is kind of tough to accept (e.g., the default lsp settings might not do anything at, or it might build the entire world every time, or it can do anything in between). I know this is a "me" problem, but I haven't figured out how I can use a .dir-locals right now -- I use emacs via nix home-manager and it seems it wants to change some file in the nix store and that's prohibited. Until I get over that, I've tried to hack something myself but I'm not the best at elisp in any case. I am very good at writing yaml/json though!

For others I guess I'd suggest a .dir-locals.el maybe?