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.
c
flag for "confirmation":%s/variable/m_&/gc
.