Hello everyone! In this article I will show you how to configure the neovim editor from scratch with lazy.vim.
💤 Lazy.nvim
A modern plugin manager for Neovim
Repo: folke/lazy.nvim
-
Outstanding features:
- 📦 Manage all your Neovim plugins with a powerful UI
- 🚀 Fast startup times thanks to automatic caching and bytecode compilation of Lua modules
- 🔌 Automatic lazy-loading of Lua modules and lazy-loading on events, commands, filetypes, and key mappings
- ⏳ Automatically install missing plugins before starting up Neovim, allowing you to start using it right away
- 🛠️ No need to manually compile plugins
- 🧪 Correct sequencing of dependencies
- 📁 Configurable in multiple files
- 🔎 Automatically check for updates
📚 GitHub Repository
All the code is in my Github profile at slydragonn/nvim-lazy repo.
📹 Tutorial video
⚙ Requirements
- Neovim >= v0.10.0
- Nerd Fonts
- NodeJS with npm
- Lazy.vim
- A C compiler in your path and libstdc++ installed: Windows support
- Git
✨ Features
- folke/lazy.nvim: A modern plugin manager for Neovim
- nvim-neo-tree/neo-tree: Neovim plugin to manage the file system and other tree like structures.
- tiagovla/tokyodark.nvim: A clean dark theme written in lua for neovim.
- nvim-tree/nvim-web-devicons: lua fork of vim-web-devicons for neovim.
- nvim-lualine/lualine.nvim: A blazing fast and easy to configure neovim statusline plugin written in pure lua.
- nvim-treesitter/nvim-treesitter: Nvim Treesitter configurations and abstraction layer.
- windwp/nvim-ts-autotag: Use treesitter to auto close and auto rename html tag.
- stevearc/conform.nvim: Lightweight yet powerful formatter plugin for Neovim.
- nvim-telescope/telescope.nvim: Highly extendable fuzzy finder over lists.
- neovim/nvim-lspconfig: Quickstart configs for Nvim LSP
- hrsh7th/nvim-cmp: A completion plugin for neovim coded in Lua.
- williamboman/mason.nvim: Portable package manager for Neovim that runs everywhere Neovim runs.
- norcalli/nvim-colorizer.lua: Color highlighter.
- akinsho/toggleterm.nvim: A neovim lua plugin to help easily manage multiple terminal windows.
- lewis6991/gitsigns.nvim: Git integration for buffers.
- windwp/nvim-autopairs: Autopairs for neovim written by lua.
- onsails/lspkind.nvim: vscode-like pictograms for neovim lsp completion items.
- L3MON4D3/LuaSnip: Snippet Engine for Neovim written in Lua.
- hrsh7th/cmp-nvim-lsp: nvim-cmp source for neovim builtin LSP client
- hrsh7th/cmp-path: nvim-cmp source for path
- hrsh7th/cmp-buffer: nvim-cmp source for buffer words
- williamboman/mason-lspconfig.nvim: Extension to mason.nvim that makes it easier to use lspconfig with mason.nvim.
- WhoIsSethDaniel/mason-tool-installer.nvim: Install and upgrade third party tools automatically.
📚 Project Structure
📂 nvim/
├── 📂 lua/📂 slydragonn/
│ └── 📂 plugins/
│ └── 📂 lsp/
│ └── ...pluginconfigfiles
│ └── 🌑 settings.lua
│ └── 🌑 maps.lua
│ └── 🌑 lazy.lua
└── 🌑 init.lua
If you don’t have some requirements
- Nerd Fonts: https://www.nerdfonts.com/
- Neovim: https://github.com/neovim/neovim/releases/
- Node: https://nodejs.org/en/download/package-manager
- C compiler: https://github.com/nvim-treesitter/nvim-treesitter/wiki/Windows-support
- Git: https://git-scm.com/downloads
Saving Settings
The configuration files go to a particular place, so you should create the nvim/ folder in the following path depending on your operating system:
Windows:
C:\Users\%YOUR_USERNAME%\AppData\Local\nvim
Linux:
~/.configs/nvim/
And in the nvim/ folder create the init.lua
file
with the following code:
- Note: slydragonn is my personal folder, but you can rename it whatever you want :)
-- ~/nvim/init.lua
require("slydragonn.settings")
Editor Settings
Then create a lua folder for our configuration and also for the plugins.
-- ~/nvim/lua/slydragonn/settings.lua
local global = vim.g
local o = vim.opt
-- Editor options
o.number = true -- Print the line number in front of each line
o.relativenumber = true -- Show the line number relative to the line with the cursor in front of each line.
o.clipboard = "unnamedplus" -- uses the clipboard register for all operations except yank.
o.syntax = "on" -- When this option is set, the syntax with this name is loaded.
o.autoindent = true -- Copy indent from current line when starting a new line.
o.cursorline = true -- Highlight the screen line of the cursor with CursorLine.
o.expandtab = true -- In Insert mode: Use the appropriate number of spaces to insert a <Tab>.
o.shiftwidth = 2 -- Number of spaces to use for each step of (auto)indent.
o.tabstop = 2 -- Number of spaces that a <Tab> in the file counts for.
o.encoding = "UTF-8" -- Sets the character encoding used inside Vim.
o.ruler = true -- Show the line and column number of the cursor position, separated by a comma.
o.mouse = "a" -- Enable the use of the mouse. "a" you can use on all modes
o.title = true -- When on, the title of the window will be set to the value of 'titlestring'
o.hidden = true -- When on a buffer becomes hidden when it is |abandon|ed
o.ttimeoutlen = 0 -- The time in milliseconds that is waited for a key code or mapped key sequence to complete.
o.wildmenu = true -- When 'wildmenu' is on, command-line completion operates in an enhanced mode.
o.showcmd = true -- Show (partial) command in the last line of the screen. Set this option off if your terminal is slow.
o.showmatch = true -- When a bracket is inserted, briefly jump to the matching one.
o.inccommand = "split" -- When nonempty, shows the effects of :substitute, :smagic, :snomagic and user commands with the :command-preview flag as you type.
o.splitright = true
o.splitbelow = true -- When on, splitting a window will put the new window below the current one
o.termguicolors = true
Add Lazy.vim
Installing Lazy is quite easy, you just have to copy this code from folke/lazy.nvim and paste it into ~/nvim/lua/slydragonn/lazy.lua
-- ~/nvim/lua/slydragonn/lazy.lua
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup("slydragonn.plugins")
Then in the init.lua file we import the lazy config:
-- ~/nvim/init.lua
require("slydragonn.settings")
require("slydragonn.lazy")
And create the plugins/ folder, where to add the plugin configuration files: ~/nvim/lua/plugins/
Lazy will read all the files in the plugins folder, because that's how we set it, and Lazy will install them all automatically, or we can use the command :Lazy
to see the UI.
Lazy Commands
- Open the UI:
:Lazy
- Install:
shift
+L
- Sync:
shift
+S
- Update:
shift
+U
- Clear:
shift
+X
- Check:
shift
+C
- Log:
shift
+L
- Restore:
shift
+R
- Profile:
shift
+P
- Debug:
shift
+D
- Help:
shift
+?
ℹ️ It is recommended to run :checkhealth lazy
after installation.
Plugin Configs:
treesitter.lua
nvim-treesitter/nvim-treesitter: Nvim Treesitter configurations and abstraction layer.
--- ~/nvim/lua/slydragonn/plugins/treesiter.lua
return {
"nvim-treesitter/nvim-treesitter",
event = { "BufReadPre", "BufNewFile" },
build = ":TSUpdate",
dependencies = {
"windwp/nvim-ts-autotag",
},
config = function()
local treesitter = require("nvim-treesitter.configs")
treesitter.setup({
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
indent = { enable = true },
autotag = {
enable = true,
},
ensure_installed = {
"json",
"javascript",
"typescript",
"tsx",
"yaml",
"html",
"css",
"markdown",
"markdown_inline",
"bash",
"lua",
"vim",
"dockerfile",
"gitignore",
"c",
"rust",
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-space>",
node_incremental = "<C-space>",
scope_incremental = false,
node_decremental = "<bs>",
},
},
rainbow = {
enable = true,
disable = { "html" },
extended_mode = false,
max_file_lines = nil,
},
context_commentstring = {
enable = true,
enable_autocmd = false,
},
})
end,
}
colorscheme.lua
tiagovla/tokyodark.nvim: A clean dark theme written in lua for neovim.
-- ~/nvim/lua/slydragonn/plugins/colorscheme.lua
return {
"tiagovla/tokyodark.nvim",
lazy = false,
priority = 1000,
config = function()
vim.cmd("colorscheme tokyodark")
end,
}
autopairs.lua
windwp/nvim-autopairs: Autopairs for neovim written by lua.
-- ~/nvim/lua/slydragonn/plugins/autopairs.lua
return {
"windwp/nvim-autopairs",
event = "InsertEnter",
config = function()
require("nvim-autopairs").setup({
disable_filetype = { "TelescopePrompt", "vim" },
})
end,
}
cmp.lua
hrsh7th/nvim-cmp: A completion plugin for neovim coded in Lua.
-- ~/nvim/lua/slydragonn/plugins/cmp.lua
return {
"hrsh7th/nvim-cmp",
event = "InsertEnter",
dependencies = {
"hrsh7th/cmp-buffer", -- source for text in buffer
"hrsh7th/cmp-path", -- source for file system paths
{
"L3MON4D3/LuaSnip",
version = "v2.*",
-- install jsregexp (optional!).
build = "make install_jsregexp",
},
"rafamadriz/friendly-snippets",
"onsails/lspkind.nvim", -- vs-code like pictograms
},
config = function()
local cmp = require("cmp")
local lspkind = require("lspkind")
local luasnip = require("luasnip")
require("luasnip.loaders.from_vscode").lazy_load()
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<C-d>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.close(),
["<CR>"] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}),
}),
sources = cmp.config.sources({
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "buffer" },
{ name = "path" },
}),
})
vim.cmd([[
set completeopt=menuone,noinsert,noselect
highlight! default link CmpItemKind CmpItemMenuDefault
]])
end,
}
colorizer.lua
norcalli/nvim-colorizer.lua: Color highlighter.
-- ~/nvim/lua/slydragonn/plugins/colorizer.lua
return {
"norcalli/nvim-colorizer.lua",
config = function()
require("colorizer").setup({ "*" })
end,
}
lualine.lua
nvim-lualine/lualine.nvim: A blazing fast and easy to configure neovim statusline plugin written in pure lua.
-- ~/nvim/lua/slydragonn/plugins/lualine.lua
return {
"nvim-lualine/lualine.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
config = function()
require("lualine").setup()
end,
}
mason.lua
williamboman/mason.nvim: Portable package manager for Neovim that runs everywhere Neovim runs.
-- ~/nvim/lua/slydragonn/plugins/mason.lua
return {
"williamboman/mason.nvim",
dependencies = {
"williamboman/mason-lspconfig.nvim",
"WhoIsSethDaniel/mason-tool-installer.nvim",
},
config = function()
require("mason").setup()
require("mason-lspconfig").setup({
automatic_installation = true,
ensure_installed = {
"cssls",
"eslint",
"html",
"jsonls",
"tsserver",
"pyright",
"tailwindcss",
},
})
require("mason-tool-installer").setup({
ensure_installed = {
"prettier",
"stylua", -- lua formatter
"isort", -- python formatter
"black", -- python formatter
"pylint",
"eslint_d",
},
})
end,
}
lspconfig.lua
williamboman/mason-lspconfig.nvim: Extension to mason.nvim that makes it easier to use lspconfig with mason.nvim.
-- ~/nvim/lua/slydragonn/plugins/lspconfig.lua
return {
"neovim/nvim-lspconfig",
event = { "BufReadPre", "BufNewFile" },
dependencies = {
"hrsh7th/cmp-nvim-lsp",
{ "folke/neodev.nvim", opts = {} },
},
config = function()
local nvim_lsp = require("lspconfig")
local mason_lspconfig = require("mason-lspconfig")
local protocol = require("vim.lsp.protocol")
local on_attach = function(client, bufnr)
-- format on save
if client.server_capabilities.documentFormattingProvider then
vim.api.nvim_create_autocmd("BufWritePre", {
group = vim.api.nvim_create_augroup("Format", { clear = true }),
buffer = bufnr,
callback = function()
vim.lsp.buf.format()
end,
})
end
end
local capabilities = require("cmp_nvim_lsp").default_capabilities()
mason_lspconfig.setup_handlers({
function(server)
nvim_lsp[server].setup({
capabilities = capabilities,
})
end,
["tsserver"] = function()
nvim_lsp["tsserver"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
["cssls"] = function()
nvim_lsp["cssls"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
["tailwindcss"] = function()
nvim_lsp["tailwindcss"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
["html"] = function()
nvim_lsp["html"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
["jsonls"] = function()
nvim_lsp["jsonls"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
["eslint"] = function()
nvim_lsp["eslint"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
["pyright"] = function()
nvim_lsp["pyright"].setup({
on_attach = on_attach,
capabilities = capabilities,
})
end,
})
end,
}
formatter.lua
stevearc/conform.nvim: Lightweight yet powerful formatter plugin for Neovim.
-- ~/nvim/lua/slydragonn/plugins/formatter.lua
return {
"stevearc/conform.nvim",
event = { "BufReadPre", "BufNewFile" },
config = function()
local conform = require("conform")
conform.setup({
formatters_by_ft = {
javascript = { "prettier" },
typescript = { "prettier" },
javascriptreact = { "prettier" },
typescriptreact = { "prettier" },
css = { "prettier" },
html = { "prettier" },
json = { "prettier" },
yaml = { "prettier" },
markdown = { "prettier" },
lua = { "stylua" },
python = { "isort", "black" },
},
format_on_save = {
lsp_fallback = true,
async = false,
timeout_ms = 1000,
},
})
vim.keymap.set({ "n", "v" }, "<leader>f", function()
conform.format({
lsp_fallback = true,
async = false,
timeout_ms = 1000,
})
end, { desc = "Format file or range (in visual mode)" })
end,
}
gitsigns.lua
lewis6991/gitsigns.nvim: Git integration for buffers.
-- ~/nvim/lua/slydragonn/plugins/gitsigns.lua
return {
"lewis6991/gitsigns.nvim",
config = function()
local gitsigns = require("gitsigns")
gitsigns.setup({
signs = {
add = { text = "│" },
change = { text = "│" },
delete = { text = "_" },
topdelete = { text = "‾" },
changedelete = { text = "~" },
untracked = { text = "┆" },
},
signcolumn = true, -- Toggle with `:Gitsigns toggle_signs`
numhl = false, -- Toggle with `:Gitsigns toggle_numhl`
linehl = false, -- Toggle with `:Gitsigns toggle_linehl`
word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff`
watch_gitdir = {
interval = 1000,
follow_files = true,
},
attach_to_untracked = true,
current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame`
current_line_blame_opts = {
virt_text = true,
virt_text_pos = "eol", -- 'eol' | 'overlay' | 'right_align'
delay = 1000,
ignore_whitespace = false,
},
current_line_blame_formatter = "<author>, <author_time:%Y-%m-%d> - <summary>",
sign_priority = 6,
update_debounce = 100,
status_formatter = nil, -- Use default
max_file_length = 40000, -- Disable if file is longer than this (in lines)
preview_config = {
-- Options passed to nvim_open_win
border = "single",
style = "minimal",
relative = "cursor",
row = 0,
col = 1,
},
yadm = {
enable = false,
},
})
end,
}
neotree.lua
nvim-neo-tree/neo-tree: Neovim plugin to manage the file system and other tree like structures.
-- ~/nvim/lua/slydragonn/plugins/neotree.lua
return {
"nvim-neo-tree/neo-tree.nvim",
branch = "v3.x",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-tree/nvim-web-devicons",
"MunifTanjim/nui.nvim",
-- "3rd/image.nvim", -- Optional image support in preview window: See `# Preview Mode` for more information
},
}
telescope.lua
nvim-telescope/telescope.nvim: Highly extendable fuzzy finder over lists.
-- ~/nvim/lua/slydragonn/plugins/telescope.lua
return {
"nvim-telescope/telescope.nvim",
tag = "0.1.6",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
require("telescope").setup()
-- set keymaps
local keymap = vim.keymap
keymap.set("n", "<leader>ff", "<cmd>Telescope find_files<cr>", { desc = "Fuzzy find files in cwd" })
keymap.set("n", "<leader>fg", "<cmd>Telescope live_grep<cr>", { desc = "Fuzzy find recent files" })
keymap.set("n", "<leader>fb", "<cmd>Telescope buffers<cr>", { desc = "Find string in cwd" })
keymap.set("n", "<leader>fs", "<cmd>Telescope git_status<cr>", { desc = "Find string under cursor in cwd" })
keymap.set("n", "<leader>fc", "<cmd>Telescope git commits<cr>", { desc = "Find todos" })
end,
}
toggleterm.lua
akinsho/toggleterm.nvim: A neovim lua plugin to help easily manage multiple terminal windows.
-- ~/nvim/lua/slydragonn/plugins/toggleterm.lua
return {
'akinsho/toggleterm.nvim',
version = "*",
config = function()
require("toggleterm").setup({
size = 10,
open_mapping = [[<F7>]],
shading_factor = 2,
direction = "float",
float_opts = {
border = "curved",
highlights = {
border = "Normal",
background = "Normal",
},
},
})
end,
}
When all plugins are added, we write the command :Lazy
and we press shift
+ L
to Install or shift
+ S
to sync.
Editor Key bindings
Inside of init.lua requires the maps file.
-- ~/nvim/init.lua
require("slydragonn.settings")
require("slydragonn.lazy")
require("slydragonn.maps") -- key bindings
maps.lua
-- ~/nvim/lua/slydragonn/maps.lua
vim.g.mapleader = " "
local function map(mode, lhs, rhs)
vim.keymap.set(mode, lhs, rhs, { silent = true })
end
-- Save
map("n", "<leader>w", "<CMD>update<CR>")
-- Quit
map("n", "<leader>q", "<CMD>q<CR>")
-- Exit insert mode
map("i", "jk", "<ESC>")
-- NeoTree
map("n", "<leader>e", "<CMD>Neotree toggle<CR>")
map("n", "<leader>r", "<CMD>Neotree focus<CR>")
-- New Windows
map("n", "<leader>o", "<CMD>vsplit<CR>")
map("n", "<leader>p", "<CMD>split<CR>")
-- Window Navigation
map("n", "<C-h>", "<C-w>h")
map("n", "<C-l>", "<C-w>l")
map("n", "<C-k>", "<C-w>k")
map("n", "<C-j>", "<C-w>j")
-- Resize Windows
map("n", "<C-Left>", "<C-w><")
map("n", "<C-Right>", "<C-w>>")
map("n", "<C-Up>", "<C-w>+")
map("n", "<C-Down>", "<C-w>-")
And that's it, with this setup you should have an amazing neovim editor.
📚 Resources
- My neovim setup with lazy.vim: https://github.com/slydragonn/nvim-lazy
- Youtube Video:
- Lazy.vim: https://github.com/folke/lazy.nvim
- Neovim resources: https://neovim.io/doc/user/lua.html#lua-intro
- Lua resources: https://www.lua.org/manual/5.4/
Thanks for reading and see you later!
Top comments (1)
thanks many usefull plugins indeed.