Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork6.5k
Lean LSP/IDE setup#36962
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
Lean LSP/IDE setup
I still remember my initial confusion and hopelessness with setting up IDE features when I switched to Neovim (back at v0.10). And things are better now. There are good guides on YouTube for the current state of things:v0.11+ (uses Lazy plugin manager) andv0.12 (requires However, if things were that easy, you could just copy-paste some config without even watching a video. Here I hope to provide more context for each aspect of LSP/IDE setup, focusing on doing more with less dependencies. Please consider it an attempt to help, not a definitive guide on how one should set up their work environment. Installing a serverFor most servers, there are several options:
I strongly recommend using the first two options, unless:
There is nothing wrong with Mason, it's a great tool. But I haven't seen a single config that would not become a maze. There always comes the need for Just keep in mind that all you actually need is a binary for your server, either on Configuring LSPFirst of all, there is the magnificentnvim-lspconfig which provides sensible defaults. You may have seen older configs that have elaborate setups around this plugin. As of 2025, you just install the plugin, no setup needed, and all it does is provide configs from itslsp/ folder. You could also copy configs from those files right into your own For example, if I choose to install the plugin after all, it will provide this from its own ---@typevim.lsp.Configreturn {cmd= {"typos-lsp"},root_markers= {"typos.toml","_typos.toml",".typos.toml","pyproject.toml","Cargo.toml", }} Then I can add some options into my ---@typevim.lsp.Configreturn {init_options= {diagnosticSeverity="Hint", }} And add even more settings inline: ---"*" stands for "all LSPs"vim.lsp.config("*", {capabilities=require("blink.cmp").get_lsp_capabilities({},true),}) Enabling LSPDon't forget to enable LSP(s). ---after vim.lsp.config()vim.lsp.enable("typos_lsp")vim.lsp.enable({"ts_ls","rust_analyzer"}) Using LSPMany things are already enabled by default. See These GLOBAL keymaps are created unconditionally when Nvim starts:- "grn" is mapped in Normal mode to|vim.lsp.buf.rename()|- "gra" is mapped in Normal and Visual mode to|vim.lsp.buf.code_action()|- "grr" is mapped in Normal mode to|vim.lsp.buf.references()|- "gri" is mapped in Normal mode to|vim.lsp.buf.implementation()|- "grt" is mapped in Normal mode to|vim.lsp.buf.type_definition()|- "gO" is mapped in Normal mode to|vim.lsp.buf.document_symbol()|-CTRL-S is mapped in Insert mode to|vim.lsp.buf.signature_help()| If you plan on using native completion, you may want to map it to something more convenient: vim.keymap.set("i","<C-Space>","<C-x><C-o>") There are other useful things like Fixing LSP
Before debugging further and asking for help, at the very least you need to know the answer to:
Additional IDE featuresCompletion and snippetsNative completion becomes more and more powerful. I believe, one day it will have everything you need and more. Until then,blink.cmp is probably the most sensible option. It covers some edge cases withsnippet expansion anddynamic completions; and delivers many quality-of-life features on top of that. By default, it provides snippet support through native FormattingMany LSPs come with built-in formatters. For those that don't, you could useconform.nvim or DIY it. DIY exampleIf the formatter has no vim.api.nvim_create_autocmd("BufWritePre", {callback=function(args)---It's a good idea to have a manual toggleifvim.g.u_manual_formattingthenreturnendlocalfiletype=vim.bo[args.buf].filetypelocalfilepath=vim.api.nvim_buf_get_name(args.buf)localcmd=nil---Don't be confused by passing the path to the file.---It's just a convenient way for prettier to know which---parser to use. We will pass actual lines later.iffiletype=="html"thencmd= {"prettier","--stdin-filepath",filepath }elseiffiletype=="json"thencmd= {"prettier","--stdin-filepath",filepath,"--trailing-comma","none"}elsereturnend---Gather lines and call formatter synchronously (max 500 ms delay).locallines=vim.api.nvim_buf_get_lines(args.buf,0,-1,false)localresult=vim.system(cmd, {text=true,stdin=lines }):wait(500)---Typically, as other tools, formatters return code 0 for "success"ifresult.code~=0thenvim.notify(result.code.."/"..result.signal..":"..result.stderr,vim.log.levels.WARN )returnend---Split output back into lineslines=vim.split(result.stdout,"\n")---Optionally trim leading empty lineswhile#lines>0andlines[1]==""dotable.remove(lines,1)end---Optionally trim trailing empty lineswhile#lines>0andlines[#lines]==""dotable.remove(lines)end---Replace buffer content with formatted linesvim.api.nvim_buf_set_lines(args.buf,0,-1,false,lines)end,}) LintingMany LSPs come with built-in linters. For those that don't, you could usenvim-lint. I won't encourage you to DIY it because many linters have uniquely structured outputs, and you will have to parse that output into Neovim diagnostics format, which is tedious. DebuggingAlthough I don't use any interactive debugger myself, I just know that the answer isnvim-dap. |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
Replies: 2 comments 8 replies
-
Great guide, but wanted to point out some important detail about Mason:
True, usually configs end up being a mess. But that's just because people don't know what they are doing (even the people "teaching" how to setup an ls). Mason just installs the servers and no other plugin is needed. You do need to add mason's directory to the path with one line: vim.env.PATH=vim.fn.stdpath('data')..'/mason/bin'.. (vim.fn.has('win32')~=0and';'or':')..vim.env.PATH and then you can use the servers. All other plugins just make "easier" to enable ls, as they do it automatically. But I agree with you that with the new interface you should just do As for using Mason or not, there are other important points when Mason is preferable:
Finally, builtin completion works with snippets, neovim has a builtin snippet engine: |
BetaWas this translation helpful?Give feedback.
All reactions
-
If I set If you have ways to solve those issues, I will accept that I was wrong about native completions. Otherwise, its state doesn't seem mature enough to recommend it. Although the following didn't form my opinion on the topic, you can also watch a person struggle with completions in a more entertaining form:https://youtu.be/tnlgQFQi2s4?si=UcrO1nCLwWrMUryh. Sure we can create a wrapper for each edge case with |
BetaWas this translation helpful?Give feedback.
All reactions
-
I haven't write rust in a while, so I just open an old project and tested what's mentioned in#36823. As you can see, I don't have the same issue: ![]() Afaik I don't have anything weird in my setup, so maybe it's something that has been fixed in nightly recently but not in the latest stable. I have never experienced something like that with the ls I use. In any case, if there is any bug it's a good idea to post as an issue so that the team can fix it. As for the video: these are the issues he had:
I mean, it's a wrapper of just 10 lines of code, not that you need to maintain a 1k monster. But it's just a simple solution if you want to use custom snippets. As I said, there are plugins for that too. Taking all into account, my whole native completion setup is shorter than your (blink config)[https://github.com/shushtain/dot/blob/main/nvim/.config/nvim/lua/plugins/blink.lua] (and would be the same amount of lines if I added docs), so I don't think it's too complicated to use native. Yes, as I said before, it has some limitations, and if you are not ok with those limitations there are plugins like blink that offer a lot more. My only comment was that "builtin completion works with snippets", as the original post (before editing) seemed to mention that it wasn't the case ("it adds missing snippet engine"). To be clear, I have never said "builtin is better than a plugin" or something like that. I just said that "Agree plugins offer more capabilities, but you can just use the builtin if you like what it offers.". Both are good options and you should use whatever offers what you want or need. |
BetaWas this translation helpful?Give feedback.
All reactions
-
If you are on nightly, then what are we even talking about? I'm glad you don't have the same issues, but they are still reproducible in v0.11.5, and I don't have enough skills to debug them on my own. As mentioned at the top of the post, the guide is mostly for v0.11.5. The reason I encourage people to install servers and write formatting recipes on their own is because it demystifies LSP instead of hiding useful settings. For example, Debugging LSP requests, however, is not something I wish upon new users, especially since it could indeed be solved already in v0.12. So, again, I won't change my recommendation in this case, unless at least those mentioned issues are solved.
|
BetaWas this translation helpful?Give feedback.
All reactions
-
Sorry, I didn't know nightly users can't comment on github. Just wanted to comment one little thing. You said:
And you shared a lengthy autocmd to show how to write that recipe. That's great! Sad that you consider then
when the snippets wrapper is literally 10 loc. Why writing your own recipe for formatting is worth but not for snippets?
I have never had to debug any LSP request. If I have a bug, I report it, and let the people that knows to fix it. Funny how I just said "builtin completion works with snippets, neovim has a builtin snippet engine." to end up being borbarded with problems with "docs, snippets/ folder support, cmd and terminal completion, ghost text suggestions", none of them go against what I previously stated which is objetively true. And funny enough none of that (except snippets/ folder support) has anything to do with snippets. But hey, it's your guide and I just wanted to give some input. And I repeat: "Great guide". |
BetaWas this translation helpful?Give feedback.
All reactions
-
So, the course of events: I wrote that native snippet expansion is problematic (but in a nicer form). You replied that it works 100%. I showed you the issues. You said you can't reproduce themin a different version of the program. What should I do with that information? Thank you for your input, I guess. I spent some time reproducing all the mentioned issues, just to make sure I'm not that dumb... I did make useful corrections based on your comments about "the engine". But you must understand that nightly and stable experiences are different. That's why I said that one day native completion will be better than anything we have so far, because it moves in the right direction. However, I can't ignore the existing issues, even if they are solved in nightly. I'm not writing docs for 10 years, I'm creating a snapshot of opinionated recommendations for specific version at this specific moment. Is that okay? And I did explain why writing custom "format on save" is valuable. Because you learn tools you can use from anywhere. You learn to format JSON from shell after generating it in any program. The same with setting up all LSP config fields: you learn you can set up any LSP server, even if When you write a wrapper to see docs, to gather snippets, to fix bugs with completion filtering, you still learn something. But those are editor-specific skills. Not all APIs are created equal. Feel free to make your own guide on writing a lean completion setup that covers the gaps. Lastly, no matter how much you speculate about the length of my dotfiles, I believe we are done talking about anything substantial. Goodbye. |
BetaWas this translation helpful?Give feedback.
All reactions
-
Nice setup! If you are on nvim 0.11 or newer you no longer need to call ---"*" stands for "all LSPs"vim.lsp.config("*", {capabilities=require("blink.cmp").get_lsp_capabilities({},true),}) as blinkcalls it for you |
BetaWas this translation helpful?Give feedback.
All reactions
👍 1
-
Thanks! I didn't know that. |
BetaWas this translation helpful?Give feedback.
