This is my daily-driver Neovim setup: a Lua configuration built around
lazy.nvim, native LSP, Treesitter and
Telescope, with a Python-first workflow (basedpyright + Ruff + mypy) and GitHub
Copilot integrated for AI assistance. It keeps the muscle memory of a classic
Vim setup (Enter to jump to a definition, <C-p> to open files, F3/F4 for
the outline and the file tree) while giving you a modern IDE-like experience.
LSP diagnostics — basedpyright + Ruff, inline and in a float
Errors and warnings appear inline as you type; press <leader>e to open the
full message in a floating window, showing which server (and which rule)
reported each one.
Fuzzy file finder (Telescope, <C-p>)
Project-wide live grep (Telescope, <leader>fg)
Buffer switcher (Telescope, Alt+Up)
File tree + symbol outline (nvim-tree F4 + aerial F3)
On-demand mypy into the quickfix list (<leader>m)
Copilot Chat (<leader>cc)
Keybinding discovery with which-key (press <leader> and wait)
- Neovim >= 0.11.3 — the config relies on the builtin
unokaicolorscheme (added in 0.11) and the native LSP APIsvim.lsp.enable()/vim.lsp.config()(since 0.11.0), which the current nvim-lspconfig/mason-lspconfig require at 0.11.3+. On an older Neovim you'll hitE185: Cannot find color scheme 'unokai'andnilvim.lsp.*errors. If your distro's package is older, use the Neovim PPA (ppa:neovim-ppa/unstable, needs sudo) or the official AppImage into~/.local/bin(no sudo). The install script checks this for you. - git, make, gcc — to clone plugins and build
telescope-fzf-native. - Node.js + npm — only if you enable GitHub Copilot (an optional feature, off by default — see Optional features).
- ripgrep — Telescope live grep.
- fd — Telescope file finding (on Debian/Ubuntu the binary is
fdfind; the install script bridges it tofd). - A Nerd Font — for the icons in the statusline, file tree and outline. Install one (e.g. FiraCode Nerd Font) and select it in your terminal.
LSP servers, formatters and linters are not system packages: Mason installs them automatically on first launch (see below).
If you only have a user account (no sudo) and the system Neovim is too old, grab
the official AppImage into ~/.local/bin:
mkdir -p ~/.local/bin
curl -L https://github.com/neovim/neovim/releases/download/v0.11.4/nvim-linux-x86_64.appimage -o ~/.local/bin/nvim
chmod +x ~/.local/bin/nvimThen make sure ~/.local/bin comes first on your PATH, or a system
nvim in /usr/bin will keep shadowing it:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # ~/.zshrc for zsh
source ~/.bashrc
hash -r # drop the shell's cached nvim path
command -v nvim && nvim --version | head -1 # should print .../.local/bin/nvim and v0.11.4hash -r matters: the shell caches where it first found nvim, so without it
you'd keep launching the old one even after fixing PATH. If command -v nvim
still points at /usr/bin/nvim, run type -a nvim to see the order. Once it
reports 0.11.4, (re-)run the bootstrap script below. (If the AppImage complains
about FUSE, run ~/.local/bin/nvim --appimage-extract and use the extracted
squashfs-root/usr/bin/nvim.)
Back up any existing Neovim config first:
mv ~/.config/nvim ~/.config/nvim.backup 2>/dev/null || true
Then:
-
Clone this repository straight into your config directory:
git clone https://github.com/juanmitaboada/nvim ~/.config/nvim -
Run the bootstrap script. On Debian/Ubuntu it installs any missing system packages (nothing to install → it skips apt/sudo entirely), checks your Neovim version, links the repo into place, and pre-syncs the plugins. It also asks whether to enable the optional features (Copilot, WakaTime) on this machine — see Optional features:
~/.config/nvim/install-neovim.shIt is safe to re-run anytime: it skips whatever is already in place and only does what's missing. (On other distros, install the same packages by hand and skip this step.)
-
Launch Neovim. Mason installs the LSP servers, formatters and linters on this first run — watch progress with
:Mason:nvim -
Authenticate Copilot (first time only, and only if you enabled Copilot):
:Copilot setup -
You are ready to go. Run
:checkhealthanytime to verify everything.
<leader> is the space bar. These are the everyday shortcuts; there are a
few more in the config files.
| Shortcut | Description | Provided by |
|---|---|---|
* / # |
Search word under the cursor forward / backward | vim |
n / N |
Repeat search next / previous | vim |
<C-p> |
Open files (fuzzy finder) | Telescope |
<leader>ff |
Find files | Telescope |
<leader>fg |
Live grep across the project (replaces :Ack) |
Telescope |
<leader>fb / Alt+Up |
Switch between open buffers | Telescope |
<leader>fh |
Search the help | Telescope |
<leader>fr |
Resume the last Telescope search | Telescope |
Alt+Right / Alt+Left |
Next / previous buffer | vim |
Alt+Down |
Close current buffer | vim |
F3 |
Toggle the symbol outline | aerial |
F4 |
Toggle the file tree | nvim-tree |
F8 |
Save the session in the current folder | vim |
Enter |
Go to definition of the symbol under the cursor | LSP |
Backspace |
Jump back (pop the tag stack) | vim |
gd / gD |
Go to definition / declaration | LSP |
gr |
List references | LSP |
gi |
Go to implementation | LSP |
K |
Hover documentation | LSP |
<leader>rn |
Rename symbol | LSP |
<leader>ca |
Code action | LSP |
<leader>ws |
Search workspace symbols | LSP |
]d / [d |
Next / previous diagnostic | LSP |
<leader>e |
Show the diagnostic under the cursor in a float | LSP |
<leader>m |
Run mypy on the current buffer (results to quickfix) | mypy.lua |
<leader>gs |
Git status | fugitive |
<leader>gb |
Git blame | fugitive |
<leader>gd |
Git diff (split) | fugitive |
Tab |
Accept the inline Copilot suggestion | Copilot |
F12 |
Open the Copilot panel with alternatives | Copilot |
<leader>cc |
Open Copilot Chat | CopilotChat |
<leader>ce |
Explain the selection / buffer | CopilotChat |
<leader>cr |
Review the selection (visual mode) | CopilotChat |
<leader>cf |
Suggest a fix for the selection (visual mode) | CopilotChat |
<C-Up> / <C-Down> |
Move the current line / block up / down | vim |
<C-Left> / <C-Right> |
Unindent / indent the current line / block | vim |
<C-j> |
Reformat the buffer as JSON (python -m json.tool) |
vim |
F2 |
Expand the snippet under the cursor (insert mode) | LuaSnip |
<C-b> / <C-z> |
Jump forward / backward between snippet placeholders | LuaSnip |
Snippets are powered by LuaSnip with the
friendly-snippets collection,
so the usual triggers for many languages are available out of the box. In
Python, for example, type a trigger such as def, class, for, while,
with, try or ifmain and press F2 to expand it, then use <C-b> / <C-z>
to jump between the placeholders.
Two plugins are tied to personal accounts, so they are off by default and never load on a fresh checkout, a server, or anyone else's machine:
- GitHub Copilot (
copilot.vim+CopilotChat.nvim) — needs a Copilot subscription, and Node.js + npm. - WakaTime (
vim-wakatime) — needs a WakaTime account and~/.wakatime.cfg.
The defaults live in lua/features.lua. A machine opts in by dropping a
git-ignored local.lua next to it — that is, at lua/local.lua inside your
config dir (usually ~/.config/nvim/lua/local.lua) — which overrides them:
-- ~/.config/nvim/lua/local.lua (not committed)
return {
copilot = true,
wakatime = true,
}Each flag is independent — set only the ones you want. With a flag off, the
corresponding plugin is neither installed nor loaded (lazy.nvim skips it via
enabled = false) and its keybindings stay unmapped, so there is nothing to
disable and nothing phones home.
The easiest way is to let the bootstrap script create it (answer yes when it asks). To do it by hand, or to change your mind later:
# enable both on this machine
echo 'return { copilot = true, wakatime = true }' > ~/.config/nvim/lua/local.luaThen run :Lazy sync (or restart Neovim) to pull the plugins in — or delete the
file to go back to the defaults. This is the only file you manage per machine;
everything else is shared.
Copilot is an optional feature, off by default. The rest of this section applies once you've enabled it via
lua/local.lua.
Inline suggestions from GitHub Copilot appear automatically while typing; press
Tab to accept one, or F12 to open the panel with several alternatives. Run
:Copilot setup once to authenticate.
For a conversation about your code, open Copilot Chat with <leader>cc. Note
that the chat does not see your code unless you hand it some context:
- Add
#bufferat the start of your message to include the whole current file, e.g.#buffer why does line 4 fail?. - Or make a visual selection first and use
<leader>ce(explain),<leader>cf(suggest a fix) or<leader>cr(review) — these act on the selection.
Without one of those, Copilot will only ask you to paste the relevant code.
To keep noise down, pylint and mypy are opt-in per project instead of running everywhere:
- pylint runs through
nvim-lintonly when the project provides its own configuration (e.g. a.pylintrc), using the project's virtualenv when one is detected. - mypy never runs automatically. Run it on demand with
<leader>m(or the:Mypycommand) on the current Python buffer; results land in the quickfix list, whereEnterjumps to each error.
| Plugin | Description |
|---|---|
| lazy.nvim | Plugin manager (bootstrapped automatically) |
| nvim-lspconfig | Configuration for the native LSP client |
| mason.nvim | Installer for LSP servers, formatters and linters |
| mason-lspconfig | Bridges Mason and lspconfig |
| mason-tool-installer | Auto-installs the configured tools |
| nvim-cmp | Completion engine (with LSP, buffer, path and snippet sources) |
| LuaSnip | Snippet engine |
| friendly-snippets | Ready-made snippet collection for many languages |
| copilot.vim | GitHub Copilot inline suggestions (optional, off by default) |
| CopilotChat.nvim | Conversational Copilot inside Neovim (optional, off by default) |
| telescope.nvim | Fuzzy finder for files, grep, buffers, symbols and more |
| telescope-fzf-native | Native fzf sorter for Telescope |
| plenary.nvim | Lua utility library used by several plugins |
| nvim-tree.lua | File system explorer |
| aerial.nvim | Symbol outline / code structure view |
| lualine.nvim | Statusline |
| nvim-web-devicons | File-type icons (needs a Nerd Font) |
| gitsigns.nvim | Git change signs in the gutter |
| vim-fugitive | Git commands from inside Neovim |
| nvim-treesitter | Syntax highlighting and parsing |
| indent-blankline | Indentation guides |
| conform.nvim | Formatting (black, shfmt, …) |
| nvim-lint | Linting (pylint, shellcheck, yamllint, …) |
| nvim-autopairs | Automatic closing of quotes, brackets, etc. |
| vim-commentary | Comment / uncomment lines and blocks |
| vim-surround | Add, change and delete surrounding pairs |
| vim-repeat | Makes . repeat supported plugin maps |
| vim-unimpaired | Handy bracket mappings ([, ]) |
| which-key.nvim | Popup that shows the available keybindings |
| vim-wakatime | Automatic coding-time tracking (wakatime.com) (optional, off by default) |
Installed automatically by Mason on first launch:
- LSP servers: basedpyright, ruff, clangd, rust_analyzer, zls, bashls, yamlls, lua_ls, marksman, dockerls.
- Formatters / linters: black, mypy, shfmt, pylint, shellcheck, yamllint, hadolint.







