跳至主要內容

Neovim 配置入門:從零打造屬於自己的編輯器

Neovim 配置入門:從零打造屬於自己的編輯器

每個工程師的工具箱裡,文字編輯器是最貼身的一件。VS Code 憑藉著豐富的生態系統佔據了大半市場,但仍有不少開發者選擇 Neovim——一個看似古老,實則在這幾年因為 Lua 生態的崛起而重新煥發生機的編輯器。

這篇文章適合從未碰過 Neovim,或者用了 Neovim 但一直靠別人的 dotfiles 過活、想要真正理解配置方式的工程師。

為什麼選擇 Neovim?

  • 鍵盤驅動:熟練後手幾乎不需要離開鍵盤
  • 極速啟動:毫秒級啟動,適合在終端機中快速編輯
  • 完全可自訂:從按鍵到 UI,一切都可以用 Lua 程式碼控制
  • 低資源消耗:比 VS Code 少用大量記憶體
  • SSH 友善:遠端開發時不需要任何額外設定

安裝 Neovim

# macOS
brew install neovim

# Ubuntu / Debian
sudo apt install neovim

# 確認版本(建議 0.10+)
nvim --version

設定檔架構

Neovim 的設定檔位於 ~/.config/nvim/,建議的目錄結構:

~/.config/nvim/
├── init.lua              # 入口點
└── lua/
    ├── core/
    │   ├── options.lua   # 基本選項
    │   ├── keymaps.lua   # 按鍵映射
    │   └── autocmds.lua  # 自動命令
    └── plugins/
        ├── init.lua      # 套件管理
        ├── lsp.lua       # 語言伺服器
        ├── completion.lua # 自動完成
        └── ui.lua        # 介面

init.lua:入口點

-- ~/.config/nvim/init.lua
require("core.options")
require("core.keymaps")
require("core.autocmds")
require("plugins")

基本選項設定

-- ~/.config/nvim/lua/core/options.lua
local opt = vim.opt

-- 行號
opt.number = true         -- 顯示行號
opt.relativenumber = true -- 相對行號(方便移動)

-- 縮排
opt.tabstop = 2
opt.shiftwidth = 2
opt.expandtab = true      -- 用空格代替 Tab
opt.smartindent = true

-- 搜尋
opt.ignorecase = true     -- 搜尋忽略大小寫
opt.smartcase = true      -- 如果有大寫字母則區分大小寫

-- 顯示
opt.termguicolors = true  -- 開啟 24-bit 色彩
opt.signcolumn = "yes"    -- 永遠顯示符號欄
opt.cursorline = true     -- 高亮目前行
opt.wrap = false          -- 不換行
opt.scrolloff = 8         -- 游標上下保留 8 行
opt.sidescrolloff = 8

-- 檔案
opt.swapfile = false
opt.backup = false
opt.undofile = true       -- 持久化 undo 歷史

-- 分割視窗
opt.splitbelow = true     -- 水平分割在下方
opt.splitright = true     -- 垂直分割在右方

-- 效能
opt.updatetime = 50       -- 縮短更新延遲
opt.timeoutlen = 300

按鍵映射

-- ~/.config/nvim/lua/core/keymaps.lua
local keymap = vim.keymap.set

-- Leader 鍵
vim.g.mapleader = " "  -- 空白鍵作為 Leader

-- 基本移動(Normal mode)
keymap("n", "<C-h>", "<C-w>h", { desc = "移動到左視窗" })
keymap("n", "<C-j>", "<C-w>j", { desc = "移動到下視窗" })
keymap("n", "<C-k>", "<C-w>k", { desc = "移動到上視窗" })
keymap("n", "<C-l>", "<C-w>l", { desc = "移動到右視窗" })

-- 調整視窗大小
keymap("n", "<C-Up>", ":resize -2<CR>")
keymap("n", "<C-Down>", ":resize +2<CR>")
keymap("n", "<C-Left>", ":vertical resize -2<CR>")
keymap("n", "<C-Right>", ":vertical resize +2<CR>")

-- Buffer 切換
keymap("n", "<S-h>", ":bprevious<CR>", { desc = "前一個 buffer" })
keymap("n", "<S-l>", ":bnext<CR>", { desc = "下一個 buffer" })

