Wiki LogoWiki - The Power of Many

W10: 结构化导航

引入 Treesitter 语法树高亮与 Telescope 异步模糊搜索系统, 重塑全域精确导航体验.

1. Treesitter: 语法树革命

传统的高亮基于脆弱的 Regex. nvim-treesitter 将代码实时解析为抽象语法树 (AST).

1.1 Treesitter 带来的变革

特性传统正则Treesitter
高亮准确性猜测精确语义
缩进基于字符基于语法结构
文本对象固定可按函数/类选择
性能中等增量解析, 极快

1.2 安装配置

-- plugins/treesitter.lua
return {
    {
        "nvim-treesitter/nvim-treesitter",
        build = ":TSUpdate",
        event = { "BufReadPre", "BufNewFile" },
        dependencies = {
            "nvim-treesitter/nvim-treesitter-textobjects",
        },
        config = function()
            require("nvim-treesitter.configs").setup({
                ensure_installed = {
                    "lua", "vim", "vimdoc",
                    "go", "python", "rust", "javascript", "typescript",
                    "json", "yaml", "toml", "markdown", "markdown_inline",
                    "bash", "dockerfile", "sql",
                },
                auto_install = true,
                highlight = {
                    enable = true,
                    additional_vim_regex_highlighting = false,
                },
                indent = {
                    enable = true,
                },
                incremental_selection = {
                    enable = true,
                    keymaps = {
                        init_selection = "<C-space>",
                        node_incremental = "<C-space>",
                        node_decremental = "<BS>",
                        scope_incremental = false,
                    },
                },
            })
        end,
    },
}

1.3 增量选择

基于语法逻辑智能扩展选择范围:

光标在变量上:

按 <C-space> → 选中变量
再按 <C-space> → 选中表达式
再按 <C-space> → 选中语句
再按 <C-space> → 选中函数体
按 <BS> → 缩小选择

1.4 Treesitter 文本对象

-- 配置 textobjects
textobjects = {
    select = {
        enable = true,
        lookahead = true,
        keymaps = {
            ["af"] = "@function.outer",   -- 选中整个函数
            ["if"] = "@function.inner",   -- 选中函数体
            ["ac"] = "@class.outer",      -- 选中整个类
            ["ic"] = "@class.inner",      -- 选中类体
            ["aa"] = "@parameter.outer",  -- 选中参数
            ["ia"] = "@parameter.inner",
            ["al"] = "@loop.outer",       -- 选中循环
            ["il"] = "@loop.inner",
            ["ai"] = "@conditional.outer", -- 选中条件语句
            ["ii"] = "@conditional.inner",
        },
    },
    move = {
        enable = true,
        set_jumps = true,
        goto_next_start = {
            ["]f"] = "@function.outer",
            ["]c"] = "@class.outer",
        },
        goto_previous_start = {
            ["[f"] = "@function.outer",
            ["[c"] = "@class.outer",
        },
    },
    swap = {
        enable = true,
        swap_next = {
            ["<leader>a"] = "@parameter.inner",
        },
        swap_previous = {
            ["<leader>A"] = "@parameter.inner",
        },
    },
},

使用示例:

daf         " 删除整个函数
cif         " 修改函数体
vac         " 选中整个类
yia         " 复制参数
]f          " 跳到下一个函数
[c          " 跳到上一个类
<leader>a   " 交换参数位置

2. Telescope: 模糊搜索中心

在现代架构中, 我们不再手动翻找目录, 而是使用 Telescope 进行模糊匹配.

2.1 安装配置

-- 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" },
        },
        cmd = "Telescope",
        keys = {
            { "<leader>ff", "<cmd>Telescope find_files<CR>", desc = "Find files" },
            { "<leader>fg", "<cmd>Telescope live_grep<CR>", desc = "Live grep" },
            { "<leader>fb", "<cmd>Telescope buffers<CR>", desc = "Buffers" },
            { "<leader>fh", "<cmd>Telescope help_tags<CR>", desc = "Help tags" },
            { "<leader>fr", "<cmd>Telescope oldfiles<CR>", desc = "Recent files" },
            { "<leader>fc", "<cmd>Telescope commands<CR>", desc = "Commands" },
            { "<leader>fk", "<cmd>Telescope keymaps<CR>", desc = "Keymaps" },
            { "<leader>fs", "<cmd>Telescope lsp_document_symbols<CR>", desc = "LSP symbols" },
            { "<leader>fd", "<cmd>Telescope diagnostics<CR>", desc = "Diagnostics" },
            { "<leader>fw", "<cmd>Telescope grep_string<CR>", desc = "Grep word" },
            { "<leader>gc", "<cmd>Telescope git_commits<CR>", desc = "Git commits" },
            { "<leader>gb", "<cmd>Telescope git_branches<CR>", desc = "Git branches" },
            { "<leader>gs", "<cmd>Telescope git_status<CR>", desc = "Git status" },
        },
        config = function()
            local telescope = require("telescope")
            local actions = require("telescope.actions")

            telescope.setup({
                defaults = {
                    mappings = {
                        i = {
                            ["<C-j>"] = actions.move_selection_next,
                            ["<C-k>"] = actions.move_selection_previous,
                            ["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
                            ["<Esc>"] = actions.close,
                        },
                    },
                    file_ignore_patterns = {
                        "node_modules", ".git/", "vendor/", "*.lock",
                    },
                    layout_config = {
                        horizontal = { preview_width = 0.5 },
                    },
                },
                pickers = {
                    find_files = {
                        hidden = true,
                    },
                    live_grep = {
                        additional_args = function()
                            return { "--hidden" }
                        end,
                    },
                },
            })

            telescope.load_extension("fzf")
        end,
    },
}

