" ingo/compat/substitution: Allow recursive use of sub-replace-expression in older Vim versions. " " DEPENDENCIES: " " Copyright: (C) 2014-2020 Ingo Karkat " The VIM LICENSE applies to this script; see ':help copyright'. " " Maintainer: Ingo Karkat let s:compatFor = (exists('g:IngoLibrary_CompatFor') ? ingo#collections#ToDict(split(g:IngoLibrary_CompatFor, ',')) : {}) "****************************************************************************** "* PURPOSE: " Use |sub-replace-expression| again within the replacement expression of " another substitute() or :substitute. In Vim 8.0 and earlier, the regexp " engine was not reentrant, and a nested replacement expression would be taken " literally instead of being interpreted. "* ASSUMPTIONS / PRECONDITIONS: " None. "* EFFECTS / POSTCONDITIONS: " None. "* INPUTS: " See |substitute()|. "* RETURN VALUES: " Replacement. "****************************************************************************** if (v:version == 800 && has('patch20') || v:version > 800) && ! has_key(s:compatFor, 'RecursiveSubstitutionExpression') function! ingo#compat#substitution#RecursiveSubstitutionExpression( expr, pat, sub, flags ) return substitute(a:expr, a:pat, a:sub, a:flags) endfunction else function! s:Submatch( idx ) return get(s:submatches, a:idx, '') endfunction function! s:EmulateSubmatch( originalExpr, expr, pat, sub ) let s:submatches = matchlist(a:expr, a:pat) if empty(s:submatches) let l:innerReplacement = a:originalExpr else let l:innerReplacement = eval(a:sub) endif unlet s:submatches return l:innerReplacement endfunction function! ingo#compat#substitution#RecursiveSubstitutionExpression( expr, pat, sub, flags ) if a:sub =~# '^\\=' " Recursive use of \= is not allowed, so we need to emulate it: " matchlist() will get us the list of (sub-)matches, which we'll inject " into the passed expression via a s:Submatch() surrogate function for " submatch(). let l:emulatedSub = substitute(a:sub[2:], '\w\@" endwhile else " For a first-only replacement, just match and replace once. let s:submatches = matchlist(a:expr, a:pat) let l:innerReplacement = s:EmulateSubmatch(a:expr, a:expr, a:pat, l:emulatedSub) let l:replacement = substitute(a:expr, a:pat, escape(l:innerReplacement, '\&'), '') endif else let l:replacement = substitute(a:expr, a:pat, a:sub, a:flags) endif return l:replacement endfunction endif " vim: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax :