# nvim-treesitter-textobjects **Repository Path**: rootquan/nvim-treesitter-textobjects ## Basic Information - **Project Name**: nvim-treesitter-textobjects - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-10 - **Last Updated**: 2026-06-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # nvim-treesitter-textobjects Syntax aware text-objects, select, move, swap, and peek support. **Warning: tree-sitter and nvim-treesitter are an experimental feature of nightly versions of Neovim. Please consider the experience with this plug-in as experimental until tree-sitter support in Neovim is stable! We recommend using the nightly builds of Neovim or the latest stable version.** ## Installation You can install nvim-treesitter-textobjects with your favorite package manager, or using the default pack feature of Neovim! ### Using a package manager If you are using [lazy.nvim](https://github.com/folke/lazy.nvim), add this to your `init.lua` or `plugins.lua`. ```lua { "nvim-treesitter/nvim-treesitter-textobjects", branch = "main", init = function() -- Disable entire built-in ftplugin mappings to avoid conflicts. -- See https://github.com/neovim/neovim/tree/master/runtime/ftplugin for built-in ftplugins. vim.g.no_plugin_maps = true -- Or, disable per filetype (add as you like) -- vim.g.no_python_maps = true -- vim.g.no_ruby_maps = true -- vim.g.no_rust_maps = true -- vim.g.no_go_maps = true end, config = function() -- put your config here end, } ``` ## Text objects: select Define your own text objects mappings similar to `ip` (inner paragraph) and `ap` (a paragraph). ```lua -- configuration require("nvim-treesitter-textobjects").setup { select = { -- Automatically jump forward to textobj, similar to targets.vim lookahead = true, -- You can choose the select mode (default is charwise 'v') -- -- Can also be a function which gets passed a table with the keys -- * query_string: eg '@function.inner' -- * method: eg 'v' or 'o' -- and should return the mode ('v', 'V', or '') or a table -- mapping query_strings to modes. selection_modes = { ['@parameter.outer'] = 'v', -- charwise ['@function.outer'] = 'V', -- linewise -- ['@class.outer'] = '', -- blockwise }, -- If you set this to `true` (default is `false`) then any textobject is -- extended to include preceding or succeeding whitespace. Succeeding -- whitespace has priority in order to act similarly to eg the built-in -- `ap`. -- -- Can also be a function which gets passed a table with the keys -- * query_string: eg '@function.inner' -- * selection_mode: eg 'v' -- and should return true of false include_surrounding_whitespace = false, }, } -- keymaps -- You can use the capture groups defined in `textobjects.scm` vim.keymap.set({ "x", "o" }, "am", function() require "nvim-treesitter-textobjects.select".select_textobject("@function.outer", "textobjects") end) vim.keymap.set({ "x", "o" }, "im", function() require "nvim-treesitter-textobjects.select".select_textobject("@function.inner", "textobjects") end) vim.keymap.set({ "x", "o" }, "ac", function() require "nvim-treesitter-textobjects.select".select_textobject("@class.outer", "textobjects") end) vim.keymap.set({ "x", "o" }, "ic", function() require "nvim-treesitter-textobjects.select".select_textobject("@class.inner", "textobjects") end) -- You can also use captures from other query groups like `locals.scm` vim.keymap.set({ "x", "o" }, "as", function() require "nvim-treesitter-textobjects.select".select_textobject("@local.scope", "locals") end) ``` ## Text objects: swap Define your own mappings to swap the node under the cursor with the next or previous one, like function parameters or arguments. ```lua -- keymaps vim.keymap.set("n", "a", function() require("nvim-treesitter-textobjects.swap").swap_next "@parameter.inner" end) vim.keymap.set("n", "A", function() require("nvim-treesitter-textobjects.swap").swap_previous "@parameter.outer" end) ``` ## Text objects: move Define your own mappings to jump to the next or previous text object. This is similar to `]m`, `[m`, `]M`, `[M` Neovim's mappings to jump to the next or previous function. ```lua -- configuration require("nvim-treesitter-textobjects").setup { move = { -- whether to set jumps in the jumplist set_jumps = true, }, } -- keymaps -- You can use the capture groups defined in `textobjects.scm` vim.keymap.set({ "n", "x", "o" }, "]m", function() require("nvim-treesitter-textobjects.move").goto_next_start("@function.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "]]", function() require("nvim-treesitter-textobjects.move").goto_next_start("@class.outer", "textobjects") end) -- You can also pass a list to group multiple queries. vim.keymap.set({ "n", "x", "o" }, "]o", function() require("nvim-treesitter-textobjects.move").goto_next_start({"@loop.inner", "@loop.outer"}, "textobjects") end) -- You can also use captures from other query groups like `locals.scm` or `folds.scm` vim.keymap.set({ "n", "x", "o" }, "]s", function() require("nvim-treesitter-textobjects.move").goto_next_start("@local.scope", "locals") end) vim.keymap.set({ "n", "x", "o" }, "]z", function() require("nvim-treesitter-textobjects.move").goto_next_start("@fold", "folds") end) vim.keymap.set({ "n", "x", "o" }, "]M", function() require("nvim-treesitter-textobjects.move").goto_next_end("@function.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "][", function() require("nvim-treesitter-textobjects.move").goto_next_end("@class.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "[m", function() require("nvim-treesitter-textobjects.move").goto_previous_start("@function.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "[[", function() require("nvim-treesitter-textobjects.move").goto_previous_start("@class.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "[M", function() require("nvim-treesitter-textobjects.move").goto_previous_end("@function.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "[]", function() require("nvim-treesitter-textobjects.move").goto_previous_end("@class.outer", "textobjects") end) -- Go to either the start or the end, whichever is closer. -- Use if you want more granular movements vim.keymap.set({ "n", "x", "o" }, "]d", function() require("nvim-treesitter-textobjects.move").goto_next("@conditional.outer", "textobjects") end) vim.keymap.set({ "n", "x", "o" }, "[d", function() require("nvim-treesitter-textobjects.move").goto_previous("@conditional.outer", "textobjects") end) ``` You can make the movements repeatable like `;` and `,`. ```lua local ts_repeat_move = require "nvim-treesitter-textobjects.repeatable_move" -- Repeat movement with ; and , -- ensure ; goes forward and , goes backward regardless of the last direction vim.keymap.set({ "n", "x", "o" }, ";", ts_repeat_move.repeat_last_move_next) vim.keymap.set({ "n", "x", "o" }, ",", ts_repeat_move.repeat_last_move_previous) -- vim way: ; goes to the direction you were moving. -- vim.keymap.set({ "n", "x", "o" }, ";", ts_repeat_move.repeat_last_move) -- vim.keymap.set({ "n", "x", "o" }, ",", ts_repeat_move.repeat_last_move_opposite) -- Optionally, make builtin f, F, t, T also repeatable with ; and , vim.keymap.set({ "n", "x", "o" }, "f", ts_repeat_move.builtin_f_expr, { expr = true }) vim.keymap.set({ "n", "x", "o" }, "F", ts_repeat_move.builtin_F_expr, { expr = true }) vim.keymap.set({ "n", "x", "o" }, "t", ts_repeat_move.builtin_t_expr, { expr = true }) vim.keymap.set({ "n", "x", "o" }, "T", ts_repeat_move.builtin_T_expr, { expr = true }) ``` You can even make a custom repeat behaviour. ```lua -- This repeats the last query with always previous direction and to the start of the range. vim.keymap.set({ "n", "x", "o" }, "", function() ts_repeat_move.repeat_last_move({forward = false, start = true}) end) -- This repeats the last query with always next direction and to the end of the range. vim.keymap.set({ "n", "x", "o" }, "", function() ts_repeat_move.repeat_last_move({forward = true, start = false}) end) ``` # Overriding or extending textobjects Textobjects are defined in the `textobjects.scm` files. You can extend or override those files by following the instructions at . You can also use a custom capture for your own textobjects, and use it in any of the textobject modules, for example: ```query ; queries/python/textobjects.scm ;; extends (function_definition) @custom_capture ``` ```lua for _, mode in ipairs { "x", "o" } do vim.keymap.set(mode, "aF", function() select.select_textobject("@custom_capture", "textobjects", mode) end) end ``` Here are some rules about the query names that should be noted. 1. Avoid using special characters in the query name, because in `move` module the names are read as lua patterns. - `@custom-capture.inner` (X) - `@custom_capture.inner` (O) 2. In `select` module, it will be preferred to select within the `@*.outer` matches. For example, - `@assignment.inner`, `@assignment.lhs`, and even `@assignment` will be selected within the `@assignment.outer` range if available. This means it will sometimes look behind. - You can write something like `@function.name` or `@call.name` and make sure `@function.outer` and `@call.outer` covers the range. ## Built-in Textobjects See [BUILTIN_TEXTOBJECTS.md](BUILTIN_TEXTOBJECTS.md) for the list of built-in textobjects and supported languages.