Back to blog
Development Tools

Building a Modern Neovim Config with Lua and Lazy.nvim

Abdeldjalile Lafkir2024-11-093 min read

Building a Modern Neovim Config

Neovim has become my editor of choice due to its blazing speed and infinite extensibility. In this post, I'll dissect my configuration, which focuses on a clean UI, robust LSP support, and seamless navigation.

The Architecture: Lazy.nvim

I use lazy.nvim as my plugin manager. It allows for a highly modular structure where every plugin category gets its own file.

My init.lua is surprisingly simple. It bootstraps lazy and imports the plugin specifications:

-- init.lua
require("lazy").setup({
  { import = "plugins.core" },       -- Themes, Dashboard
  { import = "plugins.ui" },         -- Neo-tree, Noice
  { import = "plugins.editing" },    -- Treesitter, Comments
  { import = "plugins.completion" }, -- Cmp, Snippets
  { import = "plugins.lsp" },        -- LSP Config
  { import = "plugins.formatting" }, -- Conform, None-ls
  { import = "plugins.utilities" },  -- Copilot, Which-key
}, {
  defaults = { lazy = true },
  checker = { enabled = false },
})

Core Settings

Before loading plugins, I set reasonable defaults in lua/core/options.lua. A few highlights include:

  • relativenumber = true: Essential for relative jumps.
  • clipboard = 'unnamedplus': Syncs the system clipboard with Neovim.
  • scrolloff = 4: Keeps context visible above and below the cursor.
  • undofile = true: Persists undo history even after closing the file.

Keymaps & Workflow

I've mapped my Leader key to <Space>, which is ergonomic and standard for modern setups. You can find my full list in lua/core/keymaps.lua.

Window Management

I avoid using the mouse for window resizing or navigation:

-- Resize with arrows
vim.keymap.set("n", "<Up>", ":resize -2<CR>", opts)
vim.keymap.set("n", "<Down>", ":resize +2<CR>", opts)

-- Navigate splits using Leader + hjkl
vim.keymap.set("n", "<leader>h", ":wincmd h<CR>", opts)
vim.keymap.set("n", "<leader>l", ":wincmd l<CR>", opts)

File Operations

Quick saving and quitting are muscle memory:

vim.keymap.set("n", "<leader>s", "<cmd>w<CR>", { desc = "Save file" })
vim.keymap.set("n", "<leader>q", "<cmd>q<CR>", { desc = "Exit vim" })

The Visual Stack

Aesthetics play a huge role in productivity. I use the GitHub Dark Default theme via github-nvim-theme to match the rest of my developer environment.

For the interface, I use:

  • Neo-tree: A file explorer that supports git status and icons.
  • Lualine: A fast and configurable status line.
  • Noice.nvim: Replaces the command line with nice popups and notifications.

Intelligence: LSP & Completion

My IDE-like features are powered by Native LSP and nvim-cmp.

I use mason.nvim to manage language servers like clangd (C++), pyright (Python), and ts_ls (TypeScript). Formatting is handled by conform.nvim, which ensures my code is always clean on save.

-- lua/plugins/formatting.lua
format_on_save = function(bufnr)
  return { timeout_ms = 500, lsp_fallback = true }
end

I've also integrated GitHub Copilot for AI-powered suggestions, mapped to <Tab> for seamless acceptance.

Conclusion

This configuration strikes a balance between a minimal editor and a full-blown IDE. It starts fast, looks great, and provides all the tools I need for heavy coding sessions in C++, Lua, or Web Development.

Feel free to fork my setup from my GitHub repository!