DEV Community

Cover image for Ultimate Neovim Setup Guide: lazy.nvim Plugin Manager
Alejandro LondoΓ±o
Alejandro LondoΓ±o

Posted on

Ultimate Neovim Setup Guide: lazy.nvim Plugin Manager

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

✨ Features

πŸ“š Project Structure

πŸ“‚ nvim/
β”œβ”€β”€ πŸ“‚ lua/πŸ“‚ slydragonn/
β”‚  └── πŸ“‚ plugins/
β”‚        └── πŸ“‚ lsp/
β”‚        └── ...pluginconfigfiles
β”‚  └── πŸŒ‘ settings.lua
β”‚  └── πŸŒ‘ maps.lua
β”‚    └── πŸŒ‘ lazy.lua
└── πŸŒ‘ init.lua
Enter fullscreen mode Exit fullscreen mode

If you don’t have some requirements

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")
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

Then in the init.lua file we import the lazy config:

-- ~/nvim/init.lua

require("slydragonn.settings")
require("slydragonn.lazy")
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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
    },
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>-")
Enter fullscreen mode Exit fullscreen mode

And that's it, with this setup you should have an amazing neovim editor.

πŸ“š Resources

Thanks for reading and see you later!

Top comments (0)