2.2 核心 Picker

Picker功能快捷键
find_files查找文件<leader>ff
live_grep全局搜索<leader>fg
buffers缓冲区列表<leader>fb
oldfiles最近文件<leader>fr
lsp_document_symbols符号导航<leader>fs
diagnostics诊断列表<leader>fd
git_commitsGit 提交<leader>gc
git_branchesGit 分支<leader>gb

2.3 Telescope 内快捷键

按键功能
<C-j> / <C-k>上下移动
<CR>打开文件
<C-x>水平分割打开
<C-v>垂直分割打开
<C-t>新标签页打开
<C-q>发送到 Quickfix
<C-u> / <C-d>预览滚动

2.4 搜索技巧

" 搜索时可以使用空格分隔多个词 (AND 逻辑)
" 例如输入: user service
" 会找到同时包含 user 和 service 的文件

" 使用 ! 排除
" 例如输入: user !test
" 会找到包含 user 但不包含 test 的项

" 使用 ^ 匹配开头
" 例如输入: ^main
" 会找到以 main 开头的项

3. Harpoon: 快速标记导航

对于常用文件, Harpoon 比 Telescope 更快.

3.1 配置

return {
    "ThePrimeagen/harpoon",
    branch = "harpoon2",
    dependencies = { "nvim-lua/plenary.nvim" },
    keys = {
        { "<leader>ha", function() require("harpoon"):list():append() end, desc = "Harpoon add" },
        { "<leader>hh", function() require("harpoon").ui:toggle_quick_menu(require("harpoon"):list()) end, desc = "Harpoon menu" },
        { "<leader>1", function() require("harpoon"):list():select(1) end, desc = "Harpoon 1" },
        { "<leader>2", function() require("harpoon"):list():select(2) end, desc = "Harpoon 2" },
        { "<leader>3", function() require("harpoon"):list():select(3) end, desc = "Harpoon 3" },
        { "<leader>4", function() require("harpoon"):list():select(4) end, desc = "Harpoon 4" },
    },
}

3.2 使用方式

<leader>ha      " 将当前文件加入列表
<leader>hh      " 打开 Harpoon 菜单
<leader>1-4     " 直接跳转到第 1-4 个文件

4. 本周实战任务

4.1 Treesitter 练习

  1. 安装 Treesitter 并运行 :TSUpdate
  2. 观察代码高亮的变化
  3. 练习 <C-space> 增量选择
  4. 使用 daf, cif, vac 等文本对象

4.2 Telescope 练习

  1. 配置 Telescope 快捷键
  2. 使用 <leader>ff 查找文件
  3. 使用 <leader>fg 全局搜索
  4. 使用 <leader>fs 导航符号

4.3 Harpoon 练习

  1. 将 4 个常用文件加入 Harpoon
  2. 使用 <leader>1-4 快速切换
  3. 感受与 Telescope/Buffer 切换的不同

5. 思考题

  1. Treesitter 相比正则高亮有什么优势?
  2. 什么场景用 Telescope, 什么场景用 Harpoon?
  3. 增量选择如何提高效率?
  4. 如何将搜索结果发送到 Quickfix?
  5. Treesitter 文本对象和内置文本对象有何区别?

结构化导航是现代开发的基础. Treesitter 提供语义理解, Telescope 提供快速检索, Harpoon 提供热点跳转.

On this page