-- 搜尋高亮
keymap("n", "<leader>h", ":nohlsearch<CR>", { desc = "清除搜尋高亮" })

-- 儲存與離開
keymap("n", "<leader>w", ":w<CR>", { desc = "儲存" })
keymap("n", "<leader>q", ":q<CR>", { desc = "離開" })

-- Visual mode:移動選取的行
keymap("v", "J", ":m '>+1<CR>gv=gv", { desc = "向下移動行" })
keymap("v", "K", ":m '<-2<CR>gv=gv", { desc = "向上移動行" })

-- 縮排時保持選取狀態
keymap("v", "<", "<gv")
keymap("v", ">", ">gv")

套件管理:lazy.nvim

lazy.nvim 是目前最推薦的 Neovim 套件管理器:

-- ~/.config/nvim/lua/plugins/init.lua

-- 自動安裝 lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not 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({
  -- 主題
  {
    "catppuccin/nvim",
    name = "catppuccin",
    priority = 1000,
    config = function()
      vim.cmd.colorscheme("catppuccin-mocha")
    end,
  },

  -- 狀態列
  {
    "nvim-lualine/lualine.nvim",
    dependencies = { "nvim-tree/nvim-web-devicons" },
    config = function()
      require("lualine").setup({
        options = { theme = "catppuccin" }
      })
    end,
  },

  -- 檔案瀏覽器
  {
    "nvim-tree/nvim-tree.lua",
    dependencies = { "nvim-tree/nvim-web-devicons" },
    config = function()
      require("nvim-tree").setup()
      vim.keymap.set("n", "<leader>e", ":NvimTreeToggle<CR>")
    end,
  },

  -- 模糊搜尋
  {
    "nvim-telescope/telescope.nvim",
    dependencies = { "nvim-lua/plenary.nvim" },
    config = function()
      local telescope = require("telescope.builtin")
      vim.keymap.set("n", "<leader>ff", telescope.find_files, { desc = "搜尋檔案" })
      vim.keymap.set("n", "<leader>fg", telescope.live_grep, { desc = "全文搜尋" })
      vim.keymap.set("n", "<leader>fb", telescope.buffers, { desc = "搜尋 buffer" })
    end,
  },

  -- 語法高亮
  {
    "nvim-treesitter/nvim-treesitter",
    build = ":TSUpdate",
    config = function()
      require("nvim-treesitter.configs").setup({
        ensure_installed = {
          "lua", "javascript", "typescript", "tsx",
          "vue", "python", "go", "rust", "json", "yaml"
        },
        highlight = { enable = true },
        indent = { enable = true },
      })
    end,
  },
})

LSP 設定

LSP(Language Server Protocol)讓 Neovim 擁有媲美 VS Code 的程式碼補全和診斷:

-- ~/.config/nvim/lua/plugins/lsp.lua
return {
  {
    "neovim/nvim-lspconfig",
    dependencies = {
      "williamboman/mason.nvim",
      "williamboman/mason-lspconfig.nvim",
    },
    config = function()
      require("mason").setup()
      require("mason-lspconfig").setup({
        ensure_installed = {
          "ts_ls",    -- TypeScript
          "pyright",  -- Python
          "lua_ls",   -- Lua
          "volar",    -- Vue
        }
      })

      local lspconfig = require("lspconfig")
      local on_attach = function(_, bufnr)
        local opts = { buffer = bufnr }
        vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
        vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
        vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
        vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
      end

      lspconfig.ts_ls.setup({ on_attach = on_attach })
      lspconfig.pyright.setup({ on_attach = on_attach })
    end,
  }
}

學習資源

  • :Tutor:Neovim 內建教學(在 Neovim 中直接輸入)
  • https://learnxinyminutes.com/docs/lua/:快速學習 Lua
  • kickstart.nvim:官方推薦的最小化起始設定

總結

Neovim 的學習曲線確實陡峭,但一旦熟悉後帶來的生產力提升是真實的。建議從一個最小化的設定開始,逐步加入需要的功能,而不是一開始就複製一個功能滿載的別人設定,因為你需要真正理解每一行設定的意義,才能在遇到問題時有能力除錯和調整。

分享這篇文章