Neovim Plugins Guide
Is this a modern IDE now?
Short answer: yes, for the things that matter — but it’s a different philosophy.
What you now have that matches VS Code / JetBrains:
- Syntax highlighting (treesitter) — actually better than most IDEs, it’s AST-based not regex
- Go to definition, hover docs, rename, code actions (LSP)
- Autocomplete with snippets (nvim-cmp)
- Fuzzy file/text search (telescope)
- Git diff in the gutter, blame, staging (gitsigns + lazygit)
What IDEs have that you don’t yet:
- Debugger UI (add
nvim-dapfor that) - Integrated terminal (nvim has
:termbuilt-in, but no split panel like VS Code) - Test runner panel (add
neotestfor that) - Inline AI suggestions (add
copilot.luaoravante.nvimfor that)
The real difference: nvim is composable and keyboard-driven by design. Once muscle memory kicks in, the workflow is faster than an IDE for editing-heavy work. The tradeoff is initial setup time, which you’ve now done.
Plugins
lazygit — Full git UI
What it does: Opens LazyGit in a floating terminal inside nvim. Full git client: staging, committing, branching, rebasing, stash, log — all without leaving nvim.
Keybindings:
| Key | Action |
|---|---|
<leader>gg | Open LazyGit |
When to use it:
- Staging individual lines or hunks before committing
- Interactive rebase (
ron a commit) - Browsing commit history and diffs
- Resolving merge conflicts visually
Workflow example: You’ve made changes across 3 files but only want to commit 2. Open LazyGit, navigate to each file, press Space to stage, write your commit message, done.
nvim-tree — File explorer
What it does: A sidebar file tree. Navigate, open, create, rename, delete files and folders.
Keybindings:
| Key | Action |
|---|---|
<leader>e | Toggle file tree open/closed |
a (in tree) | Create file or folder (append / for folder) |
d (in tree) | Delete |
r (in tree) | Rename |
m (in tree) | Mark/bookmark a node |
<CR> or o | Open file |
g? (in tree) | Show all keybindings |
When to use it:
- Navigating an unfamiliar codebase structure
- Creating new files in the right directory
- Quickly jumping to a file you can see in the tree
Tip: For files you open repeatedly, telescope (<leader>ff) or harpoon is faster than the tree. Use the tree for structure overview and file creation.
nvim-treesitter — Syntax highlighting
What it does: Parses your code into an actual syntax tree and highlights it semantically. Also powers smarter indentation and text objects in other plugins.
You don’t interact with it directly — it just makes everything look and behave better. The difference vs the old regex-based highlighting is especially visible in complex files (JSX, nested templates, multiline strings).
Installed parsers: Lua, Vim, Bash, JSON, YAML, TOML, Markdown, JavaScript, TypeScript, Python.
When to notice it:
- Correct highlighting inside template literals
- Proper indentation when pressing
=to format a block - String interpolation highlighted correctly inside
${}
telescope — Fuzzy finder
What it does: A floating search UI for finding anything — files, text, git history, LSP symbols, help pages, and more.
Keybindings:
| Key | Action |
|---|---|
<leader>ff | Find files by name |
<leader>fg | Search text across all files (requires ripgrep) |
<leader>fb | Switch between open buffers |
<leader>fh | Search nvim help documentation |
Inside telescope:
| Key | Action |
|---|---|
<C-j> / <C-k> | Move up/down results |
<CR> | Open selected |
<C-v> | Open in vertical split |
<C-x> | Open in horizontal split |
<Esc> | Close |
When to use it:
<leader>ff— jumping to any file in the project (faster than the tree for known files)<leader>fg— finding where a function is called, where a variable is defined, or any text pattern<leader>fb— switching between the files you currently have open
Workflow example: You remember there’s a handleAuth function somewhere. Press <leader>fg, type handleAuth, and telescope shows every file and line it appears in. Select one and you’re there.
Requires:
brew install ripgrepfor live grep to work.
mason — LSP server manager
What it does: Downloads and manages language server binaries. Think of it as a package manager for LSP servers, linters, and formatters.
Commands:
| Command | Action |
|---|---|
:Mason | Open the Mason UI |
:MasonInstall <server> | Install a specific server |
:MasonUninstall <server> | Remove a server |
Auto-installed servers: lua_ls (Lua), ts_ls (TypeScript/JavaScript), pyright (Python), bashls (Bash).
When to use it:
- Adding LSP support for a new language (open
:Mason, find the server, pressi) - Checking if a server is installed and running
Adding a new language: Open :Mason, search for the language (e.g. rust-analyzer), press i to install. Then add "rust_analyzer" to the servers list in lazy.lua.
nvim-cmp — Autocomplete
What it does: Shows completion suggestions as you type, sourced from the LSP, open buffers, file paths, and snippets.
Keybindings (when completion menu is open):
| Key | Action |
|---|---|
<Tab> | Select next item / expand snippet |
<S-Tab> | Select previous item |
<CR> | Confirm selection |
<C-Space> | Manually trigger completion |
<C-e> | Dismiss menu |
<C-b> / <C-f> | Scroll docs up/down |
Sources (in priority order):
- LSP — function signatures, types, class members
- LuaSnip — code snippets
- Buffer — words from open files
- Path — filesystem paths
When to use it:
- Completing function names and checking their signatures
- Autocompleting import paths
- Using
<C-Space>when you want suggestions but the menu didn’t appear automatically
lualine — Statusline
What it does: Replaces the default statusline at the bottom of the screen with a clean, informative bar showing: current mode, filename, git branch, git diff stats, LSP diagnostics, filetype, and cursor position.
You don’t interact with it directly — it’s always visible. Once it’s there you’ll notice when something is missing.
What to watch:
- The mode indicator changes colour (Normal / Insert / Visual / Command)
- LSP errors/warnings appear as counts on the right — if you see a number there, press
]dto jump to the next diagnostic - Git branch name always visible — useful when context switching
gitsigns — Git in the gutter
What it does: Shows git change indicators in the sign column (the thin strip left of line numbers). Also provides hunk-level operations without leaving the file.
Gutter symbols:
| Symbol | Meaning |
|---|---|
│ (green) | Added line |
│ (orange) | Changed line |
_ (red) | Deleted lines below |
Keybindings:
| Key | Action |
|---|---|
<leader>hs | Stage the hunk under cursor |
<leader>hr | Reset (discard) the hunk under cursor |
<leader>hp | Preview the hunk diff in a float |
<leader>hb | Show git blame for current line |
]c | Jump to next hunk |
[c | Jump to previous hunk |
When to use it:
- Staging specific hunks (changes) within a file rather than the whole file
- Quickly seeing what you changed without leaving the file
- Undoing just one change within a file (
<leader>hr) - Checking who last touched a line (
<leader>hb)
Workflow example: You edited a 200-line file and want to commit only the first change. Use ]c to jump between hunks, <leader>hp to preview each one, and <leader>hs to stage just the ones you want. Then commit via LazyGit.
which-key — Keybinding hints
What it does: When you press a key like <leader> and pause, a popup appears listing all valid next keys and what they do. It learns your keybindings automatically.
You don’t configure it beyond installation — it reads all your existing mappings.
When to use it:
- You’ve forgotten a keybinding and don’t want to leave your workflow to check this file
- Discovering what’s available after adding new plugins
- Learning new motions (try pressing
gin normal mode and pausing)
Tip: Press <leader> and wait ~1 second. You’ll see all your leader mappings grouped. This is especially useful now that you have ~20 bindings across all plugins.
mini.pairs — Auto-close brackets
What it does: Automatically inserts the closing character when you open a bracket, quote, or brace.
| You type | You get |
|---|---|
( | () with cursor inside |
[ | [] with cursor inside |
{ | {} with cursor inside |
" | "" with cursor inside |
' | '' with cursor inside |
Smart behaviours:
- Pressing
)when cursor is already before)jumps over it instead of inserting another - Doesn’t double-close when you type a closing char that’s already there
You don’t interact with it — it just works as you type.
mini.surround — Surround text objects
What it does: Adds, changes, and deletes surrounding characters (brackets, quotes, tags) using short motion commands.
Keybindings:
| Key | Action | Example |
|---|---|---|
sa + motion + char | Add surround | saiw" → surround word with " |
sd + char | Delete surround | sd" → remove surrounding " |
sr + old + new | Replace surround | sr"' → change " to ' |
sf + char | Find surrounding | jump to next surrounding |
Common patterns:
saiw"— surround inner word with double quotessaiw(— surround inner word with parenthesessd"— delete the surrounding double quotessr({— change(to{
When to use it:
- Wrapping a variable in quotes: cursor on word,
saiw" - Changing quote style in a string:
sr"' - Wrapping a function argument in another function call:
saiw( - Removing quotes from a string literal:
sd"