Drew Frank
Drew Frank

Reputation: 590

The behavior of ; to repeat the last t command bothers me. Can you help me make it better?

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?

Upvotes: 22

Views: 14422

Answers (4)

glts
glts

Reputation: 22724

As of Vim version 7.3.235 this annoyance has been amended. Now the default is the behaviour you had expected in the first place: ; makes the cursor jump to right before the second "r".

This was the patch announcement:

Patch 7.3.235
Problem: ";" gets stuck on a "t" command, it's not useful.
Solution: Add the ';' flag in 'cpo'. (Christian Brabandt)

The old behaviour has been demoted to a compatibility option. You can bring it back with :set cpo+=;. See :h cpo-;.

Upvotes: 38

heijp06
heijp06

Reputation: 11808

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 

Upvotes: 12

Peter Gibson
Peter Gibson

Reputation: 19564

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.

Upvotes: 1

Jim Deville
Jim Deville

Reputation: 10672

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?

Upvotes: 2

Related Questions