vimtricks.wiki Concise Vim tricks, one at a time.

How do I create custom text objects for my own operator-pending motions?

Answer

onoremap ih :<C-u>execute "normal! ?^==\+$\r:noh\rkvg_"<CR>

Explanation

Vim lets you define custom text objects using operator-pending mode mappings (onoremap) and visual mode mappings (vnoremap). These mappings work with any operator like d, c, y, or gq.

How it works

An operator-pending mapping defines what text an operator should act on. When you type d followed by your custom motion, Vim uses your mapping to select the target text.

Example: "inside heading" text object

" Select the content under a Markdown heading
onoremap ih :<C-u>execute "normal! ?^#\\+\\s\r:noh\rjV/^#\\+\\s\\\|\\%$\r:noh\rk"<CR>
vnoremap ih :<C-u>execute "normal! ?^#\\+\\s\r:noh\rjV/^#\\+\\s\\\|\\%$\r:noh\rk"<CR>

Simpler examples

" 'in line' — select from first to last non-blank character
onoremap il :<C-u>normal! ^vg_<CR>
vnoremap il :<C-u>normal! ^vg_<CR>

" 'around line' — select entire line content
onoremap al :<C-u>normal! 0v$<CR>
vnoremap al :<C-u>normal! 0v$<CR>

" 'in number' — select a number under cursor
onoremap in :<C-u>execute "normal! /\\d\+\r:noh\rvgn"<CR>

" 'entire buffer' text object
onoremap ae :<C-u>normal! ggVG<CR>
vnoremap ae :<C-u>normal! ggVG<CR>

Usage after defining

dil    " Delete 'in line'
yae    " Yank entire buffer
cal    " Change around line
=ae    " Reindent entire buffer

Tips

  • onoremap defines the text object for operator-pending mode
  • vnoremap defines it for visual mode (so vil works too)
  • The <C-u> clears any count from the command line
  • For complex text objects, consider the vim-textobj-user plugin which provides a framework
  • Custom text objects compose naturally with all operators — that's the power of Vim's grammar

Next

How do I always access my last yanked text regardless of deletes?