Skip to main content

Treesitter Setup

Treesitter is a parser generator that understands your code's actual syntax tree (not just regex patterns). This enables accurate syntax highlighting, smart code folding, and language-aware selection.

Core Idea

Traditional syntax highlighting = regex patterns on text. Treesitter = proper parse tree. The result is accurate highlighting even in complex or multi-language files (like PHP with inline HTML).

Plugin Setup

lua/plugins/treesitter.lua
return {
{
"nvim-treesitter/nvim-treesitter",
version = false,
build = ":TSUpdate",
event = { "BufReadPost", "BufNewFile" },
dependencies = {
"nvim-treesitter/nvim-treesitter-textobjects", -- treesitter-based text objects
},
config = function()
require("nvim-treesitter.configs").setup({
-- Install parsers for these languages
ensure_installed = {
"lua", "python", "javascript", "typescript",
"php", "bash", "json", "yaml", "toml",
"html", "css", "markdown", "markdown_inline",
"regex", "vim", "vimdoc", "query",
"go", "rust", "c", "cpp",
"sql", "dockerfile", "terraform",
},

-- Install parsers synchronously (only first time)
sync_install = false,

-- Auto-install missing parsers
auto_install = true,

-- Highlighting
highlight = {
enable = true,
-- Disable for large files (performance)
disable = function(lang, buf)
local max_filesize = 100 * 1024 -- 100 KB
local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf))
if ok and stats and stats.size > max_filesize then
return true
end
end,
additional_vim_regex_highlighting = false,
},

-- Incremental selection
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-space>",
node_incremental = "<C-space>",
scope_incremental = false,
node_decremental = "<bs>",
},
},

-- Indentation based on treesitter
indent = {
enable = true,
},

-- Treesitter text objects
textobjects = {
select = {
enable = true,
lookahead = true, -- jump ahead to next text object
keymaps = {
["af"] = "@function.outer",
["if"] = "@function.inner",
["ac"] = "@class.outer",
["ic"] = "@class.inner",
["al"] = "@loop.outer",
["il"] = "@loop.inner",
["aa"] = "@parameter.outer",
["ia"] = "@parameter.inner",
["ai"] = "@conditional.outer",
["ii"] = "@conditional.inner",
},
},
move = {
enable = 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" },
},
},
})
end,
},
}

Treesitter Text Objects

With nvim-treesitter-textobjects, you get semantic text objects:

KeyText Object
af / ifAround/inner function
ac / icAround/inner class
al / ilAround/inner loop
aa / iaAround/inner function argument
ai / iiAround/inner conditional (if)

Usage:

dif    → delete function body (inner)
vaf → visually select entire function
yic → yank class body
cil → change loop body
]f      → next function start
[f → previous function start
]c → next class
[c → previous class

Managing Parsers

:TSInstall python       → install Python parser
:TSUninstall python → remove parser
:TSUpdate → update all parsers
:TSInstallInfo → show all available parsers
:TSConfigInfo → show current config
:InspectTree → open parse tree view for current file

Incremental Selection

With incremental_selection configured:

<C-Space>    → start selection at current node
<C-Space> → expand to parent node
<Backspace> → shrink selection back

This selects semantically meaningful regions: word → expression → statement → block → function → file.

Code Folding with Treesitter

lua/config/options.lua
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
vim.opt.foldenable = false -- don't fold on open
vim.opt.foldlevel = 99 -- open all folds by default

Fold commands:

zc    → close fold
zo → open fold
za → toggle fold
zR → open all folds
zM → close all folds

What's Next