dundalek / lazy-lsp.nvim

Neovim plugin to auto install LSP servers
MIT License
189 stars 11 forks source link

Community curated list of preferred servers? #23

Open dundalek opened 1 year ago

dundalek commented 1 year ago

The philosophy of this plugin is to have as much as possible to work automatically without configuration and only correct when few misbehaving instances. Based on discussion in https://github.com/dundalek/lazy-lsp.nvim/issues/17 people might prefer to sacrifice some lsps if it means being exposed to less potential issues.

Should we curate a list of recommended servers, e.g. pick one server when there are multiple alternatives or exclude known misbehaving ones to reduce number of issues people can run into?

For example I recall nvim-treesitter having ensure_installed that could take value "all" or "maintained" to restrict available grammars. Would it make sense to have something similar? We could have by default a "recommended" selection while providing the option to opt-in to all servers (which is the current default).

dundalek commented 3 months ago

A possible next step would be to auto-generate list of servers similarly to servers.md but grouped by the filetype that would provide a better overview of which ones can be chosen.

JoakimPaulsson commented 3 months ago

An approach would be to have like a priority queue of LSPs for each ft. If one fails for some reason, try next available one.

Could also cache the LSP that worked and start with that LSP next time.

Pros:

Cons:

dundalek commented 3 months ago

I've created a script to generate a list of filetypes associated with multiple servers to serve as candidates for curation.

I would be interested for people to share (we already have some examples):

dundalek commented 3 months ago

I'm thinking next step could be to add the recommended options as a starting point to the configuration example in the README.

fdietze commented 3 months ago

Just opened a typescript file and was overwhelmed by all those language servers that started up :laughing: . It made me realize that language-servers and formatters are project specific. No community curated list will work for actively developing a project. In some project I want to have specific ones in another project I need others. For example npm vs deno typscript projects. Having all language servers or a list of community generated ones is wrong for projects one actively works on, instead the lsps should be already in scope using tools like nix-shell/flakes/devbox/flox etc .

On the other hand, browsing unknown projects is an important use-case as well. And in this case, a community curated list of lsps lazily started in a nix-shell would be great. So one probably wants to start language-servers for out-of-project files on demand: Have a keybinding/commad, which fires up the community curated language-servers for the current file.

dundalek commented 3 months ago

Just opened a typescript file and was overwhelmed by all those language servers that started up 😆 .

Yeah, JS/TS is a bit wild by default, but it is also an exception because the ecosystem is so large and diverse.

Having all language servers or a list of community generated ones is wrong for projects one actively works on, instead the lsps should be already in scope using tools like nix-shell/flakes/devbox/flox etc .

This gives me an idea that it would be possible to automatically enable only LSPs that are installed. But on the second thought if that is desired one can just write a for loop in config so there is no need to have a plugin for that.


In conclusion, after running the stats I see these patterns: 1) modern languages (like Go, Rust, Kotlin, Elixir, Zig) have one official implementation - no issue here 2) previous generation languages (like Python, Java, PHP, Ruby) have multiple efforts, but over time some get deprecated and will likely also consolidate towards one - we can run multiple ones for redundancy and in the future reduce suggestion 3) JS/TS is a special category, but suggesting eslint and tsserver should work for majority by default. If not it can be configured based on specific needs.

dundalek commented 3 months ago

I've created an initial curated configuration: https://github.com/dundalek/lazy-lsp.nvim/blob/master/servers.md#curated-servers

The downside is one needs to copy it to their config. I think I would be comfortable by enabling this subset by default.

However, the challenge is then how to expose the options to override these in case someone wants a server that was excluded. And how not to make it confusing how to find out which servers are enabled and which are not.

@zoriya I would be curious if you have any thoughts?

zoriya commented 3 months ago

I think excluding archived servers by default is a sane default, I don't like the idea of excluding lps to prefer another one. So

{
    "ccls",                            -- prefer clangd
    "denols",                          -- prefer eslint and tsserver
    "docker_compose_language_service", -- yamlls should be enough?
    "flow",                            -- prefer eslint and tsserver
}

feels wrong to me. I would think that having those in preferred_servers would be better. Users could then override the preferred_servers section in their own config if they want to use something else instead.

For reference, this is my exclude/preferred config:

excluded_servers = {
    -- Disable generic purpose LSP that I don't care about.
    "efm",
    "diagnosticls",
    -- Bugged servers
    "sqls",
    "rome",
},
prefer_local = true,
preferred_servers = {
    haskell = { "hls" },
    rust = { "rust_analyzer" },
    c = { "clangd" },
    cpp = { "clangd" },
    cs = { "omnisharp" },
    python = { "pyright" },
    nix = { "nil_ls" },
    typescript = { "tsserver" },
    javascript = { "tsserver" },
    jsx = { "tsserver" },
    tsx = { "tsserver" },
    javascriptreact = { "tsserver" },
    typescriptreact = { "tsserver" },
    go = { "gopls" },
    json = { "jsonls" },
    yaml = { "yamlls" },
},
dundalek commented 3 months ago

That's a good point, if the default curation is only done using preferred_servers than it is straighforward to override just by merging tables.

The thing I don't like is the duplication since js/ts is spread over 6 filetypes and for example ccls is part of 5 filetypes.

-- Bugged servers "sqls", "rome",

BTW these were dropped from nixpkgs, you can remove them for a cleaner config.

zoriya commented 3 months ago

I think it is okay to have multiples file types for the same lsp. For the case of ccls, I could want to override the objc lsp while keeping the cpp's lsp to the community curated one.

I do agree that JS cases is weird, but that's just to show how much the JS community is split. I see two ways of handling that:

I do think the second one is both simpler to write and simpler to understand, as you do not need to know lazy-lsp does some kind of magic for js.

fdietze commented 3 months ago

This gives me an idea that it would be possible to automatically enable only LSPs that are installed. But on the second thought if that is desired one can just write a for loop in config so there is no need to have a plugin for that.

I even implemented this quickly for myself, so that every installed server is automatically picked up. This felt good at first because I was working on my own project, where I know the tooling.

But opening another project sent me into this rabbit hole of deciding which language server to install. And here, the community curated preferences would be awesome.

So somehow I want community curated lsps everywhere except for projects where I explicitly want to make a choice. VSCode has some project-local configs, where they list recommended extensions. Maybe a similar standard for vim makes sense. Or even better an editor-independent standard for defining, lsps, formatters, linters etc for the project.

dundalek commented 3 months ago

I recently learned about the lspconfig autostart options (which is by default true).

Another idea for curation would be to not exclude some servers from setup completely, but instead set autostart to false, so they are not started automatically (which solves the problem of being overwhelmed with too many servers), but the user could start them manually using :LspStart when being inside a specific file.

An example is ltex (grammar checking for markdown), which is quite heavy on CPU, but it is still useful to have ability to start it manually.