I currently write a substitute function that I often need for programming in vim.
The functions I already wrote look like this and run basically okay for searching and replacing strings which do not have any special characters inside. I already realized to escape the "/" automatically. My question is, how do I have to adapt the escape() function in the line
execute ':silent :argdo %s/' . escape(searchPattern, '/') . '/' . escape(replacePattern, '/') . '/ge'
So that automatically all of the characters that have to be escaped will be escaped?
" MAIN FUNCTION
" inspired by http://vimcasts.org/episodes/project-wide-find-and-replace/
function! SubstituteProjectwide(searchInput)
:set hidden
let cwd = getcwd()
let filename=expand('%:p')
call inputsave()
let searchPattern = input('Search for: ', a:searchInput)
let replacePattern = input('Replace "' . searchPattern . '" with: ')
let filePattern = input('Filepattern: ', cwd . '/**/*.*')
call inputrestore()
execute ':silent :args ' . filePattern
execute ':silent :vimgrep /' . searchPattern . '/g ##'
execute ':silent :Qargs'
execute ':silent :argdo %s/' . escape(searchPattern, '/\') . '/' . escape(replacePattern, '/\') . '/ge'
execute ':silent :edit ' . filename
echo 'Replaced "' . searchPattern . '" with "' . replacePattern . '" in ' . filePattern
endfunction
" VISUAL ENTRYPOINT WITH SELECTED TEXT
function! SubstituteProjectwideVisual()
let v = @*
call SubstituteProjectwide(GetVisualSelectedText())
endfunction
:vnoremap <F6> :call SubstituteProjectwideVisual()<cr>
" NORMAL ENTRYPOINT WITH WORD UNDER CURSOR
function! SubstituteProjectwideNormal()
let wordUnderCursor = expand("<cword>")
call SubsituteProjectwide(wordUnderCursor)
endfunction
:nnoremap <F6> :call SubstituteProjectwideNormal()<cr>
" GETTING THE FILES W## Heading ##ICH CONTAIN SEARCH PATTERN
" copied from http://vimcasts.org/episodes/project-wide-find-and-replace/
command! -nargs=0 -bar Qargs execute 'args' QuickfixFilenames()
function! QuickfixFilenames()
let buffer_numbers = {}
for quickfix_item in getqflist()
let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
endfor
return join(map(values(buffer_numbers), 'fnameescape(v:val)'))
endfunction
" GETTING THE CURRENT VISUAL SELECTION
" copied from: https://stackoverflow.com/questions/1533565/how-to-get-visually-selected-text-in-vimscript
function! GetVisualSelectedText()
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
UPDATE
I managed to escape many characters like that
escape(searchPattern, ' / \') . '/' . escape(replacePattern, ' / \')
But how do I know which list of characters I have to escape, when it is basically possible, that every character can be inside the search and also the replace string?
To do a literal substitution, specify "very-nomagic" (:help /\V
) , and escape the separator (/
) and \
in the source.
In the replacement, &
and ~
must be escaped, too, if the 'magic'
option is set. (\V
doesn't work here.)
execute ':silent :argdo %s/\V' . escape(searchPattern, '/\') . '/' . escape(replacePattern, '/\' . (&magic ? '&~' : '')) . '/ge'
Line breaks (if possible) must be changed from ^M
to \n
:
execute ':silent :argdo %s/\V' . substitute(escape(searchPattern, '/\'),"\n",'\\n','ge') . '/' . escape(replacePattern, '/\' . (&magic ? '&~' : '')) . '/ge'