這是 Neovim 從零開始系列的第八篇。整個系列共 12 篇文章,將帶你從完全不懂 Vim,到能用 Neovim 打造一個完整的現代化開發環境。
本篇的目標
經過前幾篇的設定,你的 Neovim 已經有了 LSP 和自動補全。這篇要加入三個讓開發體驗再度提升的功能:
- Treesitter:基於語法樹的精確高亮和文字操作
- Telescope:強大的模糊搜尋(取代 VSCode 的 Cmd+P)
- oil.nvim:檔案瀏覽器(取代 VSCode 的左側邊欄)
Treesitter:真正理解你的程式碼
傳統語法高亮 vs Treesitter
傳統的語法高亮用正則表達式來匹配——它只看文字模式,不懂程式碼結構。這導致:
- 複雜的語法可能標錯顏色
- 巢狀結構容易混亂
- 不同語言嵌套(如 HTML 中的 JavaScript)效果差
Treesitter 完全不同——它解析程式碼為語法樹(AST),真正理解程式碼的結構。好處是:
- 語法高亮更精確(區分函數名、變數、型別、常數等)
- 支援增量解析(編輯時只重新解析修改的部分,非常快)
- 提供基於語法結構的文字操作(如選取整個函數)
安裝 Treesitter
-- lua/plugins/treesitter.lua
return {
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
event = "BufReadPost",
dependencies = {
"nvim-treesitter/nvim-treesitter-textobjects",
},
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = {
"lua", "vim", "vimdoc",
"javascript", "typescript", "tsx",
"go", "gomod", "gosum",
"python",
"html", "css", "json", "yaml", "toml",
"markdown", "markdown_inline",
"bash", "dockerfile",
"gitcommit", "diff",
},
auto_install = true,
highlight = {
enable = true,
},
indent = {
enable = true,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-space>",
node_incremental = "<C-space>",
scope_incremental = false,
node_decremental = "<bs>",
},
},
})
end,
}
增量選取
上面設定中的 incremental_selection 是一個非常好用的功能:
- 按
Ctrl+Space開始選取(選取目前的語法節點) - 再按
Ctrl+Space擴大選取(選取父節點) - 按
Backspace縮小選取
// 游標在 "hello" 上
const msg = "hello world"
// Ctrl+Space → 選取 "hello world"(字串內容)
// Ctrl+Space → 選取 "hello world"(含引號)
// Ctrl+Space → 選取 msg = "hello world"(賦值表達式)
// Ctrl+Space → 選取整行(宣告語句)
這比手動用 Visual mode 精確多了。
Treesitter Text Objects
安裝 nvim-treesitter-textobjects 後,你可以用語法結構來操作:
-- 加在 treesitter.lua 的 config 中
textobjects = {
select = {
enable = true,
lookahead = true,
keymaps = {
["af"] = "@function.outer", -- 選取整個函數
["if"] = "@function.inner", -- 選取函數內容
["ac"] = "@class.outer", -- 選取整個 class
["ic"] = "@class.inner", -- 選取 class 內容
["aa"] = "@parameter.outer", -- 選取參數(含逗號)
["ia"] = "@parameter.inner", -- 選取參數(不含逗號)
},
},
move = {
enable = true,
set_jumps = true,
goto_next_start = {
["]f"] = "@function.outer", -- 跳到下一個函數
["]c"] = "@class.outer", -- 跳到下一個 class
},
goto_previous_start = {
["[f"] = "@function.outer", -- 跳到上一個函數
["[c"] = "@class.outer", -- 跳到上一個 class
},
},
},
現在你可以:
| 指令 | 功能 |
|---|---|
daf |
刪除整個函數 |
vif |
選取函數內容 |
yaf |
複製整個函數 |
cia |
修改一個參數 |
]f |
跳到下一個函數 |
[f |
跳到上一個函數 |
這些操作理解程式碼結構,不再只是文字模式匹配。
Telescope:萬能模糊搜尋
Telescope 是 Neovim 生態中最重要的 plugin 之一。它提供了一個統一的模糊搜尋介面,可以搜尋幾乎任何東西:檔案、文字、Git 記錄、LSP 符號等。
前置需求
Telescope 需要幾個外部工具來發揮最佳效能:
# ripgrep — 極快的文字搜尋
brew install ripgrep
# fd — 極快的檔案搜尋
brew install fd
安裝 Telescope
-- lua/plugins/telescope.lua
return {
"nvim-telescope/telescope.nvim",
branch = "0.1.x",
dependencies = {
"nvim-lua/plenary.nvim",
{
"nvim-telescope/telescope-fzf-native.nvim",
build = "make",
},
},
config = function()
local telescope = require("telescope")
local actions = require("telescope.actions")
telescope.setup({
defaults = {
path_display = { "truncate" },
sorting_strategy = "ascending",
layout_config = {
horizontal = {
prompt_position = "top",
preview_width = 0.55,
},
width = 0.87,
height = 0.80,
},
mappings = {
i = {
["<C-j>"] = actions.move_selection_next,
["<C-k>"] = actions.move_selection_previous,
["<C-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
["<Esc>"] = actions.close,
},
},
file_ignore_patterns = {
"node_modules",
".git/",
"dist/",
"build/",
"%.lock",
},
},
pickers = {
find_files = {
hidden = true,
},
},
})
-- 載入 fzf extension(加快搜尋速度)
telescope.load_extension("fzf")
-- 快捷鍵
local builtin = require("telescope.builtin")
-- 檔案搜尋
vim.keymap.set("n", "<leader>ff", builtin.find_files, { desc = "Find files" })
vim.keymap.set("n", "<leader>fr", builtin.oldfiles, { desc = "Recent files" })
vim.keymap.set("n", "<leader>fb", builtin.buffers, { desc = "Find buffers" })
-- 文字搜尋
vim.keymap.set("n", "<leader>fg", builtin.live_grep, { desc = "Live grep" })
vim.keymap.set("n", "<leader>fw", builtin.grep_string, { desc = "Grep word under cursor" })
-- Git
vim.keymap.set("n", "<leader>gc", builtin.git_commits, { desc = "Git commits" })
vim.keymap.set("n", "<leader>gs", builtin.git_status, { desc = "Git status" })
-- LSP
vim.keymap.set("n", "<leader>fs", builtin.lsp_document_symbols, { desc = "Document symbols" })
vim.keymap.set("n", "<leader>fS", builtin.lsp_workspace_symbols, { desc = "Workspace symbols" })
-- 其他
vim.keymap.set("n", "<leader>fh", builtin.help_tags, { desc = "Help tags" })
vim.keymap.set("n", "<leader>fd", builtin.diagnostics, { desc = "Diagnostics" })
vim.keymap.set("n", "<leader>fk", builtin.keymaps, { desc = "Keymaps" })
end,
}
Telescope 快捷鍵 vs VSCode 對照
| Telescope | 功能 | VSCode 對應 |
|---|---|---|
<leader>ff |
搜尋檔案 | Cmd+P |
<leader>fg |
全域文字搜尋 | Cmd+Shift+F |
<leader>fb |
切換 Buffer | Cmd+Tab |
<leader>fr |
最近開啟的檔案 | Cmd+P 歷史 |
<leader>fw |
搜尋游標下的文字 | 選取文字 → Cmd+Shift+F |
<leader>fs |
搜尋文件中的符號 | Cmd+Shift+O |
<leader>fh |
搜尋幫助文件 | — |
Telescope 內的操作
| 快捷鍵 | 功能 |
|---|---|
<C-j> / <C-k> |
上下移動選擇 |
<CR> |
開啟選中項目 |
<C-x> |
水平分割開啟 |
<C-v> |
垂直分割開啟 |
<C-q> |
發送到 quickfix list |
<Esc> |
關閉 |
使用技巧
模糊搜尋語法(在搜尋框中):
| 語法 | 功能 |
|---|---|
foo |
模糊匹配 foo |
'exact |
精確匹配 exact |
^prefix |
前綴匹配 |
suffix$ |
後綴匹配 |
!exclude |
排除包含 exclude 的結果 |
例如:搜尋 'spec .ts$ 會找到所有精確包含 “spec” 且以 “.ts” 結尾的檔案。
oil.nvim:檔案瀏覽器
在 VSCode 中你習慣左側的檔案樹。在 Neovim 中,oil.nvim 提供了一個更 Vim-native 的方案——它把目錄當成一個可編輯的 buffer。你可以用 Vim 的所有操作來管理檔案。
-- lua/plugins/oil.lua
return {
"stevearc/oil.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
config = function()
require("oil").setup({
default_file_explorer = true,
columns = {
"icon",
},
view_options = {
show_hidden = true,
},
keymaps = {
["g?"] = "actions.show_help",
["<CR>"] = "actions.select",
["<C-v>"] = "actions.select_vsplit",
["<C-s>"] = "actions.select_split",
["-"] = "actions.parent",
["_"] = "actions.open_cwd",
["`"] = "actions.cd",
["g."] = "actions.toggle_hidden",
},
})
vim.keymap.set("n", "-", "<CMD>Oil<CR>", { desc = "Open file explorer" })
end,
}
oil.nvim 的操作
| 操作 | 功能 |
|---|---|
- |
打開檔案瀏覽器(或返回上層目錄) |
<CR> |
進入目錄 / 開啟檔案 |
| 在 buffer 中新增一行文字 | 建立新檔案 |
在 buffer 中刪除一行 (dd) |
刪除檔案 |
| 在 buffer 中修改檔名 | 重新命名檔案 |
:w |
確認所有變更 |
是的,你沒看錯——用 Vim 的編輯操作來管理檔案。新增一行就是新增檔案,刪除一行就是刪除檔案。這就是 Vim 哲學的精髓。
另一個選擇:neo-tree
如果你比較習慣 VSCode 風格的側邊欄檔案樹,可以用 neo-tree:
-- lua/plugins/neo-tree.lua(替代方案)
return {
"nvim-neo-tree/neo-tree.nvim",
branch = "v3.x",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-tree/nvim-web-devicons",
"MunifTanjim/nui.nvim",
},
config = function()
require("neo-tree").setup({
close_if_last_window = true,
filesystem = {
follow_current_file = { enabled = true },
filtered_items = {
visible = true,
hide_dotfiles = false,
},
},
})
vim.keymap.set("n", "<leader>e", ":Neotree toggle<CR>", { desc = "Toggle file explorer" })
end,
}
我個人推薦 oil.nvim——它更符合 Vim 的思維方式。但如果你剛從 VSCode 轉過來,neo-tree 的側邊欄可能更親切。
功能對照總表
以下整理本篇設定的功能與 VSCode 的對照:
| 功能 | VSCode | Neovim |
|---|---|---|
| 語法高亮 | 內建 | Treesitter |
| 搜尋檔案 | Cmd+P |
<leader>ff (Telescope) |
| 全域搜尋 | Cmd+Shift+F |
<leader>fg (Telescope) |
| 搜尋符號 | Cmd+Shift+O |
<leader>fs (Telescope) |
| 切換檔案 | Cmd+Tab |
<leader>fb (Telescope) |
| 檔案瀏覽器 | 側邊欄 | - (oil.nvim) |
| 選取函數 | 手動選取 | vaf (Treesitter) |
| 跳到下個函數 | — | ]f (Treesitter) |
驗證安裝
重啟 Neovim 後,確認以下幾點:
- Treesitter:打開一個程式碼檔案,語法高亮應該更精確(變數、函數、型別有不同顏色)
- Telescope:按
<leader>ff,應該出現模糊搜尋檔案的介面 - Telescope grep:按
<leader>fg,輸入文字應該能全域搜尋 - oil.nvim:按
-,應該看到當前目錄的檔案列表
如果 Treesitter 的高亮不正確,執行 :TSUpdate 更新所有語法解析器。
小結
到這裡,設定篇的四篇文章就完成了。你的 Neovim 已經具備:
| 功能 | 提供者 |
|---|---|
| 基本配置 | init.lua (options + keymaps) |
| Plugin 管理 | lazy.nvim |
| 漂亮外觀 | catppuccin + lualine |
| 程式碼智能 | LSP + nvim-cmp |
| 精確語法高亮 | Treesitter |
| 模糊搜尋 | Telescope |
| 檔案瀏覽 | oil.nvim |
這已經是一個非常強大的開發環境了!接下來的進階篇會加入更多工作流整合:Git、Terminal、快捷鍵系統。
下一篇,我們來整合 Git 工作流——讓你在 Neovim 中完成所有 Git 操作。
Neovim 系列文章導航
基礎篇
設定篇 5. 安裝 Neovim 與 init.lua 6. Plugin 管理 lazy.nvim 7. 程式碼智能 LSP + 補全 8. 語法高亮與檔案導航(本篇)
進階篇 9. Git 整合工作流 10. Terminal 與 Claude Code 整合 11. 打造快捷鍵系統 12. 從 VSCode 完全畢業