11

Is it possible to define a text object in vim that will act on a rectangular region?

For instance, suppose I have vertically aligned columns of text, like this:

column 1 co    column 2 col
lumn 1 colu    umn 2 column
mn 1 column    2 column 2 c
1 column 1     olumn 2 colu

Would it be possible to define a textobject c for columns, such that dac would delete a column, yac would yank it, cac would change it, and so on?

(I know about Control-V for selecting a rectangular region, and I know you can then use d, y, etc to delete, yank etc the selected region. But I'm specifically curious about what's possible using text objects.)

  • 6
    Is it possible? Absolutely! Case and point: textobj-word-column.vim – Peter Rincker Jun 30 '15 at 19:46
  • @PeterRincker This is nice, but I wonder if it couldn't be simplified to take advantage of Kana's textobj-user. – lcd047 Jun 30 '15 at 23:01
  • Thanks, Peter, that's exactly the sort of example I was looking for. – Leah Velleman Jul 1 '15 at 3:00
  • 2
    @PeterRincker make this an answer :) – Vitor Jul 1 '15 at 11:02
5

Yes, this is possible. @PeterRincker suggests the plugin textobj-word-column, which defines four text objects (ic, ac, iC, and aC) for word-based columns.

The idea behind this functionality is to create a function that defines a column based motion, and then to map this function appropriately to visual/select mode mappings and operator pending mappings. To use the above mentioned plugin as an example, it creates the following mappings:

xnoremap <silent> ac :<C-u>call TextObjWordBasedColumn("aw")<cr>
xnoremap <silent> aC :<C-u>call TextObjWordBasedColumn("aW")<cr>
xnoremap <silent> ic :<C-u>call TextObjWordBasedColumn("iw")<cr>
xnoremap <silent> iC :<C-u>call TextObjWordBasedColumn("iW")<cr>
onoremap <silent> ac :call TextObjWordBasedColumn("aw")<cr>
onoremap <silent> aC :call TextObjWordBasedColumn("aW")<cr>
onoremap <silent> ic :call TextObjWordBasedColumn("iw")<cr>
onoremap <silent> iC :call TextObjWordBasedColumn("iW")<cr>

Here TextObjWordBasedColumn(...) defines the column motion and is mapped to both visual/select mode with xnoremap and operator pending mode with onoremap. Note that the function is slightly complex in order to handle indendation and to find the appropriate motion boundaries.

4

Is it possible? Absolutely! Case and point: textobj-word-column.vim.

How to make your own text objects

Typically visual mode is used to create a new text object. The visual mode can be line-wise, character-wise (typically), or visual-block. Here is the basics of what you will need:

  • An unused key combination typically a{char} or i{char} where {char} is both descriptive and unused. e.g. i/ as an example text object between /'s.
  • Need a way to find the start of your text-object. e.g. T/
  • Need a way to find the end of your text-object. e.g. t/
  • Choose a visual mode. e.g. v
  • Create a visual mode (only) mapping via xnoremap.
  • Create a operator pending mode mapping that uses the visual mode mapping via onoremap and :normal.

Now for an example of our simple i/ which creates a text-object between /'s:

xnoremap i/ :<c-u>normal! T/vt/<cr>
onoremap i/ :normal vi/<cr>

As long as you follow the basic ingredients you can create text-objects for all sorts of things.

Advanced text-object creation with vim-textobj-user

The vim-textobj-user plugin provides a common way to define custom text-objects in a more declarative fashion. For example here is a php tag text-object:

call textobj#user#plugin('php', {
\   'code': {
\     'pattern': ['<?php\>', '?>'],
\     'select-a': 'aP',
\     'select-i': 'iP',
\   },
\ })

For more help with vim-textobj-user see its help doc: :h textobj-user-introduction.

For more help

:h map-overview
:h visual-start
:h :norm

As well as the Creating new text objects Vim wiki page.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.