Skip to content
Neovim IDE

My Neovim Configuration

Here you will find the structure and configuration of the Neovim setup I implemented

Why use Lua to configure Neovim?

Directory Structure

The Neovim structure with Lua follows a modular pattern that separates settings by category:

  • init.lua
  • lazy-lock.json
  • .luarc.json
  • Directorylua/
    • Directoryconfig/
      • autocmds.lua
      • keymaps.lua
      • lazy.lua
      • options.lua
      • theme.lua
    • Directoryplugins/
      • init.lua
      • Directorygit-manager/
        • …
      • Directoryinterface/
        • …
      • Directorylsp/
        • …
      • Directorymarkdown/
        • …
      • Directoryprogramming/
        • …

Main File: init.lua

init.lua is the entry point of the configuration. It should be minimal, delegating the work to smaller modules:

init.lua
-- Enables the Lua module cache (huge startup gain on Neovim 0.9+).
if vim.loader and vim.loader.enable then
vim.loader.enable()
end
-- Leader keys must be set before any plugin spec is loaded.
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Loads the configuration modules.
require("config.options")
require("config.lazy")
require("config.keymaps")
require("config.autocmds")

Why this order?

  1. options first: Basic settings that do not depend on plugins
  2. lazy next: The plugin manager must be loaded before the plugins
  3. keymaps: Mappings that work without specific plugins
  4. autocmds: Events that depend on other settings

Configuration Modules (lua/config/)

options.lua

Pure Neovim settings that do not require plugins:

options.lua
local opt = vim.opt
-- Indentation
opt.expandtab = true -- converts tabs to spaces
opt.tabstop = 2 -- visual width of a tab
opt.softtabstop = 2 -- spaces inserted when pressing <Tab>
opt.shiftwidth = 2 -- spaces used for auto-indent
opt.autoindent = true -- copies indent from the current line
opt.smartindent = true -- smart indentation for new lines
-- UI
opt.number = true -- shows absolute line numbers
opt.relativenumber = false -- set to true for hybrid numbers
opt.cursorline = true -- highlights the current line
opt.signcolumn = "yes" -- always renders the sign column
opt.termguicolors = true -- 24-bit colors
opt.showmode = false -- the mode is shown by lualine

lazy.lua

Bootstrap of the lazy.nvim plugin manager:

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",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
spec = {
{ import = "plugins" }, -- Imports all plugins from lua/plugins/
},
defaults = {
lazy = false, -- plugins opt in to lazy loading
version = false, -- always uses the latest commit
},
performance = {
cache = { enabled = true },
rtp = {
disabled_plugins = {
"gzip", "tarPlugin", "tohtml", "tutor", "zipPlugin",
"netrwPlugin", "matchit", "matchparen", "spellfile",
},
},
},
})

keymaps.lua

Global mappings that do not depend on specific plugins:

keymaps.lua
local map = function(mode, lhs, rhs, opts)
opts = vim.tbl_extend("force", { silent = true }, opts or {})
vim.keymap.set(mode, lhs, rhs, opts)
end
-- Window navigation
map("n", "<C-h>", "<C-w>h", { desc = "Window: move left" })
map("n", "<C-j>", "<C-w>j", { desc = "Window: move down" })
map("n", "<C-k>", "<C-w>k", { desc = "Window: move up" })
map("n", "<C-l>", "<C-w>l", { desc = "Window: move right" })
-- Clear search highlight
map("n", "<Esc>", "<cmd>nohlsearch<cr>", { desc = "Clear search highlight" })

autocmds.lua

Lightweight autocommands for Neovim events:

autocmds.lua
-- Briefly highlights the yanked region
vim.api.nvim_create_autocmd("TextYankPost", {
group = augroup("highlight_yank"),
callback = function() vim.highlight.on_yank({ timeout = 150 }) end,
})
-- Removes trailing whitespace on save (except markdown)
vim.api.nvim_create_autocmd("BufWritePre", {
group = augroup("trim_whitespace"),
callback = function()
if vim.bo.filetype == "markdown" or vim.bo.filetype == "mdx" then return end
local save = vim.fn.winsaveview()
vim.cmd([[keepjumps %s/\s\+$//e]])
vim.fn.winrestview(save)
end,
})

theme.lua

Shared color palette used by all plugins:

theme.lua
return {
-- Backgrounds
bg = "#0d0d0d", -- primary background
bg_alt = "#0d0d0d", -- elevated surfaces
bg_float = "#0d0d0d", -- floating windows
-- Foregrounds
fg = "#c9d1d9", -- primary text
fg_strong = "#e6edf3", -- titles, focused elements
fg_muted = "#6e7681", -- comments, hints
-- Semantic accents
green = "#3fb950", -- success, additions
blue = "#58a6ff", -- info, links
orange = "#e8912d", -- warnings
red = "#ff7b72", -- errors, deletions
yellow = "#d29922", -- caution, modifications
purple = "#bc8cff", -- C# / .NET accent
}

Plugin System (lua/plugins/)

plugins/init.lua

Loader that imports the plugin groups:

plugins/init.lua
return {
{ import = "plugins.interface" },
{ import = "plugins.lsp" },
{ import = "plugins.markdown" },
{ import = "plugins.programming" },
{ import = "plugins.git-manager" },
}

Organization by Category

Each category is a directory with an individual .lua file for each plugin:

  • interface/: UI plugins (telescope, neotree, dashboard, etc.)
  • lsp/: LSP plugins (nvim-lspconfig, mason, nvim-dap)
  • programming/: Development plugins (cmp, neotest, comment, etc.)
  • git-manager/: Git plugins (gitsigns, lazygit)
  • markdown/: Markdown-specific plugins

How to Configure Neovim to Read Lua Files

  1. Create the configuration directory

    Creating the directory on Windows
    mkdir $env:LOCALAPPDATA\nvim
  2. Create the init.lua file

    Creating init.lua on Windows
    New-Item -Path "$env:LOCALAPPDATA\nvim\init.lua" -ItemType File
  3. Add the directory structure

    Creating the structure on Windows
    mkdir $env:LOCALAPPDATA\nvim\lua
    mkdir $env:LOCALAPPDATA\nvim\lua\config
    mkdir $env:LOCALAPPDATA\nvim\lua\plugins
  4. Copy the configuration files

    Copy the files from your Neovim repository into the corresponding directories.

  5. Restart Neovim

    Restarting Neovim
    nvim

    lazy.nvim will automatically install the plugins on the first run.