Skip to main content
Treesitter provides superior syntax highlighting and code understanding through parsing, enabling intelligent text objects and navigation.

Core plugins

The Treesitter setup includes three main plugins:

nvim-treesitter

Core parser and highlighting engine

textobjects

Code-aware text objects and motions

context

Sticky context header showing scope

Installation

Treesitter is loaded immediately (not lazy) and automatically updates parsers:
lua/plugins/treesitter.lua
{
  "nvim-treesitter/nvim-treesitter",
  branch = "main",
  lazy = false,
  build = ":TSUpdate",
  opts = {},
}
The :TSUpdate command runs automatically after installation to compile all parsers.

Language support

Parsers are automatically installed for these languages:
lua/plugins/treesitter.lua
ensure_installed = {
  "c",
  "lua",
  "vim",
  "vimdoc",
  "query",
  "markdown",
  "markdown_inline",
  "go",
  "gomod",
  "gosum",
  "jsdoc",
  "javascript",
  "typescript",
  "tsx",
  "angular",
  "html",
}

Auto-installation

lua/plugins/treesitter.lua
auto_install = true,
Parsers for other languages are installed automatically when you open a file of that type.

Syntax highlighting

Treesitter highlighting is enabled with performance optimizations:
lua/plugins/treesitter.lua
highlight = {
  enable = true,
  
  disable = function(lang, buf)
    -- Disable for large files (>100KB)
    if not buf or type(buf) ~= "number" then
      return false
    end
    local max_filesize = 100 * 1024 -- 100 KB
    local ok, stats = pcall(vim.uv.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,
}
Treesitter highlighting is automatically disabled for files larger than 100KB to maintain performance.

Text objects

Treesitter text objects allow you to operate on semantic code units like functions, classes, and arguments.

Selecting text objects

OperatorTargetDescription
afFunction (outer)Around function including signature
ifFunction (inner)Inside function body only
acClass (outer)Around class including declaration
icClass (inner)Inside class body
aaArgument (outer)Around parameter/argument
iaArgument (inner)Inside argument (value only)
aoLoop (outer)Around loop statement
ioLoop (inner)Inside loop body
aiConditional (outer)Around if/else/switch
iiConditional (inner)Inside conditional body
arReturn (outer)Around return statement
irReturn (inner)Return value only
asScopeAround local scope

Usage examples

  • vif - Select inside function body
  • vac - Select around class
  • vaa - Select around argument

Configuration

lua/plugins/treesitter.lua
require("nvim-treesitter-textobjects").setup({
  select = {
    lookahead = true,
    selection_modes = {
      ["@parameter.outer"] = "v", -- character-wise for parameters
      ["@function.outer"] = "V", -- line-wise for functions
    },
    include_surrounding_whitespace = false,
  },
})
Lookahead allows you to target the next text object even if your cursor isn’t directly on it.
Jump between semantic code elements:

Function navigation

KeyActionDescription
]fNext function startJump to start of next function
]FNext function endJump to end of next function
[fPrev function startJump to start of previous function
[FPrev function endJump to end of previous function

Class navigation

KeyActionDescription
]cNext class startJump to start of next class
]CNext class endJump to end of next class
[cPrev class startJump to start of previous class
[CPrev class endJump to end of previous class

Loop and conditional navigation

KeyActionDescription
]oNext loopJump to next loop
[oPrev loopJump to previous loop
]iNext conditionalJump to next if/else/switch
[iPrev conditionalJump to previous conditional

Swapping

Swap function arguments/parameters:
KeyActionDescription
<leader>aSwap nextSwap with next parameter
<leader>ASwap previousSwap with previous parameter
lua/plugins/treesitter.lua
map("n", "<leader>a", function()
  swap.swap_next("@parameter.inner")
end, { desc = "Swap next parameter" })

Example

function example(first, second, third) {
  // With cursor on 'second':
  // <leader>a swaps to: function example(first, third, second)
  // <leader>A swaps to: function example(second, first, third)
}

Treesitter context

Shows the current function/class/scope at the top of the window when scrolling:
lua/plugins/treesitter.lua
{
  "nvim-treesitter/nvim-treesitter-context",
  dependencies = { "nvim-treesitter/nvim-treesitter" },
  opts = {
    enable = true,
    max_lines = 4, -- Show up to 4 lines of context
    min_window_height = 15, -- Only show when window is tall enough
    line_numbers = true,
    multiline_threshold = 20, -- Show for scopes with 20+ lines
    trim_scope = "outer",
    mode = "topline",
    separator = "─",
    zindex = 20,
  },
}

Sticky header

Function/class signature stays visible while scrolling

Performance optimized

Disabled for files over 200KB

Visual separator

Clear horizontal line separates context from content

Smart activation

Only shows for scopes with 20+ lines

Context example

When scrolling inside a long function:
──────────────────────────────────────────────
  42 | function processUserData(data) {
──────────────────────────────────────────────
  68 |   // Current line visible here
  69 |   return result;

Indentation

Treesitter-based indentation:
lua/plugins/treesitter.lua
indent = {
  enable = true,
}
Provides better indentation for complex expressions and nested structures.

Incremental selection

Expand selection based on syntax tree:
KeyActionDescription
<leader>ssInit selectionStart incremental selection
<leader>siIncrement nodeExpand to parent node
<leader>scIncrement scopeExpand to scope
<leader>snDecrement nodeShrink to child node
lua/plugins/treesitter.lua
incremental_selection = {
  enable = true,
  keymaps = {
    init_selection = "<leader>ss",
    node_incremental = "<leader>si",
    scope_incremental = "<leader>sc",
    node_decremental = "<leader>sn",
  },
}

Example workflow

1

Start selection

Press <leader>ss with cursor on a variable name Selects: variable
2

Expand once

Press <leader>si Selects: variable.property
3

Expand again

Press <leader>si Selects: const x = variable.property
4

Expand to scope

Press <leader>sc Selects: entire function body

Treesitter modules

The configuration uses treesitter-modules.nvim for better module organization:
lua/plugins/treesitter.lua
{
  "MeanderingProgrammer/treesitter-modules.nvim",
  dependencies = { "nvim-treesitter/nvim-treesitter" },
  opts = { ... },
}
This provides the same configuration interface as the official plugin but with improved stability.

Commands

Install parser for specific language:
:TSInstall python
:TSInstall rust
Update all installed parsers:
:TSUpdate
Show status of all Treesitter modules:
:TSModuleInfo
Open Treesitter syntax tree inspector:
:InspectTree
Shows the parsed syntax tree for current buffer.

Toggle Treesitter

Disable/enable Treesitter highlighting:
<leader>uT
This toggle is provided by Snacks.nvim.

Performance tips

Large files

Automatically disabled for files over 100KB

Context

Context disabled for files over 200KB

Minimal highlighting

No additional vim regex highlighting

Selective context

Context only shows for scopes with 20+ lines
  • nvim-ts-autotag: Auto-close HTML/JSX tags (see Editing plugins)
  • nvim-ts-context-commentstring: Context-aware comments (see Editing plugins)
  • Blink.cmp: Uses Treesitter for smarter completions (see Completions)

Build docs developers (and LLMs) love