强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

14 - Tree-sitter

“Tree-sitter doesn’t just color your code — it understands it.”

14.1 什么是 Tree-sitter

14.1.1 增量解析器

Tree-sitter 是一个通用的增量解析框架,它将源代码解析为具体的语法树(AST)。与正则表达式匹配不同,Tree-sitter 真正理解代码结构。

正则匹配(传统高亮):
  if (x > 0) → 关键字 + 括号 + 变量 + 运算符 + 数字
  不理解嵌套、范围、作用域

Tree-sitter:
  if (x > 0) → if_statement
                 ├── condition: comparison_expression
                 │    ├── left: identifier "x"
                 │    ├── operator: ">"
                 │    └── right: number "0"
                 └── consequence: ...
  完整的语法树结构

14.1.2 优势

特性传统正则Tree-sitter
速度极快(增量)
准确性有误报语法精确
嵌套不支持完整支持
跨行困难原生支持
自定义对象不可能可定义
增量更新全量只更新变更部分

14.2 安装与配置

14.2.1 nvim-treesitter

-- ~/.config/nvim/lua/plugins/treesitter.lua
return {
    { "nvim-treesitter/nvim-treesitter",
        build = ":TSUpdate",
        event = { "BufReadPost", "BufNewFile" },
        opts = {
            ensure_installed = {
                "lua", "vim", "vimdoc", "query",
                "python", "javascript", "typescript", "tsx",
                "go", "rust", "c", "cpp", "java",
                "html", "css", "scss",
                "json", "yaml", "toml", "xml",
                "markdown", "markdown_inline",
                "bash", "fish", "dockerfile",
                "regex", "sql", "graphql",
            },
            highlight = {
                enable = true,
                additional_vim_regex_highlighting = false,
            },
            indent = {
                enable = true,
            },
            incremental_selection = {
                enable = true,
                keymaps = {
                    init_selection = "<C-space>",
                    node_incremental = "<C-space>",
                    scope_incremental = false,
                    node_decremental = "<BS>",
                },
            },
        },
        config = function(_, opts)
            require("nvim-treesitter.configs").setup(opts)
        end,
    },
}

14.2.2 Tree-sitter 命令

:TSInstall python       " 安装 Python 解析器
:TSUpdate               " 更新所有解析器
:TSUpdate python        " 更新 Python 解析器
:TSInstallInfo          " 查看解析器信息
:TSModuleInfo           " 查看模块启用状态
:TSHighlightCapturesUnderCursor  " 查看光标下高亮组

14.3 语法高亮

14.3.1 高亮组

Tree-sitter 定义了一套语义化的高亮组:

高亮组含义示例
@variable变量x, count
@variable.builtin内置变量self, this
@function函数定义def foo()
@function.call函数调用foo()
@function.builtin内置函数print()
@method方法obj.method()
@keyword关键字if, for, return
@string字符串"hello"
@number数字42, 3.14
@comment注释# comment
@type类型int, str
@operator运算符+, ==
@punctuation标点(, {, [
@tagHTML 标签<div>
@attribute属性@property
@namespace命名空间module.name

14.3.2 自定义高亮

vim.api.nvim_set_hl(0, "@variable", { fg = "#f8f8f2" })
vim.api.nvim_set_hl(0, "@function", { fg = "#50fa7b", bold = true })
vim.api.nvim_set_hl(0, "@keyword", { fg = "#ff79c6", italic = true })

14.4 文本对象

14.4.1 nvim-treesitter-textobjects

{ "nvim-treesitter/nvim-treesitter-textobjects",
    dependencies = { "nvim-treesitter/nvim-treesitter" },
    event = "VeryLazy",
    config = function()
        require("nvim-treesitter.configs").setup({
            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",
                        ["ab"] = "@block.outer",
                        ["ib"] = "@block.inner",
                    },
                },
                move = {
                    enable = true,
                    set_jumps = true,
                    goto_next_start = {
                        ["]f"] = "@function.outer",
                        ["]c"] = "@class.outer",
                        ["]a"] = "@parameter.inner",
                    },
                    goto_next_end = {
                        ["]F"] = "@function.outer",
                        ["]C"] = "@class.outer",
                    },
                    goto_previous_start = {
                        ["[f"] = "@function.outer",
                        ["[c"] = "@class.outer",
                        ["[a"] = "@parameter.inner",
                    },
                    goto_previous_end = {
                        ["[F"] = "@function.outer",
                        ["[C"] = "@class.outer",
                    },
                },
                swap = {
                    enable = true,
                    swap_next = {
                        ["<leader>sa"] = "@parameter.inner",
                    },
                    swap_previous = {
                        ["<leader>sA"] = "@parameter.inner",
                    },
                },
            },
        })
    end,
}

14.4.2 文本对象用法

def hello(name, age):    # 光标在函数内
    print(f"Hello {name}, age {age}")
    return True

# vaf → 选择整个函数(含 def 行)
# vif → 选择函数体(不含 def 行)
# vac → 选择整个类
# via → 选择当前参数
# ]f  → 跳到下一个函数
# [f  → 跳到上一个函数

14.5 增量选择

incremental_selection = {
    enable = true,
    keymaps = {
        init_selection = "<C-space>",    -- 开始选择
        node_incremental = "<C-space>",  -- 扩展选择
        scope_incremental = false,       -- 扩展到作用域
        node_decremental = "<BS>",       -- 缩小选择
    },
},

使用流程:

# 光标在 variable 上
result = calculate(a + b, c)

# <C-space>   → 选中 variable (result)
# <C-space>   → 选中 assignment (整个语句)
# <C-space>   → 选中 expression (calculate(...))
# <BS>        → 缩回到 assignment

14.6 缩进

indent = {
    enable = true,
    disable = { "python", "yaml" },  -- 某些语言禁用(可能不准确)
},

14.7 Playground

{ "nvim-treesitter/playground",
    cmd = "TSPlaygroundToggle",
    dependencies = { "nvim-treesitter/nvim-treesitter" },
}
:TSPlaygroundToggle    " 打开语法树可视化
:TSHighlightCapturesUnderCursor  " 查看高亮组

14.8 业务场景

场景Tree-sitter 功能
精确语法高亮替代正则高亮
结构化文本对象vif, vac, via
函数导航]f, [f
参数交换<leader>sa
增量选择<C-space>
语法树调试Playground

14.9 总结

组件用途
nvim-treesitter语法高亮 + 增量解析
nvim-treesitter-textobjects文本对象 + 移动
playground语法树可视化

下一步第 15 章 - Telescope 模糊搜索 → 用 Telescope 构建强大的搜索工作流。


扩展阅读