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 character 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!
I am wondering how to use one hotkey mapping two command in vim.
for exmpale, I already have those two mapping
map <silent> <F7> zM
map <silent> <F8> zR
But, I just want to use F8 to toggle between zM and zR.
Hoping anyone can give me solution.
Thanks a lot.
Won't zA do what you wanted...?
If it won't then we need to go deeper. http://www.vim.org/scripts/script.php?script_id=1494 tells you what to do, here's the relevant script:
map <buffer> F8 :call ToggleFold()<CR>
let b:folded = 1
function! ToggleFold()
if( b:folded == 0 )
exec "normal! zM"
let b:folded = 1
else
exec "normal! zR"
let b:folded = 0
endif
endfunction
Can you have Vim expand a fold automatically when the cursor touches it?
See the foldopen option. It controls which groups of commands will lead to
opening a fold if the cursor is moved into a closed fold.
Note that vertical movements do not open a closed fold, though. Moreover,
there is no setting in foldopen to enable this behavior. When hor item is
set in foldopen option, to open a fold one can use h, l or other
horizontal movement commands. In case if it is crucial to automatically open
a fold on any cursor movement that touches it, one can approach this problem
by remapping some subset of vertical movement commands like it is shown below.
nnoremap <silent> j :<c-u>call MoveUpDown('j', +1, 1)<cr>
nnoremap <silent> k :<c-u>call MoveUpDown('k', -1, 1)<cr>
nnoremap <silent> gj :<c-u>call MoveUpDown('gj', +1, 1)<cr>
nnoremap <silent> gk :<c-u>call MoveUpDown('gk', -1, 1)<cr>
nnoremap <silent> <c-d> :<c-u>call MoveUpDown("\<lt>c-d>", +1, '&l:scroll')<cr>
nnoremap <silent> <c-u> :<c-u>call MoveUpDown("\<lt>c-u>", -1, '&l:scroll')<cr>
nnoremap <silent> <c-f> :<c-u>call MoveUpDown("\<lt>c-f>", +1, 'winheight("%")')<cr>
nnoremap <silent> <c-b> :<c-u>call MoveUpDown("\<lt>c-b>", -1, 'winheight("%")')<cr>
function! MoveUpDown(cmd, dir, ndef)
let n = v:count == 0 ? eval(a:ndef) : v:count
let l = line('.') + a:dir * n
silent! execute l . 'foldopen!'
execute 'norm! ' . n . a:cmd
endfunction
An inferior, but a bit thriftier solution would be to open a fold on every
cursor movement.
autocmd CursorMoved,CursorMovedI * silent! foldopen
Unfortunately, this solution is not general one. After the fold under the
cursor is opened, the cursor is positioned on the first line of that fold. If
this behavior is undesirable, one can follow the vertical direction of
a movement, and place the cursor on the last line of the fold when the cursor
is moving bottom-up.
autocmd CursorMoved,CursorMovedI * call OnCursorMove()
function! OnCursorMove()
let l = line('.')
silent! foldopen
if exists('b:last_line') && l < b:last_line
norm! ]z
endif
let b:last_line = l
endfunction
However, a fold will not be opened if the movement jumps over the fold. For
example, 2j on the line just above a fold will put the cursor on the line
just after that fold, not the second line in it.
set foldopen=all
seems to do what you want. You may also make an autocommand for cursor movement:
au CursorMoved * call AutoOpen()
calling a function like:
function! AutoOpen()
if foldclosed(".") == line(".")
call feedkeys("zo")
endif
endfunction
If you want this to also work in insert mode, use:
au CursorMoved,CursorMovedI * call AutoOpen()
:help fdo and possibly :help fcl may help you. I have this line in my .vimrc:
set foldopen=block,hor,insert,jump,mark,percent,quickfix,search,tag,undo
When I'm using vim I generally never want to move to a punctuation mark when I press w or b to go forwards or backwards. So I'm wondering if there's a setting or something to change this functionality?
e.g. If I've got some code like
object.method(args)
and my cursor is at the [o] in "object" then I want w to move to the [m] in "method", and another w to move to the [a] in "args". I don't want it to land on the [.] or the [(]. If I've ever wanted to move to a punctuation char I've always used f or F to jump straight to it. I've never personally wanted to move to a punctuation char when I move through words and I just realized this is really bugging me.
I too find that I would like a movement that is more inclusive that w, but not as inclusive as W. In particular, I would like a movement that only considers tokens beginning with alphanumeric characters as significant.
So I came up with the following:
" <SPACE> : forward to next word beginning with alphanumeric char
" <S-SPACE> : backward to prev word beginning with alphanumeric char
" <C-SPACE> : same as above (as <S-SPACE> not available in console Vim
" <BS> : back to prev word ending with alphanumeric char
function! <SID>GotoPattern(pattern, dir) range
let g:_saved_search_reg = #/
let l:flags = "We"
if a:dir == "b"
let l:flags .= "b"
endif
for i in range(v:count1)
call search(a:pattern, l:flags)
endfor
let #/ = g:_saved_search_reg
endfunction
nnoremap <silent> <SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'f')<CR>
vnoremap <silent> <SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv/\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <S-SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'b')<CR>
vnoremap <silent> <S-SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv?\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <BS> :call <SID>GotoPattern('[A-Za-z0-9_]\(\>\\|$\)', 'b')<CR>
vnoremap <silent> <BS> :<C-U>let g:_saved_search_reg=#/<CR>gv?[A-Za-z0-9_]\(\>\\|$\)<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
" Redundant mapping of <C-SPACE> to <S-SPACE> so that
" above mappings are available in console Vim.
"noremap <C-#> <C-B>
if has("gui_running")
map <silent> <C-Space> <S-SPACE>
else
if has("unix")
map <Nul> <S-SPACE>
else
map <C-#> <S-SPACE>
endif
endif
I have had this for a long time now, and I find that I use <SPACE>/<C-SPACE> movements so much more than w and W; it just seems more useful when coding. You can, of course, map the commands to whatever keys you find useful or more appropriate.
Even running the risk of creating a script for something that's built-in (like
I did last time), here is a little function that may help accomplishing
this.
function! JumpToNextWord()
normal w
while strpart(getline('.'), col('.')-1, 1) !~ '\w'
normal w
endwhile
endfunction
Basically, what it does is executing the standard w and repeating it
if the character under the cursor is not in a word character (feel free to
change that pattern.
If you add that and a little map in your .vimrc:
nnoremap <silent> ,w :call JumpToNextWord()<CR>
It should work.