Doing Real Work with Neovim
You know, I like to think we have fun here. I love showing off cool tools and amazing Neovim configurations so that you can all take inspiration and have fun molding these things for your own needs, whether it's programming, DevOps, writing, whatever. But lately, I've been seeing comments—comments from people who say I'm not actually doing any work. I'm just reconfiguring my tools over and over again. Well, I got a message for you, pal: I do do work. I do do work all the time. So in this video, we're going to configure Neovim as a base level for Ruby on Rails and actually do some work with it. We're going to show off a cool configuration, I'm going to commit some code. This is going to be fun. So let's get into it.
Configuration Overview
Now, quick disclaimer: we're not actually going to make from scratch this Neovim configuration for Ruby on Rails. I'm just going to show off a nice base configuration line by line and kind of give you an explanation as to what's going on, because we already covered configuring Neovim in depth in a series called Neovim for Noobs that exists both on YouTube and on our platform, learn.typecraft.dev. So check out learn.typecraft.dev if you actually want to know more about configuring Neovim in detail. But for today, we're just going to show off a nice base configuration for Ruby on Rails. It's only a few plugins and is really amazing. So let's get into it.
The init.lua and lazy.nvim
So right here I have my Neovim configuration for Ruby on Rails. It lives in .config/nvim, that is the default path for Neovim configuration. So let's look at the file system from here. Now at first you can see that we have two files, well, a file and a directory. The file is called init.lua. Now this is a special file that Lua will look for when it loads up in Neovim. This is part of its default runtime path, and this is going to be one of the first files that Lua is going to try and load.
So what we're actually doing in this file is we install a program called lazy.nvim. lazy.nvim is amazing. It is a package manager for Neovim that has unbelievable features. It has a great UI and it has some really awesome stuff. So check out the repository for more information, but just know that lazy.nvim is how we are installing all of our plugins for Neovim to extend its functionality, and it's amazing. So in this file, we load up lazy.nvim, and then we require two things down here. One of them is a file called vim-options. This is telling Lua to load the vim-options module, and we'll show that off in a second. And then it says require lazy and call the setup function on lazy and pass the plugins module to be set up by lazy. That means lazy is going to look for the plugins module in Lua to load all of the functionality that we're going to add in lazy.nvim for Neovim.
Lua Modules and Plugin Structure
So now let's go to our Lua module, which is another part of the default runtime path of Lua in Neovim, and we can see our very first file here is that vim-options file that we are requiring in our init.lua. Now this is a very basic file. We are just setting some of the more ergonomic Vim things that I like to have in my Neovim configs, basically stuff like setting your tabs to two spaces, making your leader key space, don't use swap files, things like that. Fairly straightforward stuff.
And in our plugins folder in this directory, this is a Lua module that's being loaded by lazy. Now what lazy does is for each file, it's going to concatenate all of the tables that we returned in these files into one big Lua table, and then that is our configuration that lazy uses. So an example here could be in this Catppuccin module, I'm returning a table, and all of these files return a table in Lua, and at the end of the day, lazy.nvim is going to concatenate them all and that is going to be our configuration.
Plugin Breakdown: Catppuccin Theme
So let's check out our configuration. We can see here that we don't really have a lot of plugins because we don't really need a lot of plugins to get a ton of great functionality for Ruby on Rails. The first plugin here is Catppuccin. Let's just go over line by line what's going on here. So we're returning a Lua table as I said before, and within this table we have a few attributes. One attribute, the very first one, is the short URL for the GitHub repository for Catppuccin. Now if we go to the Catppuccin repository, we can see that it is github.com/catppuccin/nvim, and that is what we put up here: catppuccin/nvim. lazy.nvim will know to look for that on GitHub, download the relevant files, etc., etc.
Next up is an attribute called lazy. By default, lazy is true, and we want to set this to be false for Catppuccin because it is an important plugin. It's a color scheme and we want it to be on all the time, not lazy at all. Just load it up immediately with Neovim. We name it Catppuccin, that's something we probably don't need but we're referencing it elsewhere. We can call it anything we want. And the priority is 1,000. Now this means that for every non-lazy plugin, the things with the higher priorities will be loaded first. So Catppuccin is loaded right away. And then at the bottom here, we have a config function that allows us to set some configurations after this plugin has loaded. And in this one, what we want to do is call the vim meta accessor, which Lua exposes some of Vim's APIs to us in the runtime it has in Neovim so that we can call things like color scheme. And so in here what we do is we call vim.cmd.colorscheme catppuccin-mocha. This is the first plugin that we set up here. It's just a color scheme, but it's a good example of what we're doing.
Tree-sitter for Syntax and Oil for Files
Now another very important plugin that we have here is something called Tree-sitter. Tree-sitter is a parsing tool and parsing generator tool that allows us to parse our files and do things with them like give us syntax highlighting in our codebases. Now this is an amazing tool. There's a lot of documentation around Tree-sitter, there's a lot going on here, but what we use it for is to install parsers that will parse our code and give us nice syntax highlighting basically automatically with this autoinstall = true option we have in our configuration function.
Now another really great plugin that's just, you know, something I like to have in almost every single installation of Neovim is oil.lua. Oil is amazing. It's a library that allows you to explore the file system by opening up a window, but also it treats these windows as Neovim buffers so you can do all kinds of cool stuff with your files as if it's a Neovim buffer. Here, let me show you. I set the keymap for this program to be dash. So if I type dash, I am in Oil's interface here. So I have a list of the files in this current directory, and if I want to create a new one, let's say something.lua, I can just do this as if it's a new Neovim buffer. Then if I save this buffer, it asks me if I want to create this file. I hit Y for yes, and then there we go. This is our file. But I actually don't want this file so I'll just delete it, write that, yes to delete. And here we go, back to oil.lua. Oil is amazing.
Fuzzy Finding with Telescope
Another amazing plugin that we need in basically every single Neovim configuration is something called Telescope by TJ DeVries. Telescope is amazing. It allows you to fuzzily find files in your system, to fuzzily grep for strings throughout your whole entire project. It has its own plugin ecosystem. It's unbelievable. Now we set up a few key maps with Telescope. Control-P will find all our files in a system. This is really great, and it will fuzzily find files, so we can just start typing and it'll find files for us. And we also have some other goodies here. We have live grep set to leader fg, so we can search for strings in our system throughout our whole project here. And then the other thing we can do here that's really amazing that I actually have built in, that I don't think I've seen a lot of people do, is use leader leader to call a function called old file. So if I open up a previous file, I can type leader leader and then hit enter to go to oil.lua here. But then if I want to go back to the file I had opened before, I just do leader leader enter, that'll go back to Telescope. Awesome way to just sort of go back and forth between files you have opened.
LSP Setup with Mason and Ruby LSP
Next up is the real meat of this configuration, and it's the meat of basically any configuration. You need LSP support in your Neovim config, and this is how we set it up in this configuration for Ruby on Rails. It's pretty simple, but you need a few plugins to get this working. First of all, you're going to need Mason. Mason is a plugin that allows you to install binaries on your system, and you can open it with the :Mason command. It has a great UI, and you can just install the binaries you want by searching through them. It allows you to install LSPs, debuggers, linters, and formatters. Mason is great and you need it for basically everything.
Next thing we want is mason-lspconfig. It just gives us some more features on top of Mason, and it integrates with the LSP configuration. And then finally, what we want is nvim-lspconfig, which allows us to interface with Neovim's built-in LSP configuration a little bit easier than we would if we were to just, you know, raw dog it and just do it ourselves. It gives us some nice functionality like allowing us to set up our language servers and broadcast the capabilities of all our language servers to all the buffers in Neovim. And so what these three lines do here is it sets up Ruby LSP for all the buffers in Neovim. So Neovim, when it comes across a Ruby file, will use Ruby LSP for its LSP functionality. And again, we install Ruby LSP with Mason. We can see that we have Ruby LSP already installed, otherwise you can just search for it on the screen, hit I to install it, and you're good to go. And at the very bottom here, we have some keymaps set for some of the functionality we want in our LSP functionality. Capital K will show off documentation when we hover over a line. We also have go-to definition, go-to references. We're going to show all this off when we're actually in our project here. We have leader gf, which will call format on a file using the LSP. We have code actions and renaming things through our LSP as well. The LSP config can be pretty complex, but I like to think that I kept it fairly simple for this setup because it's just Ruby LSP.
Completions and Snippets
And then finally, last but not least, we have the actual snippets and completion setup for our Ruby Neovim configuration. This is a pretty crazy setup. I haven't seen a very clean setup for completions and snippets. You're just going to need a lot of different plugins, and all these plugins together, basically what they do is they provide a snippet engine. Some of these plugins actually provide snippets themselves, and together they load up snippets and allow you to display snippets on your screen when you're in a Neovim buffer. Again, we go into a little more detail on this with Neovim for Noobs, so check that out if you're interested in more detail on how this works. And that's basically our configuration.
Live Demo: Exploring a Rails App
So let's see how this works. I can go to a Ruby on Rails project that we're actually working on right now. It's actually a bit of a surprise. I don't even know if I should really tell you guys. Can you just keep it a secret between you and me? Yeah, okay. It's Learn 2.0. That's right. Learn is actually built on Ghost CMS, and what we want to do is move off of Ghost so that we can better control some of the things in our system, in our platform for Learn. So we're making our own Ruby on Rails application. It'll use Ghost as sort of a headless CMS, but our Ruby on Rails app is the thing that we actually work on, and it's going to be amazing.
So let's check out this application and do some stuff and let's just see what our Neovim configuration gives us. So let's open up Neovim. We can do Control-P to open up Telescope, and let's search for, I don't know, models user. So this is our user model right here. We have great syntax highlighting with Tree-sitter. Tree-sitter has a Ruby parser installed and it is highlighting our text right here on the screen. And we have some great LSP functionality. If I go down to this has_many relationship for subscriptions, I can type leader gd and it'll go to the definition of the subscription model. This is really amazing, and it's using Ruby LSP under the hood to get this functionality.
Now, if I go over and hover over subscription, I can type Shift-K or capital K to get documentation on this model. Now with Ruby LSP, we actually also get the schema from the database for this model as well. It's pretty amazing. The next what we can do is find all the references in this project for this model by typing leader gr, that means go to references. And we have all kinds of great stuff here, and it brings up a list of all the files that reference subscription. So that's a nice way to sort of traverse your file system. And then here, if we actually put in an error, let's say we add a space where we shouldn't have, we have our diagnostics coming from Ruby LSP as well, using RuboCop under the hood, which is a gem installed in this project to give us our diagnostic information. So from here, we can use our code action with leader ca and this will give us our options. We can actually disable this RuboCop cop if we want to, just like this, or what I would rather prefer to do is use our code action to just auto-correct this layout right here, and we're good to go.
Live Demo: Building a New Model
So now let's actually do a little bit of work in this project. We want to create a new model for whenever someone views a piece of content. So let's do that right here. We can do rails g model ContentView and we want this to have relationships to a couple of things, like the user and the actual content that they're viewing. So we want to reference the content that they're viewing as well as a user itself in this model. And then we want to store something. This is going to be a simple example, but let's just store something like a view count as an integer, and that will track the amount of times that someone has actually viewed this piece of content. And we want to keep track of the first time someone's viewed this content. So let's do first_viewed_at, which is a datetime. Cool. So now this should generate the model for us. And of course, I have a typo in my generator, so I can just fix it like this, and there we go. Now we have created a model in this application.
So let's check it out. Now we can go to models/content_view, and this is the model that we just created. Okay, so that created the model. Now let's just run our migrations, and now we're good to go. So now if we open up our project in Neovim and go to the model ContentView model, if we hover over this content view using shift-K, we can actually see the schema that we just migrated into our database. Really helpful, really awesome. And we have just a couple of things here like belongs to user and belongs to content. That's really nice.
AI-Powered PRs with CodeRabbit
So now let's take this example and push this up in a branch and create a PR. So let's open up lazygit and let's add all the stuff that we created and create a new commit here, which is 'add ContentView', and we can push this up using Shift-P, which will push all of our changes to this remote branch. Now we can exit out of lazygit and go over to our actual GitHub repository and create a pull request.
And now this is where the sponsor of this video, CodeRabbit, comes into play. CodeRabbit is an amazing AI tool for checking the pull requests of your GitHub repository and giving you amazing comments, suggestions, and all kinds of cool stuff. It'll do everything that you would want. It would even generate unit tests for your files if you ask it to. Now you can see down here that CodeRabbit has actually already processed this and it's given me a list of my commits and the files that it has selected for processing. Now you can see CodeRabbit has already analyzed this code and it's given me a bunch of stuff that I can do here. Now I can actually generate some really great unit tests for this model that I just created. So let's copy this. We can go into the files that have been changed, and in this file, I can create a new comment that says, "CodeRabbit AI, generate unit code for this file." Now if I leave this comment, CodeRabbit will then generate unit test code for this file. It's going to be amazing. Okay, I just got noticed that CodeRabbit has added a comment on this PR. Let's see what it says. Look at this, CodeRabbit has generated unit testing for this model, and it's even using RSpec, which is the testing library that we're using in Ruby on Rails.
Also, let me just add one more comment that says, "Generate summary for this PR," and see what CodeRabbit does. Because if there's one thing I don't like, it's actually writing summaries for pull requests. It's just something I hate. Let's see if CodeRabbit can handle this for us. And now if we hit refresh, we can see that CodeRabbit has actually generated a wonderful summary for this PR. This is fantastic, and it's very, very accurate, and it's amazing. So check out CodeRabbit. It's an unbelievable tool for managing your repositories, doing code reviews basically through AI, and it gives you some extremely helpful suggestions and has some really great features that can help you cut your workflow down in your PR cycle. And so there you have it. That is a beautiful Ruby on Rails Neovim configuration that only takes a few packages, but it comes out great. Now subscribe if you want more Neovim tips and tricks. And hey, thanks, nerds.