tonybtw.com
tonybtw.com
https://git.tonybtw.com/tonybtw.com.git
git://git.tonybtw.com/tonybtw.com.git
+++ title = "Neovim on Linux — Complete IDE Tutorial" author = ["Tony", "btw"] description = "A quick and painless guide on installing and configuring Neovim, and how to use it as your full daily driver IDE, btw." date = 2025-05-10 draft = false image = "/img/neovim.png" showTableOfContents = true +++
Intro {#intro}
A clean and painless guide to turning Neovim into a modern IDE.
Neovim is a Vim-based text editor built for extensibility and usability. In this tutorial, you’ll learn how to set it up with plugins, keybinds, and full LSP support. This guide assumes you're using a Unix-like system and are comfortable with basic terminal commands.
Install Neovim and dependencies {#install-neovim-and-dependencies}
Use your system’s package manager to install Neovim, along with a few tools that will be required later (like npm and ripgrep).
# Gentoo
sudo emerge app-editors/neovim
sudo emerge net-libs/nodejs
sudo emerge sys-apps/ripgrep
# Arch
sudo pacman -S neovim nodejs npm ripgrep
Set up your Neovim config directory {#set-up-your-neovim-config-directory}
Create your config folder and add the main config file.
mkdir -p ~/.config/nvim
cd ~/.config/nvim
nvim .
In Neovim, press % to create a new file named init.lua:
print("I use Neovim by the way")
Save and quit with :wq, then reopen Neovim.
Create a Lua module for options {#create-a-lua-module-for-options}
mkdir -p ~/.config/nvim/lua/config
nvim lua/config/options.lua
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.shiftwidth = 4
Then in init.lua:
require("config.options")
Add keybindings {#add-keybindings}
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>cd", vim.cmd.Ex)
In init.lua:
require("config.keybinds")
Install Lazy.nvim {#install-lazy-dot-nvim}
Clone it into your runtime path.
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({})
Then:
require("config.lazy")
Add a theme plugin {#add-a-theme-plugin}
return {
"folke/tokyonight.nvim",
config = function()
vim.cmd.colorscheme("tokyonight")
end,
}
Add Telescope for fuzzy finding {#add-telescope-for-fuzzy-finding}
return {
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
local builtin = require("telescope.builtin")
vim.keymap.set("n", "<leader>ff", builtin.find_files)
vim.keymap.set("n", "<leader>fg", builtin.live_grep)
vim.keymap.set("n", "<leader>fb", builtin.buffers)
vim.keymap.set("n", "<leader>fh", builtin.help_tags)
end,
}
Add Treesitter for syntax highlighting {#add-treesitter-for-syntax-highlighting}
return {
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
highlight = { enable = true },
indent = { enable = true },
ensure_installed = { "lua" },
auto_install = false,
})
end,
}
Add Harpoon for file bookmarking {#add-harpoon-for-file-bookmarking}
return {
"ThePrimeagen/harpoon",
config = function()
local harpoon = require("harpoon")
vim.keymap.set("n", "<leader>a", function() harpoon:list():add() end)
vim.keymap.set("n", "<C-e>", function() harpoon.ui:toggle_quick_menu(harpoon:list()) end)
end,
}
Add LSP, autocompletion, and snippets {#add-lsp-autocompletion-and-snippets}
return {
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"hrsh7th/nvim-cmp",
"L3MON4D3/LuaSnip",
},
config = function()
require("mason").setup()
require("mason-lspconfig").setup({ ensure_installed = { "lua_ls" } })
local lspconfig = require("lspconfig")
lspconfig.lua_ls.setup({})
local cmp = require("cmp")
cmp.setup({
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<Tab>"] = cmp.mapping.select_next_item(),
["<S-Tab>"] = cmp.mapping.select_prev_item(),
}),
sources = { { name = "nvim_lsp" }, { name = "luasnip" } },
})
end,
}
One-liner utility plugins {#one-liner-utility-plugins}
return {
{ "tpope/vim-fugitive" },
{ "ojroques/nvim-osc52" },
{
"norcalli/nvim-colorizer.lua",
config = function()
require("colorizer").setup()
end,
},
}
Final init.lua Example {#final-init-dot-lua-example}
require("config.options")
require("config.keybinds")
require("config.lazy")
/home/tony/.config/nvim
├── init.lua
├── lazy-lock.json
├── lua
│ ├── config
│ │ ├── keybinds.lua
│ │ ├── lazy.lua
│ │ └── options.lua
│ └── plugins
│ ├── colors.lua
│ ├── harpoon.lua
│ ├── init.lua
│ ├── lsp.lua
│ ├── lualine.lua
│ ├── one-liners.lua
│ ├── orgmode.lua
│ ├── telescope.lua
│ └── treesitter.lua
├── plugin
│ └── flterm.lua
└── README.md
5 directories, 16 files
My keybinds {#my-keybinds}
If you want to just copy my nvim config, my keybind documentation is here:
General {#general}
| Mode | Key | Action |
|---|---|---|
| n | <leader>cd | Open Ex mode (`:Ex`) |
| n | J | Join lines while keeping the cursor in place |
| n | <C-d> | Scroll half-page down and center cursor |
| n | <C-u> | Scroll half-page up and center cursor |
| n | n | Next search result (centered) |
| n | N | Prev search result (centered) |
| n | Q | Disable Ex mode |
| n | <C-k> | Next quickfix entry (centered) |
| n | <C-j> | Prev quickfix entry (centered) |
| n | <leader>k | Next location list entry (centered) |
| n | <leader>j | Prev location list entry (centered) |
| i | <C-c> | Exit insert mode |
| n | <leader>x | Make current file executable |
| n | <leader>u | Toggle Undotree |
| n | <leader>rl | Reload config |
| n | <leader><leader> | Source current file |
Visual Mode {#visual-mode}
| Mode | Key | Action |
|---|---|---|
| v | J | Move block down |
| v | K | Move block up |
| x | <leader>p | Paste without overwriting clipboard |
| v | <leader>y | Yank to system clipboard |
Linting & Formatting {#linting-and-formatting}
| Mode | Key | Action |
|---|---|---|
| n | <leader>cc | Run php-cs-fixer |
| n | <F3> | Format (LSP) |
Telescope {#telescope}
| Mode | Key | Action |
|---|---|---|
| n | <leader>ff | Find files |
| n | <leader>fg | Git-tracked files |
| n | <leader>fo | Recent files |
| n | <leader>fq | Quickfix list |
| n | <leader>fh | Help tags |
| n | <leader>fb | Buffers |
| n | <leader>fs | Grep string under cursor |
| n | <leader>fc | Grep current filename (no extension) |
| n | <leader>fi | Search in ~/.config/nvim |
Harpoon {#harpoon}
| Mode | Key | Action |
|---|---|---|
| n | <leader>a | Add to Harpoon |
| n | <C-e> | Toggle Harpoon quick menu |
| n | <leader>fl | Telescope Harpoon marks |
| n | <C-p> | Prev Harpoon mark |
| n | <C-n> | Next Harpoon mark |
LSP {#lsp}
| Mode | Key | Action |
|---|---|---|
| n | K | Hover docs |
| n | gd | Go to definition |
| n | gD | Go to declaration |
| n | gi | Go to implementation |
| n | go | Go to type definition |
| n | gr | List references |
| n | gs | Signature help |
| n | gl | Show diagnostics float |
| n | <F2> | Rename symbol |
| n,x | <F3> | Format code |
| n | <F4> | Code actions |
Misc {#misc}
| Mode | Key | Action |
|---|---|---|
| n | <leader>dg | Run DogeGenerate |
| n | <leader>s | Replace word on current line |
Final Thoughts {#final-thoughts}
You're now ready to use Neovim as a modern, fast, and extensible code editor.
Thanks so much for checking out this tutorial. If you got value from it, and you want to find more tutorials like this, check out my youtube channel here: YouTube, or my website here: tony,btw
You can support me here: kofi