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/dotfiles repo.
⚙ 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 (2)
thanks many usefull plugins indeed.
Thank you for the instructional!
Just one question. You mentioned that we should create the plugin within
~/nvim/lua/plugins/
. Should it not be~/nvim/lua/slydragonn/plugins/
? as you mention later on at the top of your respective plugins's code?