Understanding Neovim #7 - Language Server Protocol

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] how dear everybody and welcome to episode 7 it's finally time that we start discussing the elephant in the room the thing that most people have been waiting for let's discuss LSP this episode is going to be broken down into many smaller subsections there's so much to cover with how LSPs work and all of the intricacies that we can't cover all of this in one episode or else this episode would be at least an hour long so in this episod epis we are going to cover three distinct things the first thing is we are going to discuss the theory the basics of why LSP exists and what sort of problems it is designed to solve the second thing we'll look at is how we can quote unquote enable LSP support within neovim using the envm LSP config package and then at the end we are going to install an LSP using our system package manager and we are then going to utilize that LSP within new then in a completely separate episode we are going to look into Mason Mason is going to allow us to automate the installation of LSP servers and from then on we are going to discuss how to customize your LSP experience and how to make it just a bit nicer for you so let's start off with the basics what is LSP and what sort of problems are we trying to solve here now LSP stands for the language server protocol and what this means is that by definition it is a communication protocol it's supposed to be some sort of unified message syntax in a way where we can communicate from a client to a server and no matter what sort of server you have or what sort of client you have both of these will be able to communicate with each other because they're using the same underlying format for messages now a language server is a server that can take in some input like a file I'm going to use rust as an example here we can send over a rust file to a language server and what the language server is going to do is it's going to analyze our rust file and it's going to look for many different things inside for instance it's going to look for errors in our code we used an incorrect type somewhere or we misspelled a variable name it's going to find errors of that nature and then on the other side of the spectrum we have warnings we have instruction on how to format the file and then on the other other side of the spectrum we have things like code actions so for example you can run a code action and the language server can say oh I can generate this function for you for example or I can create some basic type definitions for you so a language server is a tool specifically for programmers for us who write code we would love to see warnings and errors about our code it would be awesome if we could have a language server that does this now the issue that LSP is trying to solve is imagine you have five editors side by side completely different editors and they all open up the same rust documents back before LSP existed every single one of those editors would have had to implement their own sort of schema for detecting errors in files and providing code actions and all of that everybody had a different way of doing it but with LSP if all of those five editors Implement an LSP client they can all communicate with the same server and the same server is going to produce the same sorts of Errors the same sort of warnings the word server might be a bit confusing to some of you does this mean that I'm going to have to connect to the internet like am I sending my code over the internet to some sort of server no absolutely not a server is something that can produce information for other people to consume that's where the word comes from right it's supposed to serve data but that doesn't mean it's somewhere online on the web in our case an LSP server is simply an application that runs on our computer it's completely local it runs on our computer and in our case neovim is going to connect to this server and is then going to Simply communicate with and you may be asking yourself now what's exactly the difference between treca and LSP in that case so treca as I alluded to in the past episodes and as I explained is simply a passing Library it's supposed to take your files and convert them into something meaningful but the job of an LSP is much more complex and much deeper instead of just finding basic errors in your code like oh you missed a bracket or oh you missed a curly brace the job of an LSP is to actually look into the semantics of your code so not just at a surface level the structure but it's supposed to look at the behaviors of your code and catch behavioral errors not syntactical errors at a basic level what this means is Tre at best can only find syntax errors it can only find as I said a missing bracket a missing curly brace however an LSP can find deeper things like a misspelled variable an unused function an incorrect type its job is to Aid you in the development experience okay so fantastic we have this LSP this language server protocol which allows any amount of editors to communicate with a single language server and that server can then do all of the magic it can read your code and it can produce errors produce warnings uh that the developer can then see in their own text editor instance this is great but how does this practically translate over into neovim how does this work within Newen similarly to the treer implementation the LSP client implementation has been here the whole time it's embedded within new of them we have to awaken this functionality uh with the help of something like LSP config the job of a LSP client is to be able to communicate with a server right that should make sense what this means is say you for example hover over a function with your cursor and you press go to definition right you press a keybind which takes you to the definition of a function what the client then does is it recognizes that you're trying to go to the definition and then it sends a request over to the server and it asks the server hey I have this function where is the definition of this function the server then does its magic and it sends back a response saying oh it's in this file at this position and then the LSP client translates that back over to some sort of physical action in Nim's case this means opening up that specific file at that specific line and that's how go-to definition would work and one last thing left every programming language is different right so similarly to trees which needs a special passer for every single programming language that exists the same thing goes for LSP you need a custom LSP server for a specific language there's a specific LSP server for rust a specific LSP server for typescript and the list goes on so with that theoretical introduction out of the way let's now hop on over into new ofm and see what we can conjure up with this new information okay so let's open up our beloved newm that we've been working on for the past six episodes and the first thing I'd like to show you is that I'm not lying LSP has been here the whole time so treer was packaged in a table called vm. treer in our case LSP is packaged in can you guess it vm. LSP so here's the code uh that would print out the contents of the vm. LSP table as a recap vm. prints allows us to print complex tables and display what's inside of them and we need to use this L command in order to execute some sort of lure this is an operation that you will do quite often so there is a Shand for this within ovim and that is simply the equals sign command so I can type equals vm. LSP and this is the equivalent to what I had earlier this is the equivalent of running lure vm. prints vm. LSP I can hit enter and indeed you can see that the whole client implement ation is already here within newm without installing any sort of plugins and if you scroll down a bit you can see that there's quite a few functions that can operate on buffers and the job of most of these functions is to provide the default behavior that you would expect from an LSP client stuff like hovering over a function that means displaying its documentation going to the implementation of a function renaming a variable all of this stuff is essentially already implemented and ready to go within new of them there's quite a lot in here and you're not supposed to know any of this I'm showing you this cuz I want to show you that that all of this stuff isn't Magic all of this stuff has a physical function or an implementation behind the scenes that does the specific thing that we'd like to do so I'm going to do something in this episode that I don't believe any other tutorial has ever done we are not going to install any sort of helper libraries what we're going to do is we are going to set up an LSP server the hard way we're going to do it the manual way and hopefully through this you're going to learn a load and after that once we do it the manual way you'll immediately understand why the LSP config plugin exists and why it's supposed to make our life easier and in what ways it makes our life easier in order to actually run an LSP server we need some sort of LSP server to begin with so the language server that I would like to set up manually in this episode is going to be clang D now clang D is the name of the language server for the C and C++ programming languages and you might be asking out of all of the possible languages that we could be installing a language server for why specifically this one well first of all it is the easiest for beginners and here's why clang D is essentially the best possible implementation of an LSP server some LSP servers break the rules of the language server protocol they kind of do their own little thing whereas clang D is very very faithful to the original specification so there won't be random errors or weird Oddities that we would have to handle ourselves manually additionally C is a language almost all of you should know it's the most basic language that people learn when they start off with computer science and even if you don't know C don't worry we're only going to be writing some very basic programs in order to demonstrate how LSP works so over at clang d. lm.org installation we have the getting started page for the clang D language server now if you'd like to install clang D permanently on your system feel free to follow the installing with a package manager guides here on Mac OS it's as simple as Brew installing on Windows you need to run the installer on d/ you B to you need to run the install command it's generally very easy to get clang deinstalled on your system just so we're all on the same page and just so there's absolutely no possibility for anything to go wrong we're going to install the Standalone dotzip releases now these Standalone releases are simply the binaries packaged with a zip file this means we can download the zip file to a single location every single one of us no matter what operating system we're on and then we can simply point the new to that binary specifically and this just ensures that everybody is absolutely on the same page here and there's no chance that I'm going to get comments saying oh this installation method didn't work on my machine as long as you just get the zip release over here everything should perfectly work so select the operating system of your choice I'm on Linux so I'm going to hit clang D- Linux and it's asking me to save the file so let's save it the next thing that I'm going to do is I'm going to move the zip file over to my home directory and then what I'm going to do is in my home directory I'm going to unzip this zip file into a directory which I'm going to call clang D at the end of this episode we are going to remove this ZIP file I'm showing you all of this as a demonstration of how the LSP servers work so we're now going to unzip into the clang D directory and inside of clang D I'm going to have a subdirectory called clang dor 17.0.2 that's the version that we pulled from the internet and in here we have a binary folder so we obviously want to go into that and inside here you go here's the clang D binary as I said an LSP server is simply an application that's going to run on our system so it makes sense that we're going to have a clang D binary over here I can even go as far as to run this binary itself and upon hitting enter you can see clang gives us a nice warning saying that it should be used via an editor plug-in rather than being invoked directly but what I'm trying to show you is that this is an application that we can run just like anything else so I'm going to press contrl + C to now terminate the language server and what we now want to do is we now want to point neovim to this language server we want to say I want you to use this for my C files now to do this we are going to use the vm. LSP dostart function this creates a new LSP client and starts a language server of our choice if you're opening the help pages and for some reason you are finding a weird errors cryptic errors there have been a few breaking changes in treer recently so if you just run TS updates it's going to update all of your passes and then hopefully once you restart neovim and reopen the help page for vm. LSP dostart you should no longer get any errors fingers crossed so this function is going to start our language server and we are going to provide a path to this language server using this CMD over here and that's it we don't have to do anything else apart from this so let's try this I'm going to copy over this snippet from the help page but don't worry we are going to be trimming it down quite a bit so you don't have to copy this yourself and in another terminal I'm going to open up myit DOL and just for the sake of testing let's paste down this code snippet so every time we launch newm we are going to attempt to run and start an LSP server now in the name first of all I'd love to change these to double quotation marks that's just my preferred style and in between these we can give a name to our language server so I'm just going to do the most boring thing and I'm going to call the language server clang D now in the CMD this is where things get very important and interesting right because we need this path that we copied over a while back with our clang de installation and we need to paste it in here and of course we don't want to just provide the directory name we want to provide the actual binary name so clang as well and this is where it might differ from operating system to operating system on Linux this path is pretty familiar to anybody who's used Linux before but on Windows this is probably going to be C users your username SL desktop SL clang D and then the rest of the path note that if your clang D installation is for example clang D.E then you should also add the exe at the end here and then down at the bottom we have this root directory root directory is pretty self-explanatory when you think about how programming languages work usually programming languages have a concept of a project a project is a directory where you can stall many different files they can all import each other include each other and that's how you generally build big applications by creating projects in programming languages this root directory is supposed to be some sort of directory that the LSP should treat as the project root and this is the root directory this code I'm not going to explain it all in this episode mostly because these functions aren't actually in the stable release of neoven I'm not going to explain any of these yet cuz you know they might change or something the gist of it is we are looking for a p project. toml or a setup.py now this example that's given in The Help pages is for python as you can see cuz P project right and setup.py are both usually files that denote the roots of a project in Python we don't need any of these because we just want to try out whether the language server even works so we're only going to be testing it on a single file we can completely delete all of this and we can type Vim fn. getcwd which is going to get the current word working directory which new ofm is in you can see the current working directory either by running Echo get CWD or by just running the PWD command which does the exact same thing so make sure all of the commands are set up appropriately save and quit this file and I recommend creating an empty directory which I just called empty and in here we can create a test. C file and inside of this test. C file we can have the most basic C program there is I'm simply defining a main function and then I'm printing hello world to the screen but what you might have noticed is hang on I don't see any LSP completions I don't see anything did it not work let's revisit our configuration okay everything seems like it's fine so why is it that when I enter a test. C file I'm not getting any sort of Diagnostics well this is because of a quirk in the LSP client if you start the client too quickly it's not going to function the way you would expect it to so what we have to do is we have to delay the execution of this start function by a little bit and we can do this using an auto command if you'd like to see what Auto commands are you can look at the help page colon H Auto command and it's going to give you a full-on introduction Auto commands are essentially callbacks that new have been broadcasts throughout the entire editor whenever some sort of event occurs now there are many different events within ym and if you run uh colon H events you can get the whole list of events that new can broadcast when something about the editor changing and as you can see there are a ton of these I can keep scrolling and uh it will be a while before we hit the end so what we want to do is we want to hook into one of these Auto commands we want to listen in on one of now the one we're specifically interested in is the one close to the top the third entry down as of the making of this video it is buff enter buff enter you can see the description here it occurs after entering visiting or switching to a new or existing buffer useful for setting file type options so what we can do is we can say whenever we enter a file and only after we have entered a file and after neovim has fully loaded this file do we actually want to start up our LSP client because when we do it over here we are doing it before neim gets the chance to load all files into memory and load all of the buffers so we're going to use vm. api. enmor creatore Auto command and we're going to listen in to the buff enter event now after this buff enter we need to provide a table and inside of this table we can provide many any uh types of metadata for new of him but we're specifically interested in the Callback and callback is a function that is going to execute once this buff enter event is encountered so after new ofm loads the first file which in our case is going to be test. C it's going to broadcast this event saying oh okay I've loaded this file I'm going to now tell everybody I've entered a buffer and now we can execute this call back to do something after we've entered this buffer and we simply want to delete and paste over the code here so after we've entered the file we want to run vi. LSP dostart now we can save we can go back to the other new instance which has test.c open save and quit reenter the file and would you look at that if you've provided all of your paths correctly you should see this error and this error occurs because print f is not a known function but look at that we've just done something quite incredible we've manually started up a language server now here are some really cool things we can do right out of the gate the first one is is we can hover over the function using v. lp. buff. hover if you hit enter you can see we get a window which shows us it's a function that returns an INT if I just include standard i.h uh up at the top here I can also run this hover function over print F and it's going to give me the whole description of this function so I extracted the print F out into a function called say hello and now over here I can run this function which is vm. LSP dobu dode and if I hit enter on here you can see my cursor now moves from here to the definition of the function which is in this case say hello so we have all of the features that you would expect from a big editor like vs code or Eclipse by using our own fingers and by typing out some code which automatically starts the LSP server over here upon entering a buffer we now have access to all of those features and in fact if you look inside of him. LSP dobu you have quite a lot of functions over here at your disposal that you can play around with if you would like to all of these functions have help pages so you can check them out and see what they do and all of this stuff works in real time so if I remove a character here it's now telling me there's a call to some Undeclared function say hello but you see this is quite problematic isn't it because we had to do all of this to start up LSP server now granted it's not actually that complicated as long as you know the path your LSP server you're actually fine but it gets a bit more complicated what if you want to configure the LSP server in some way you want to change its settings and so on now you have to start playing around a bit with uh all of the different inbuilt options and it gets a bit complicated instead of doing all of this every single time we can have a plugin that does this for us not to mention this buff enter doesn't do any filtering it's going to run this command on any sort of file we will ever enter even files that are not from the C programming language this is going to run clang D for every single file no matter whether it's a C file or not we would like to be able to filter out this stuff and only run clang D whenever we are within a cile or only run a specific language server for a specific language and this is where enfim LSP config comes into play it is a set of Quick Start configurations for the newm LSP and if you scroll down a bit you can see what it allows us to do is actually quite useful it allows us to Simply run LSP config do our language server. setup and that's it so instead of going through all of the hassle that we were going through here manually starting up this server we can simply do LSP config do clang d. setup and that's the equivalent of all of this work and not only that enm LSP config will only launch that language server if you're in a file for that specific language also this root directory detection is going to be different for every language as well like if you recall the example we saw was for python specifically so envm LSP config has all of these configurations set up for you so you don't have to do anything so let us delete this code that was in our init L and let's Now set up automatic LSPs and we can exit out of the test. C file we can also remove this file now completely it doesn't matter whatsoever so let's hop on over into our plugins. lure file and inside of here we are now going to declare a new plugin so you should hopefully know the drill by now we're going to create a new empty table and within this table we are going to take the end part of the URL which is nm/ en- LSP config and we're going to paste it in over here and also before I forget you are also free to delete the zip file as well as the directory that we unpacked clang D in so over here remove clang D and also remove the clang dzip we're not going to need that anymore in this episode so here we are setting nimnim LSP config and we want to supply some sort of configuration for this plugin that makes sense because we are going to want to tell LSP config what sort of LSP servers we would like to set up in the suggested configuration you see that this is what it's telling us to do it's telling us to require LSP config and then after after that simply run LSP config do our server. setup so let's do that let's declare a variable which we are going to call LSP config and we are going to require LSP config in and let's run LSP config dolang d. setup now note we deleted that custom installation of clang D so what we're going to have to do and this is some homework for you is to set up the clang D server globally on your system so you install it using the install instructions on the website and then when it's available globally within your system you'll know it's available globally because in a terminal of your choice you should be able to just run clang D on its own without having to supply any sort of file if you can achieve that if your terminal can see it LSP config can see it as well next thing that we need to do is we need to save we need to quit re-enter newm let lazy install LSP config for us and what we've achieved here is exactly the same as what we did earlier manually now as you saw I have clang d installed because my shell recognizes that there is a clang D command so what I should be able to do is I should be able to enter a random test.c file anywhere type out hello world and the second I hit Escape I should indeed have a fully working language server I'm going to leave the episode here there is still a ton that we have to go through namely keybinds and also automatic installation of language service the homework that I gave you to install clang D is basically optional don't worry if you have errors when installing clang D or if something doesn't go your way in the next episode we are going to look at M now the job of Mason is to automate the installation of these language servers so we don't have to do it ourselves however you can now go ahead and install any sort of language server that you would like if you would like to see what sort of language servers are available for what language if you scroll down in the envm LSP config repository there is a server configurations. MD file and this is a massive long file that describes every language server that is available and usually these language servers are named after the language that they're designed for so if I wanted a language server for rust I could search rust and indeed there is rust analyzer if I wanted something for typescript in that case it's called TS server right if I wanted something for Zig um there is zls Zig language server so you can now find your favorite language install the language server for that specific programming language of your choice and then go over here if I wanted to set up something like the oaml language server if I just click on that it's going to take me to the entry for it and the snippet to enable the language server is right here oaml ls. setup so you can go down here into your config LSP config do paste in the name do setup save enter your favorite languages file and you should have an LSP working for that language I hope that all of these explanations made sense in this video we are going to as I said continue the LSP journey in the next episode where we're going to set up key bindings and that is going to allow us to go to definition by just pressing some keys instead of running the long f. LSP dobu dode function and after we're done with that we are going to set up Mason which is going to automate the installation of all of our language servers so we don't have to go over to these websites and look at every single installation instruction manually thank you so much for watching and I will see you in the next episode ciao
Info
Channel: Vhyrro
Views: 6,967
Rating: undefined out of 5
Keywords: neovim, tutorial, from scratch
Id: HL7b63Hrc8U
Channel Id: undefined
Length: 25min 18sec (1518 seconds)
Published: Sat Jan 27 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.