Text objects are one of the power of Vim that I particulary like.

I wanted to create my personnal text object with the p (="previous") and n (="next") parameters. For instance if I type din) (="delete in next closing parenthesis") vim will look for the next parenthesis (even if it's in another line below) and delete it's content.

It is simple when I want to reach the previous/next parenthesis wich is in the same line as my cursor:

"Point the previous parenthesis
onoremap ip) :<C-U>normal! F(vi(<CR>
"Point the next parenthesis
onoremap in) :<C-U>normal! f(vi(<CR>

But the problems come when I want to modifie those mapping to extend the search outside of the line.

I finally found an alternative with this structure (onoremap [keys] :[search] | [selection]<CR>):

"Point the previous parenthesis
onoremap ip) :<C-U>call search('(','b')<Space><Bar><Space>normal! lvi)<CR>
"Point the next parenthesis
onoremap in) :<C-U>call search('(')<Space><Bar><Space>normal! lvi)<CR>

But I have to use the "search()" function because the "/" command doesn't seem to work.
I also need to use "<Space><Bar><Space>" to combine two commands (work as "|").
I see that using "<C-U>" right after ":" can avoid some border effect here .

My question:
Is there a user-friendly way (a shorter and more readable answer) to do the same kind of mapping?

Personnally, text object is one of my favorite vim feature and I think it's a bit sad to struggle doing a mapping "on the fly" (but now I know that way, I can reproduce that without any problem).

  • 2
    Does ` \| ` (escaped bar char with a space on each side) work in place of <space><bar><space>? Other than that there's not too much you can do to simplify the thing. Except move the bulk of it into a function...then the mapping is nice and short and clean.
    – B Layer
    Feb 2, 2021 at 2:11
  • 1
    I mean, you could try ?(<cr>vib
    – D. Ben Knoble
    Feb 2, 2021 at 3:03
  • 2
    Plug-in wellle/targets.vim implements in) and ip), also works with counts and takes care of many of the odd corner cases... Is your question about how to get these particular mappings? If so, then I'd recommend just getting the plug-in.
    – filbranden
    Feb 2, 2021 at 3:46
  • If it's more about writing your mappings... Then what exactly do you mean by "user-friendly"? It's unclear what parts of it are not that user-friendly that you would like to address... Note that you don't need <Space>, but you do need to escape the bar with either <Bar> or \|. A way to avoid these would be define a function that performs the commands to implement the motion and selection, then have the mapping just call the function. In the function you don't need |, just use separate commands on separate lines.
    – filbranden
    Feb 2, 2021 at 3:49
  • 1
    @filbranden this is good, I didn't know about that plugin. Normally, I try to do things without any plugin but I will certainly try it when I find the time. Feb 2, 2021 at 11:48

1 Answer 1


Thanks to the comments and the documentation, I found some solutions.

Using "\|"

No need to use <Space><Bar><Space>, the bar is recognized when a \ is put before:

"Point the previous parenthesis
onoremap ip) :<C-U>call search('(','b') \| normal! lvi)<CR>
"Point the next parenthesis
onoremap in) :<C-U>call search('(') \| normal! lvi)<CR>

Using a range

Some commands in the command-line mode can accept a range. Fortunately, there are the /{pattern}[/] and ?{pattern}[?] range that look for the previous/next line that match a specified {pattern} (see :help :range):

"Point the previous parenthesis
onoremap ip) :<C-U>?(?normal! f(vi)<CR>
"Point the next parenthesis
onoremap in) :<C-U>/(/normal! f(vi)<CR>

Unfortunately, those mapping won't work for parenthesis in the same line as the cursor.

Perhaps I will find some other ways to do so but now it is better. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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