Using vim's f command over multiple lines
Anyone knows how to quickly find the next occurrence of a character (like the f command) but multi-line? I.e. to quickly jump to the next occurrence of some c开发者_高级运维haracter in a file?
Isn't that what "/" does?
If you're looking for the next "x" then do /x while in command mode.
Then you can hit "n" to advance to the next x, and then the next x, etc.
There are lots of vim cheat sheets out there with all kinds of tips.
There's an example of redefining f
to ignore case in the 'eval.txt' help file.
:h eval.txt
(search for "ignore case" a couple times)
We can modify that to do what you want. Add the following function to your ~/.vimrc
file or better yet, create a plugin file: ~/.vim/plugin/find-char.vim
(create the directories if you do not already have them).
function FindChar()
let c = nr2char( getchar() )
let match = search('\V' . c)
endfunction
Then, in your ~/.vimrc
add the following line:
nmap f :call FindChar()<CR>
Now, f
should work like you want it to.
BTW, this was tested with Vim 7.2 on Ubuntu 10.04.
Christian Brabandt's ft_improved plugin extends the built-in f
/ t
commands to search in following lines, too.
Having wanted to know exactly the same thing I looked through the answers here. None of are exactly what I wanted so I cobbled together a few of them.
q335's answer was the closest because it handles omaps properly which is necessary to do something like dt}
(delete everything up to, but not including the next curly brace) but Curt's answer handles special character searching and uses a single function which to me is much more preferable so I'm not adding too much to my .vimrc
Here is my result:
"Makes f and t work across multiple lines
nmap <silent> f :call FindChar(0, 0, 0)<cr>
omap <silent> f :call FindChar(0, 1, 0)<cr>
nmap <silent> F :call FindChar(1, 0, 0)<cr>
omap <silent> F :call FindChar(1, 1, 0)<cr>
nmap <silent> t :call FindChar(0, 0, 1)<cr>
omap <silent> t :call FindChar(0, 0, 0)<cr>
nmap <silent> T :call FindChar(1, 0, 1)<cr>
omap <silent> T :call FindChar(1, 0, 0)<cr>
"Functions
fun! FindChar(back, inclusive, exclusive)
let flag = 'W'
if a:back
let flag = 'Wb'
endif
if search('\V' . nr2char(getchar()), flag)
if a:inclusive
norm! l
endif
if a:exclusive
norm! h
endif
endif
endfun
Aaaa, vimscript. It takes about 2 years to write 20 lines well :D. Here is the latest, sleekest version: works for ALL modes: visual, operator pending, normal.
let prvft='f'
let prvftc=32
fun! MLvF(c,...)
let [g:prvftc,g:prvft]=[a:c,a:0? 'f':'F']
let pos=searchpos('\C\V'.nr2char(g:prvftc),'bW')
call setpos("'x", pos==[0,0]? [0,line('.'),col('.'),0] : [0,pos[0],pos[1],0])
return "`x"
endfun
fun! MLvf(c,...)
let [g:prvftc,g:prvft]=[a:c,a:0? 'F':'f']
let pos=searchpos('\C\V'.nr2char(g:prvftc).(mode(1)=='no'? '\zs' : ''),'W')
call setpos("'x", pos==[0,0]? [0,line('.'),col('.'),0] : [0,pos[0],pos[1],0])
return "`x"
endfun
fun! MLvT(c,...)
let [g:prvftc,g:prvft]=[a:c,a:0? 't':'T']
let pos=searchpos('\C\V'.nr2char(g:prvftc).'\zs','bW')
call setpos("'x", pos==[0,0]? [0,line('.'),col('.'),0] : [0,pos[0],pos[1],0])
return "`x"
endfun
fun! MLvt(c,...)
let [g:prvftc,g:prvft]=[a:c,a:0? 'T':'t']
let pos=searchpos('\C\V\_.'.(mode(1)=='no'? '\zs' : '').nr2char(g:prvftc),'W')
call setpos("'x", pos==[0,0]? [0,line('.'),col('.'),0] : [0,pos[0],pos[1],0])
return "`x"
endfun
no <expr> F MLvF(getchar())
no <expr> f MLvf(getchar())
no <expr> T MLvT(getchar())
no <expr> t MLvt(getchar())
no <expr> ; MLv{prvft}(prvftc)
no <expr> , MLv{prvft<#'Z'? tolower(prvft) : toupper(prvft)}(prvftc,1)
Or the super garbled:
let [pvft,pvftc]=[1,32]
fun! Multift(x,c,i)
let [g:pvftc,g:pvft]=[a:c,a:i]
let pos=searchpos((a:x==2? mode(1)=='no'? '\C\V\_.\zs' : '\C\V\_.' : '\C\V').(a:x==1 && mode(1)=='no' || a:x==-2? nr2char(g:pvftc).'\zs' : nr2char(g:pvftc)),a:x<0? 'bW':'W')
call setpos("'x", pos[0]? [0,pos[0],pos[1],0] : [0,line('.'),col('.'),0])
return "`x"
endfun
no <expr> F Multift(-1,getchar(),-1)
no <expr> f Multift(1,getchar(),1)
no <expr> T Multift(-2,getchar(),-2)
no <expr> t Multift(2,getchar(),2)
no <expr> ; Multift(pvft,pvftc,pvft)
no <expr> , Multift(-pvft,pvftc,pvft)
One approach to this problem is to use the easymotion plugin.
This lets you use motions such as f
across the entire visible window of text. You trigger the plugin, then enter f
and the character you are looking for. It highlights each position that the character appears on screen in a highlight color (e.g. red), and shows the position using a letter (a
, b
, c
, d
, ...). You simply press the letter corresponding to the position you wish to jump to.
The plugin's README on Github includes an animation that visually demonstrates how it works.
You could make a mapping to go to the next character under the cursor:
:map f yl/\V<c-r>"<c-m>
the \V will make sure symbols are matched literally.
Also, you may want to look at the *
and #
commands, which are already defined for you, although they might not be what you want.
The most reasonable way of doing this at the moment is hidden in this comment.
You just have to install two plugins: vim-repeat and vim-fanfingtastic.
Personally, I use Vundle to manage my vim plugins.
So this is the way you can make f
, F
, etc. work as desired:
- Install Vundle.
Add these lines to your
.vimrc
:Plugin 'tpope/vim-repeat' Plugin 'dahu/vim-fanfingtastic'
- Run
$ vim +PluginInstall +qall
in your shell. - Voila!
精彩评论