3

I am trying to create a text object for consecutive lower-case letters.

Here is how I am setting up the inner text object:

xnoremap in :<C-u>normal! ?[^a-z]?e+1<CR>v/[^a-z]/s-1<CR>
onoremap in :normal vin<CR>

The following shows what happens when I type vin:

[text]               some important text
[cursor]                       |
[expected selection]      ^^^^^^^^^
[actual selection]             ^^^^

I then tried the following with the same text and cursor position:

v:<C-u>normal! ?i

The cursor didn't move. I expected it to.

Searching forward doesn't work either:

v:<C-u>normal! /t

However all these work:

v:<C-u>normal! b
v:<C-u>normal! e
v:<C-u>normal! Fi
v:<C-u>normal! ft

How can I solve this?

2

This is because the <CR> in your mapping signals to the norm command to finish, not for the the ? command to finish. So when you get to the first <CR>, the command that vim runs is

normal! ?[^a-z]?e+1

And this command does not do anything. Because you don't hit enter by the time the normal command is over, nothing actually happens. So here we have a dilemma. We need to tell vim to press enter inside of the normal command, but we can't press enter (because that finishes the normal command). Here is where we use <C-v> to enter a literal carriage return.

So you need to put a <C-v> before every <CR> that is not the final <CR> in your command. This makes the following mapping:

xnoremap in :<C-u>normal! ?[^a-z]?e+1<C-v><CR>v/[^a-z]/s-1<C-v><CR><CR>
onoremap in :normal vin<CR>

Some unrelated side notes about your approach:

  1. This approach only works if you're in the middle of your object. If you're at the beginning of it, things break.

  2. Using \L is equivalent to [^a-z], and is faster and more readable.

  • 1
    Thanks for both the clear explanation and the side notes. All much appreciated! – Andy Stewart May 25 '17 at 19:10
  • My pleasure! Glad to help. :) – DJMcMayhem May 25 '17 at 19:11
  • Preceding the initial backward search (?) with l to move right one character seems to solve note 1. – Andy Stewart May 25 '17 at 19:21
  • @AndyStewart Yes, but that causes a new problem: It doesn't work if you're at the end of your object. – DJMcMayhem May 25 '17 at 19:22
  • Why not? If you're on the last lower case letter, moving 1 character right then searching backwards will start the search on the last lower case letter. – Andy Stewart May 25 '17 at 20:08

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.