Lua Session 04: Plugins

Plugin management. This session covers lazy.nvim plugin specs, module organization, and lazy loading patterns.

Pre-Session State

  • Know vim.opt, vim.keymap, vim.api

  • Understand autocommands

  • Can create user commands

Lesson 1: lazy.nvim Basics

Concept: lazy.nvim uses declarative plugin specs.

Exercise 1.1: Simple plugin spec

-- Minimal spec (just the repo)
return {
    "nvim-lua/plenary.nvim"
}

Exercise 1.2: Plugin with options

return {
    "folke/which-key.nvim",
    event = "VeryLazy",  -- Load lazily
    opts = {
        -- Options passed to setup()
        plugins = {
            spelling = { enabled = true }
        }
    }
}

Exercise 1.3: Plugin with config function

return {
    "nvim-treesitter/nvim-treesitter",
    build = ":TSUpdate",
    config = function()
        require("nvim-treesitter.configs").setup({
            ensure_installed = { "lua", "python", "bash" },
            highlight = { enable = true },
        })
    end
}

Lesson 2: Lazy Loading

Concept: Load plugins only when needed for faster startup.

Exercise 2.1: Load on event

return {
    "numToStr/Comment.nvim",
    event = { "BufReadPre", "BufNewFile" },  -- Load when opening file
    opts = {}
}

Exercise 2.2: Load on filetype

return {
    "mfussenegger/nvim-dap-python",
    ft = "python",  -- Load only for Python files
    config = function()
        require("dap-python").setup("python")
    end
}

Exercise 2.3: Load on command

return {
    "folke/trouble.nvim",
    cmd = { "Trouble", "TroubleToggle" },  -- Load when command used
    opts = {}
}

Exercise 2.4: Load on keymap

return {
    "nvim-telescope/telescope.nvim",
    keys = {
        { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
        { "<leader>fg", "<cmd>Telescope live_grep<cr>", desc = "Live Grep" },
    },
    opts = {}
}

Lesson 3: Dependencies

Concept: Declare plugin dependencies for load ordering.

Exercise 3.1: Simple dependency

return {
    "nvim-telescope/telescope.nvim",
    dependencies = {
        "nvim-lua/plenary.nvim"  -- Required by telescope
    },
    opts = {}
}

Exercise 3.2: Multiple dependencies

return {
    "nvim-telescope/telescope.nvim",
    dependencies = {
        "nvim-lua/plenary.nvim",
        "nvim-tree/nvim-web-devicons",
        {
            "nvim-telescope/telescope-fzf-native.nvim",
            build = "make"
        }
    },
    config = function()
        require("telescope").setup({})
        require("telescope").load_extension("fzf")
    end
}

Lesson 4: Module Structure

Concept: Organize plugins in separate files.

Exercise 4.1: Directory structure

~/.config/nvim/
├── init.lua                    -- Bootstrap lazy.nvim
├── lua/
│   └── plugins/
│       ├── init.lua            -- Empty or imports
│       ├── colorscheme.lua     -- Theme plugins
│       ├── editor.lua          -- Editor enhancements
│       ├── lsp.lua             -- LSP configuration
│       └── telescope.lua       -- Fuzzy finder

Exercise 4.2: Loading plugin directory

-- init.lua
require("lazy").setup({
    spec = {
        { import = "plugins" }  -- Load all from lua/plugins/
    }
})

Exercise 4.3: Single plugin file

-- lua/plugins/telescope.lua
return {
    "nvim-telescope/telescope.nvim",
    dependencies = { "nvim-lua/plenary.nvim" },
    keys = {
        { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
    },
    opts = {
        defaults = {
            layout_strategy = "horizontal",
        }
    }
}

Exercise 4.4: Multiple plugins in one file

-- lua/plugins/editor.lua
return {
    -- Comment.nvim
    {
        "numToStr/Comment.nvim",
        event = { "BufReadPre", "BufNewFile" },
        opts = {}
    },

    -- Autopairs
    {
        "windwp/nvim-autopairs",
        event = "InsertEnter",
        opts = {}
    },

    -- Surround
    {
        "kylechui/nvim-surround",
        event = "VeryLazy",
        opts = {}
    }
}

Summary: What You Learned

Concept Syntax Example

Plugin spec

{ "owner/repo" }

{ "folke/which-key.nvim" }

opts

opts = {}

Passed to setup()

config

config = function()…​end

Custom configuration

event

event = "VeryLazy"

Load on event

ft

ft = "python"

Load on filetype

cmd

cmd = {"Cmd"}

Load on command

keys

keys = {{lhs, rhs}}

Load on keymap

dependencies

dependencies = {}

Load order

import

{ import = "dir" }

Load plugin files

Exercises to Complete

  1. [ ] Create a plugin spec for Comment.nvim with lazy loading

  2. [ ] Add telescope with keymaps and dependencies

  3. [ ] Organize your plugins into separate files

  4. [ ] Add a filetype-specific plugin (e.g., markdown preview)

Next Session

Session 05: LSP - lspconfig, mason, diagnostics.

Session Log

Timestamp Notes

Start

<Record when you started>

End

<Record when you finished>