Neovim · Part 2 — Cài đặt, cấu trúc Lua config và nền móng
Dựng cấu hình Neovim sạch từ đầu: init.lua, options, keymaps, autocommands, leader key, backup config và health check.
Phần này dựng nền móng: một config Neovim sạch, nhỏ, đọc được, đủ để mở project và không bị lạc.
Ta chưa cài plugin. Nếu nền không vững, plugin chỉ làm lỗi khó debug hơn.
Cấu trúc config
Neovim đọc config ở:
~/.config/nvim/
Trên Windows thường là:
~/AppData/Local/nvim/
Kiểm tra chính xác trong Nvim:
:echo stdpath('config')
:echo stdpath('data')
Tạo cấu trúc ban đầu:
~/.config/nvim/
├─ init.lua
└─ lua/
└─ config/
├─ options.lua
├─ keymaps.lua
└─ autocmds.lua
init.lua chỉ nên là cửa vào:
require("config.options")
require("config.keymaps")
require("config.autocmds")
Quy tắc: file nào làm việc nấy. Đừng để init.lua thành một bức tường 1000 dòng.
Options nền tảng
Tạo lua/config/options.lua:
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
local opt = vim.opt
opt.number = true
opt.relativenumber = true
opt.mouse = "a"
opt.clipboard = "unnamedplus"
opt.breakindent = true
opt.undofile = true
opt.ignorecase = true
opt.smartcase = true
opt.signcolumn = "yes"
opt.updatetime = 250
opt.timeoutlen = 400
opt.splitright = true
opt.splitbelow = true
opt.list = true
opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" }
opt.inccommand = "split"
opt.cursorline = true
opt.scrolloff = 8
opt.expandtab = true
opt.shiftwidth = 2
opt.tabstop = 2
opt.smartindent = true
Giải thích nhanh:
| Option | Vì sao bật |
|---|---|
number | biết dòng hiện tại |
relativenumber | motion theo số dòng dễ hơn |
undofile | undo còn sau khi đóng file |
signcolumn=yes | diagnostic/git sign không làm layout nhảy |
splitright/splitbelow | split giống trực giác hiện đại |
ignorecase/smartcase | search thường thông minh hơn |
clipboard=unnamedplus | copy/paste với system clipboard |
Nếu clipboard không hoạt động, chạy :checkhealth provider. Trên Linux bạn có thể cần xclip, xsel, wl-clipboard, hoặc OSC 52 tùy terminal/SSH.
Keymaps đầu tiên
Tạo lua/config/keymaps.lua:
local map = vim.keymap.set
map("n", "<Esc>", "<cmd>nohlsearch<CR>", { desc = "Clear search highlight" })
map("n", "<leader>w", "<cmd>write<CR>", { desc = "Save file" })
map("n", "<leader>q", "<cmd>quit<CR>", { desc = "Quit window" })
map("n", "<C-h>", "<C-w><C-h>", { desc = "Move to left window" })
map("n", "<C-j>", "<C-w><C-j>", { desc = "Move to lower window" })
map("n", "<C-k>", "<C-w><C-k>", { desc = "Move to upper window" })
map("n", "<C-l>", "<C-w><C-l>", { desc = "Move to right window" })
map("v", "J", ":m '>+1<CR>gv=gv", { desc = "Move selection down" })
map("v", "K", ":m '<-2<CR>gv=gv", { desc = "Move selection up" })
desc quan trọng. Các plugin như which-key, picker, hoặc help UI có thể đọc mô tả này.
Leader key nên đặt trước khi plugin load. Series này dùng Space.
Autocommands nhỏ nhưng đáng tiền
Tạo lua/config/autocmds.lua:
local group = vim.api.nvim_create_augroup("user_config", { clear = true })
vim.api.nvim_create_autocmd("TextYankPost", {
group = group,
desc = "Highlight yanked text",
callback = function()
vim.highlight.on_yank()
end,
})
vim.api.nvim_create_autocmd("BufReadPost", {
group = group,
desc = "Jump to last edit position",
callback = function()
local mark = vim.api.nvim_buf_get_mark(0, '"')
local line_count = vim.api.nvim_buf_line_count(0)
if mark[1] > 0 and mark[1] <= line_count then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
})
Autocmd là nơi gắn hành vi theo sự kiện: sau khi yank, sau khi đọc file, trước khi save, khi FileType đổi.
Lệnh sống còn
| Lệnh | Ý nghĩa |
|---|---|
:source % | reload file config đang mở |
:messages | xem lỗi/message gần đây |
:checkhealth | kiểm tra môi trường |
:verbose set option? | biết option được set ở đâu |
:map | xem keymap |
:verbose map <leader>w | keymap này đến từ đâu |
:lua =vim.opt.shiftwidth:get() | inspect Lua value |
:h option-list | mở docs option |
Khi config lỗi, đừng xóa bừa. Dùng :messages, :checkhealth, và :verbose.
Backup trước khi phá
Nếu bạn đã có config cũ:
mv ~/.config/nvim ~/.config/nvim.bak
mv ~/.local/share/nvim ~/.local/share/nvim.bak
mv ~/.local/state/nvim ~/.local/state/nvim.bak
mv ~/.cache/nvim ~/.cache/nvim.bak
Sau đó tạo config mới. Nếu muốn quay lại, đổi tên .bak về chỗ cũ.
Đừng xóa thẳng khi chưa hiểu. Config editor là công cụ làm việc hằng ngày; đối xử với nó như source code.
Bài tập
- Tạo cấu trúc config như trên.
- Mở
nvim ~/.config/nvim/init.lua, chạy:source %. - Bật/tắt
relativenumberbằng:set relativenumber!. - Tạo keymap
<leader>xđể đóng buffer hoặc quit window. - Dùng
:verbose map <leader>wđể xem keymap đến từ đâu.
Lời giải gợi ý
vim.keymap.set("n", "<leader>x", "<cmd>quit<CR>", { desc = "Close window" })Nếu muốn đóng buffer sau này, khi đã có plugin bufferline hoặc mini.bufremove, ta sẽ map lại. Giai đoạn đầu cứ giữ đơn giản.
Điều cốt lõi
Một config Neovim tốt bắt đầu từ options ít, keymaps rõ, autocmds có tên, và mọi thứ chia file vừa đủ. Plugin chưa cần xuất hiện cho tới khi bạn biết nền này đang làm gì.