5

As a poor-mans refactoring, I'd like to do a search and replace, but omit strings that are in double quotes (C/C++ quoting rules). For example

cout << "Some variable " << variable << endl;

replacing variable -> m_variable

cout << "Some variable " << m_variable << endl;

So I'd like the equivalent of

:%s/variable/m_variable/g

but ignoring text in quotes. Is there a way to do this in vim?

1
  • 7
    Use the c flag for "confirmation": %s/variable/m_&/gc.
    – romainl
    Commented Apr 22, 2015 at 14:20

1 Answer 1

5

It can be done by testing the syntax name behind the variable to replace:

:%s/variable/\=(match(map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")'), '\cstring')==-1 ? 'NEw' : submatch(0))/g

But nobody will want to use that. Instead, we'd better define a new command.

:command! -bang -nargs=1 -range SubstituteUnlesString 
    \ <line1>,<line2>call s:SubstituteUnlessString("<bang>", <f-args>)

" Function: s:SubstituteUnlessString(bang, repl_arg) {{{3
function! s:SubstituteUnlessString(bang, repl_arg) range abort
  let do_loop = a:bang != "!"
  let sep = a:repl_arg[0]
  let fields = split(a:repl_arg, sep)
  let cleansed_fields = map(copy(fields), 'substitute(v:val, "\\\\[<>]", "", "g")')
  " build the action to execute
  if fields[1] =~ '^\\='
    let replacement = matchstr(fields[1], '^\\=\zs.*')
  elseif fields[1] =~ '&\|\\\d'
    let replacement = "'".substitute(fields[1], '&\|\\\(\d\)', '\=string(".submatch(".(submatch(0)=="&"?"0":submatch(1)).").")', 'g') ."'"
  else
    let replacement = string(fields[1])
  endif
  let action = '\=(match(map(synstack(line("."), col(".")), "synIDattr(v:val, \"name\")"), "\\cstring")==-1 ? '.replacement.' : submatch(0))'
  let cmd = a:firstline . ',' . a:lastline . 's'
    \. sep . fields[0]
    \. sep . action
        \. sep.(len(fields)>=3 ? fields[2] : '')
  " echomsg cmd
  exe cmd
endfunction

That you would be able to use this way:

:%SubstituteUnlessString/variable/m_variable/g
" or
:1,3SubstituteUnlessString#variable#m_&#g

Yeah. It's a bit overkill. The c flag from :substitute is more than enough.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.