tags:

views:

151

answers:

3

Okay, suppose we have a line of text:

[s]tackoverflow rocks

where the brackets show the location of the cursor, in normal mode. After pressing tr, you get:

stackov[e]rflow rocks

Now for the fun part. What happens if you push ; to repeat the command? Nothing! Vim finds the next 'r' (immediately to the right of the cursor) and positions itself just left of that (where it already was).

I would prefer that ; advance the cursor to this position:

stackoverflow[ ]rocks

This can be achieved by using l to move right one character before pressing ;, but the extra step is irritating. There is a similar issue with T, but not with f and F. Is there some way to make ; behave the way I want with t and T?

+1  A: 

2 comments one: Can you map ; to the lt_ command you are looking for? 2nd: Why not use 2tr or /r followed by n instead?

James Deville
I'm not sure how to remap ; because I want it to different things depending on what t/T/f/Fx command was last issued. Also, I generally don't like ntx because I don't like counting characters to know what n to use. I find that just pushing a "repeat" key until I get where I'm going is less disruptive of my flow of though.This is really a pretty minor issue, and maybe I should just / instead :P.
Drew Frank
I agree that it's annoying - there are definitely plenty of reasons to use tTfF instead of /. I'm not sure why it behaves this way - my best guess is it's designed to feel right if you've moved around a lot since you issued the last tT command, so you don't want to assume you've already noticed the match right in front of the cursor.
Jefromi
A: 

It sounds like your problem is more with the behaviour of t rather than ;.

In your example, lets say you start at 'e':

stackov[e]rflow rocks

I'm guessing you'd (reasonably) expect tr to jump forward to [ ]rocks rather than staying in place.

If so, you should leave ; as is and perhaps remap t to lt or something.

Peter Gibson
Good point. From what I can tell, though, `;` is someone implemented separately from the `tTfF` commands -- even if I remap `t` as you suggest, it doesn't change the behavior of `;`.
Drew Frank
+3  A: 

Maybe it's not the answer you are looking for but I could not resist writing a VIM script for this. I put it in my .vimrc and it works for me:

map ; :call Semicolon()<CR>
function Semicolon()
   let s:pos1 = getpos(".")
   normal! ;
   let s:pos2 = getpos(".")
   if s:pos1 == s:pos2
      normal! 2;
   endif
endfunction

The basic idea is that ; will not move to the next match, but 2; will (if there is a match). The script supports ; after any of tTfF. The easiest way to implement the , command is to write a similar function for that.

EDIT Changed the script after Luc's excellent suggestion

EDIT2

OK, these things are always more difficult than I originally think. The current mapping has the following problems:

  1. Suppose you did a search like tr above. Now what should d; or c; do? As far as I'm concerned they should delete or change up until the first r not the second. This can be solved by only doing the mapping for normal and visual mode, not operator pending mode.
  2. The current mapping does not work in visual mode. i.e., if you type v;;;; after the first ; the editor is no longer in visual mode (because of the :call). This can be solved by calling the function using @= instead of :call.

So now I end up with the following in my .vimrc (I also made one function for , and ;):

" Remap ; and , commands so they also work after t and T
" Only do the remapping for normal and visual mode, not operator pending
" Use @= instead of :call to prevent leaving visual mode
nmap ; @=FixCommaAndSemicolon(";")<CR>
nmap , @=FixCommaAndSemicolon(",")<CR>
vmap ; @=FixCommaAndSemicolon(";")<CR>
vmap , @=FixCommaAndSemicolon(",")<CR>
function FixCommaAndSemicolon(command)
   let s:pos1 = getpos(".")
   execute "normal! " . a:command
   let s:pos2 = getpos(".")
   if s:pos1 == s:pos2
      execute "normal! 2" . a:command
   endif
   return ""
endfunction
Peter van der Heijden
Prefer "normal! ;" to "normal _;"
Luc Hermitte
@Luc - Good suggestion. I actually searched for an option like that, but missed it. I'll edit my script
Peter van der Heijden
This is perfect thanks! Out of curiousity, why did you think it would not be the answer I'm looking for? Is there a downside to using scripts like this?
Drew Frank
@Drew - AFAIK there is no downside to scripting (apart form polluting your .vimrc). It might just have been that you were looking for a simple command to achieve this, not something that involves scripting.
Peter van der Heijden
the downside is that when you move to a vim with the standard ; mapping, it'll drive you mad.
slim