Reputation: 590
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
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
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:
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.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
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
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