How do I incrementally expand or shrink a selection based on syntax tree nodes using nvim-treesitter?
Answer
gnn / grn / grm
Explanation
nvim-treesitter's incremental selection module lets you grow and shrink your visual selection one syntax node at a time. Instead of manually counting brackets or using motion combinations, you initiate a selection at the current node and then tap a single key to expand to the enclosing node — function argument → argument list → function call → expression — until you have exactly what you need. This is far more precise than v + motion combinations for structured code.
How it works
Enable the module in your treesitter config:
require('nvim-treesitter.configs').setup({
incremental_selection = {
enable = true,
keymaps = {
init_selection = 'gnn', -- start selection at current node
node_incremental = 'grn', -- expand to parent node
scope_incremental = 'grc', -- expand to enclosing scope
node_decremental = 'grm', -- shrink back to child node
},
},
})
Keys:
gnn— initiate selection at the syntax node under the cursor (enters Visual mode)grn— expand the selection to the next larger syntax nodegrc— expand to the nearest enclosing scope (function body, block, etc.)grm— shrink the selection back to the previous, smaller node
Example
With the cursor on name in print(greet(name)), pressing gnn selects the identifier. Pressing grn expands to greet(name) (the function call). Pressing grn again selects print(greet(name)). Now you can yank, delete, or change the entire expression.
Tips
- After initiating with
gnn, you are in Visual mode — all normal visual operators (d,y,c,>) work on the current selection grmundoes expansions one step at a time, so you can overshoot and come back- This works on any language with a treesitter grammar installed (
:TSInstall python,:TSInstall go, etc.) - Combine with
nvim-treesitter-textobjectsfor even more precise node selections like@function.outerand@class.inner