Skip to main content
Theme

<- Back

Learning Neovim

Posted on 2025-08-04


I've been using Neovim as my primary editor for some time now and have grown quite comfortable with it. However, reaching this level of comfort required extensive research and learning. I thought it would be helpful to create a brief guide for those looking to transition to Neovim as their full-time editor. This guide assumes a basic understanding of Neovim. If you're entirely new to it, I recommend starting with the vimtutor command in the terminal to run through the introductory tutorial. Additionally, it's assumed you have Kickstart.nvm, LazyVim, NvChad, AstroNvim, or something similar set up. Alternatively, you've created your own config from scratch containing at least an LSP and Telescope.nvim. If you're not sure which to use, I recommend using Kickstart, and make sure to read the comments in the main init.lua file.

Navigating between files

I (almost always) start Neovim from the root of the repository I'm working with. To open a file, I'll use Telescope's find_files. This one acts similarly to Ctrl/Cmd-P in Neovim, allowing me to quickly find any file within the project by file name. Often I will want to have two files side by side, which I can accomplish by Ctrl+v when I have the file selected in Telescope (Ctrl+x for a horizontal split). With Telescope open, you still have access to many Neovim features. Opening it will put you in insert mode, allowing you to type the desired file name. If you hit escape, it will put you in normal mode while keeping Telescope open. To go up and down in the file list, you can either use Ctrl+p/n (previous/next) in insert mode, or press escape to get to normal mode, then just use k/j to go up and down.

Telescope also has many other helpful pickers available. Some I use frequently, with their relevant names:

Make sure to check the Telescope documentation, as it has many different pickers you may find useful.

Sometimes you'll want to take a quick look at what a function does, dive deeper into a type declaration, or something similar. For this, I use the vim.lsp.buf.definition function, which I have mapped to gd ([g]o to [d]efinition). When I want to inspect a function's details, I'll put my cursor on the function name and hit gd which opens the file where this function is declared and puts the cursor directly on it. When I'm done looking, I use Vim's jump list functionality to return to my previous file with Ctrl+o. Ctrl+i goes forward in the jump list, so if you go back, move your cursor off the function name and decide you want to take another look, Ctrl+i will bring you back to the function declaration file without having to move your cursor back to the function call and hitting gd.

Navigating within a file

For navigating within a file, I typically use h, j, k, l if my target is nearby, or H, M, L (High, Middle, Low) for quick jumps to the top, middle, or bottom of the file. Additionally, I rely on the great plugin folke/flash.nvim for more precise navigation. Activated by pressing s or /, you simply type the first letter or two of your destination. The plugin then displays a unique character key next to each match. Pressing the corresponding key transports your cursor directly to the desired location. This is somewhat akin to the ggandor/leap.nvim plugin, but I find that flash.nvim offers several additional features that make it my preferred choice.

Text block manipulation

There are several ways I tend to work with blocks of text or code. If there's a block of text you want to delete, you can use dap (Delete Around Paragraph) with your cursor anywhere in the block. If you want to operate on something more granular, you can swap out the p with whatever you're trying to target, for example { or ". Using a (Around) will operate on the target as well, while using i (In) will operate within the target.

// Original
function SomeFunc(arg) {
    const foo = {
        val1: "1",
        val2: "2",
    }
    return foo;
}
// Using di{ with your cursor in between the foo object braces
function SomeFunc(arg) {
    const foo = {
    }
    return foo;
}
// Using di{ with your cursor inside the function
function SomeFunc(arg) {
}

Of course, running the above commands with c instead of d will do the exact same, except put you in insert mode immediately. Or, if you use y instead of d, it will yank the target instead.

While it may seem like you need to remember a metric ton of different key combinations, these commands follow a language-type syntax, with verbs, motions, multipliers, and text objects (targets). Common verbs are change (c), delete (d), visual select (v), yank (copy) (y), and paste (p). Common motions are the h/j/k/l movements, around (a), in (i), find (f, capitalized to find backwards), and till (t, like find but not including the target letter). Common text objects are paragraphs (p), words (w, W to include punctuation), tags (t), and specific brackets ({/[/( or b for any bracket). Multipliers are simply numbers prefixed to repeat an action or motion that many times.

So, putting this all together, here are some examples of things you can do:

Additional tips and tricks