Suppose that I have a document like this, and I want to search for all occurences of the URL:
Vim resources: [http://example.com/search?q=vim][q]
...
[q]: http://example.com/search?q=vim
I don't want to type it out in full, so I'll place my cursor on the first URL, and run "uyi[
to yank it into the 'u' register. Now to search for it, I'd like to just paste the contents of that register into the search field by running:
/\V<c-r>u<CR>
This results in Vim searching for the string 'http:' - because the '/' character terminates the search field.
I can get around the problem by running this instead:
/\V<c-r>=escape(@u, '\/')<CR><CR>
But it's a lot of typing!
How can I create a mapping for Vim's commandline that simplifies this workflow?
My ideal workflow would go something like this:
- press
/\V
to bring up the search prompt, and use very nomagic mode
- hit ctrl-x to trigger the custom mapping (ctrl-x is available)
- Vim listens for the next key press... (pressing
<Esc>
would cancel)
- pressing 'u' would escape the contents of the 'u' register, and insert on the command line
Try this:
cnoremap <c-x> <c-r>=<SID>PasteEscaped()<cr>
function! s:PasteEscaped()
" show some kind of feedback
echo ":".getcmdline()."..."
" get a character from the user
let char = getchar()
if char == "\<esc>"
return ''
else
let register_content = getreg(nr2char(char))
return escape(register_content, '\/')
endif
endfunction
By the way, something that might be useful to know (if you don't already) is that you can use ?
as the delimiter for :s
. Which means that you could write a search-and-replace for an url like so:
:s?http://foo.com?http://bar.com?g
I've accepted Andrew Radev's solution, which solved the hard parts. But here's the version that I've added to my vimrc file, which adds a couple of enhancements:
cnoremap <c-x> <c-r>=<SID>PasteEscaped()<cr>
function! s:PasteEscaped()
echo "\\".getcmdline()."\""
let char = getchar()
if char == "\<esc>"
return ''
else
let register_content = getreg(nr2char(char))
let escaped_register = escape(register_content, '\'.getcmdtype())
return substitute(escaped_register, '\n', '\\n', 'g')
endif
endfunction
This should work:
- whether you use
/
or ?
(to search forwards, or backwards)
- and when the pasted register includes multiple lines
Also, I changed the prompt. While waiting for a register, the prompt switches to \
- which seems like a suitable cue for 'PasteEscaped'. Also, I've appended a "
, which mimics Vim's behavior after pressing <c-r>
at the command line.
If you've any further suggestions for improvements, please leave a comment.
How about different workflow? For example, creating your own operator to search target text as is:
" https://gist.github.com/1213642
" Requiement: https://github.com/kana/vim-operator-user
map YourFavoriteKeySequence <Plug>(operator-search-target-text)
call operator#user#define('search-target-text', 'OperatorSerachTargetText')
function! OperatorSerachTargetText(motion_wise)
execute 'normal!' '`['.operator#user#visual_command_from_wise_name(a:motion_wise).'`]"xy'
let @/ = '\V' . escape(substitute(@x, '[\r\n]$', '', ''), '\')
normal! n
endfunction
I like @nelstrom's solution and made a small change to support escaping [ and ].
cnoremap <c-x> <c-r>=<SID>PasteEscaped()<cr>
function! s:PasteEscaped()
echo "\\".getcmdline()."\""
let char = getchar()
if char == "\<esc>"
return ''
else
let register_content = getreg(nr2char(char))
let escaped_register = escape(register_content, '\'.getcmdtype())
let escaped_register2 = substitute(escaped_register,'[','\\[','g')
let escaped_register3 = substitute(escaped_register2,']','\\]','g')
return substitute(escaped_register3, '\n', '\\n', 'g')
endif
endfunction