mirror of
https://github.com/neovim/neovim.git
synced 2025-12-15 19:05:40 +00:00
Merge pull request #19072 from zeertzjq/vim-8.2.4628
vim-patch:8.2.{4628,4895,4977,5146,5154}
This commit is contained in:
@@ -3468,7 +3468,6 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
static int pre_hl_id = 0;
|
||||
pos_T old_cursor = curwin->w_cursor;
|
||||
int start_nsubs;
|
||||
int save_ma = 0;
|
||||
|
||||
bool did_save = false;
|
||||
|
||||
@@ -4060,7 +4059,8 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
// there is a replace pattern.
|
||||
if (!cmdpreview || has_second_delim) {
|
||||
long lnum_start = lnum; // save the start lnum
|
||||
save_ma = curbuf->b_p_ma;
|
||||
int save_ma = curbuf->b_p_ma;
|
||||
int save_sandbox = sandbox;
|
||||
if (subflags.do_count) {
|
||||
// prevent accidentally changing the buffer by a function
|
||||
curbuf->b_p_ma = false;
|
||||
@@ -4069,20 +4069,24 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
// Save flags for recursion. They can change for e.g.
|
||||
// :s/^/\=execute("s#^##gn")
|
||||
subflags_T subflags_save = subflags;
|
||||
// get length of substitution part
|
||||
|
||||
// Disallow changing text or switching window in an expression.
|
||||
textlock++;
|
||||
// Get length of substitution part, including the NUL.
|
||||
// When it fails sublen is zero.
|
||||
sublen = vim_regsub_multi(®match,
|
||||
sub_firstlnum - regmatch.startpos[0].lnum,
|
||||
(char_u *)sub, (char_u *)sub_firstline, 0,
|
||||
REGSUB_BACKSLASH | (p_magic ? REGSUB_MAGIC : 0));
|
||||
textlock--;
|
||||
|
||||
// If getting the substitute string caused an error, don't do
|
||||
// the replacement.
|
||||
// Don't keep flags set by a recursive call
|
||||
subflags = subflags_save;
|
||||
if (aborting() || subflags.do_count) {
|
||||
if (sublen == 0 || aborting() || subflags.do_count) {
|
||||
curbuf->b_p_ma = save_ma;
|
||||
if (sandbox > 0) {
|
||||
sandbox--;
|
||||
}
|
||||
sandbox = save_sandbox;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
@@ -4111,10 +4115,12 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
int start_col = new_end - new_start;
|
||||
current_match.start.col = start_col;
|
||||
|
||||
textlock++;
|
||||
(void)vim_regsub_multi(®match,
|
||||
sub_firstlnum - regmatch.startpos[0].lnum,
|
||||
(char_u *)sub, (char_u *)new_end, sublen,
|
||||
REGSUB_COPY | REGSUB_BACKSLASH | (p_magic ? REGSUB_MAGIC : 0));
|
||||
textlock--;
|
||||
sub_nsubs++;
|
||||
did_sub = true;
|
||||
|
||||
|
||||
@@ -2892,11 +2892,13 @@ static void append_command(char *cmd)
|
||||
|
||||
STRCAT(IObuff, ": ");
|
||||
d = (char *)IObuff + STRLEN(IObuff);
|
||||
while (*s != NUL && (char_u *)d - IObuff < IOSIZE - 7) {
|
||||
while (*s != NUL && (char_u *)d - IObuff + 5 < IOSIZE) {
|
||||
if ((char_u)s[0] == 0xc2 && (char_u)s[1] == 0xa0) {
|
||||
s += 2;
|
||||
STRCPY(d, "<a0>");
|
||||
d += 4;
|
||||
} else if ((char_u *)d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) {
|
||||
break;
|
||||
} else {
|
||||
mb_copy_char((const char_u **)&s, (char_u **)&d);
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
|
||||
static char_u e_recursive[] = N_("E956: Cannot use pattern recursively");
|
||||
static char_u e_regexp_number_after_dot_pos_search[]
|
||||
= N_("E1204: No Number allowed after .: '\\%%%c'");
|
||||
static char_u e_substitute_nesting_too_deep[] = N_("E1290: substitute nesting too deep");
|
||||
|
||||
#define NOT_MULTI 0
|
||||
#define MULTI_ONE 1
|
||||
@@ -1722,6 +1723,19 @@ int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *de
|
||||
return result;
|
||||
}
|
||||
|
||||
// When nesting more than a couple levels it's probably a mistake.
|
||||
#define MAX_REGSUB_NESTING 4
|
||||
static char_u *eval_result[MAX_REGSUB_NESTING] = { NULL, NULL, NULL, NULL };
|
||||
|
||||
#if defined(EXITFREE)
|
||||
void free_resub_eval_result(void)
|
||||
{
|
||||
for (int i = 0; i < MAX_REGSUB_NESTING; i++) {
|
||||
XFREE_CLEAR(eval_result[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int destlen, int flags)
|
||||
{
|
||||
char_u *src;
|
||||
@@ -1734,7 +1748,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
|
||||
fptr_T func_one = (fptr_T)NULL;
|
||||
linenr_T clnum = 0; // init for GCC
|
||||
int len = 0; // init for GCC
|
||||
static char_u *eval_result = NULL;
|
||||
static int nesting = 0;
|
||||
bool copy = flags & REGSUB_COPY;
|
||||
|
||||
// Be paranoid...
|
||||
@@ -1745,6 +1759,11 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
|
||||
if (prog_magic_wrong()) {
|
||||
return 0;
|
||||
}
|
||||
if (nesting == MAX_REGSUB_NESTING) {
|
||||
emsg(_(e_substitute_nesting_too_deep));
|
||||
return 0;
|
||||
}
|
||||
int nested = nesting;
|
||||
src = source;
|
||||
dst = dest;
|
||||
|
||||
@@ -1752,19 +1771,20 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
|
||||
if (expr != NULL || (source[0] == '\\' && source[1] == '=')) {
|
||||
// To make sure that the length doesn't change between checking the
|
||||
// length and copying the string, and to speed up things, the
|
||||
// resulting string is saved from the call with "flags & REGSUB_COPY"
|
||||
// == 0 to the call with "flags & REGSUB_COPY" != 0.
|
||||
// resulting string is saved from the call with
|
||||
// "flags & REGSUB_COPY" == 0 to the call with
|
||||
// "flags & REGSUB_COPY" != 0.
|
||||
if (copy) {
|
||||
if (eval_result != NULL) {
|
||||
STRCPY(dest, eval_result);
|
||||
dst += STRLEN(eval_result);
|
||||
XFREE_CLEAR(eval_result);
|
||||
if (eval_result[nested] != NULL) {
|
||||
STRCPY(dest, eval_result[nested]);
|
||||
dst += STRLEN(eval_result[nested]);
|
||||
XFREE_CLEAR(eval_result[nested]);
|
||||
}
|
||||
} else {
|
||||
const bool prev_can_f_submatch = can_f_submatch;
|
||||
regsubmatch_T rsm_save;
|
||||
|
||||
xfree(eval_result);
|
||||
XFREE_CLEAR(eval_result[nested]);
|
||||
|
||||
// The expression may contain substitute(), which calls us
|
||||
// recursively. Make sure submatch() gets the text from the first
|
||||
@@ -1779,6 +1799,11 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
|
||||
rsm.sm_maxline = rex.reg_maxline;
|
||||
rsm.sm_line_lbr = rex.reg_line_lbr;
|
||||
|
||||
// Although unlikely, it is possible that the expression invokes a
|
||||
// substitute command (it might fail, but still). Therefore keep
|
||||
// an array of eval results.
|
||||
nesting++;
|
||||
|
||||
if (expr != NULL) {
|
||||
typval_T argv[2];
|
||||
typval_T rettv;
|
||||
@@ -1806,23 +1831,24 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
|
||||
}
|
||||
if (rettv.v_type == VAR_UNKNOWN) {
|
||||
// something failed, no need to report another error
|
||||
eval_result = NULL;
|
||||
eval_result[nested] = NULL;
|
||||
} else {
|
||||
char buf[NUMBUFLEN];
|
||||
eval_result = (char_u *)tv_get_string_buf_chk(&rettv, buf);
|
||||
if (eval_result != NULL) {
|
||||
eval_result = vim_strsave(eval_result);
|
||||
eval_result[nested] = (char_u *)tv_get_string_buf_chk(&rettv, buf);
|
||||
if (eval_result[nested] != NULL) {
|
||||
eval_result[nested] = vim_strsave(eval_result[nested]);
|
||||
}
|
||||
}
|
||||
tv_clear(&rettv);
|
||||
} else {
|
||||
eval_result = (char_u *)eval_to_string((char *)source + 2, NULL, true);
|
||||
eval_result[nested] = (char_u *)eval_to_string((char *)source + 2, NULL, true);
|
||||
}
|
||||
nesting--;
|
||||
|
||||
if (eval_result != NULL) {
|
||||
if (eval_result[nested] != NULL) {
|
||||
int had_backslash = false;
|
||||
|
||||
for (s = eval_result; *s != NUL; MB_PTR_ADV(s)) {
|
||||
for (s = eval_result[nested]; *s != NUL; MB_PTR_ADV(s)) {
|
||||
// Change NL to CR, so that it becomes a line break,
|
||||
// unless called from vim_regexec_nl().
|
||||
// Skip over a backslashed character.
|
||||
@@ -1844,12 +1870,12 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int des
|
||||
}
|
||||
if (had_backslash && (flags & REGSUB_BACKSLASH)) {
|
||||
// Backslashes will be consumed, need to double them.
|
||||
s = vim_strsave_escaped(eval_result, (char_u *)"\\");
|
||||
xfree(eval_result);
|
||||
eval_result = s;
|
||||
s = vim_strsave_escaped(eval_result[nested], (char_u *)"\\");
|
||||
xfree(eval_result[nested]);
|
||||
eval_result[nested] = s;
|
||||
}
|
||||
|
||||
dst += STRLEN(eval_result);
|
||||
dst += STRLEN(eval_result[nested]);
|
||||
}
|
||||
|
||||
can_f_submatch = prev_can_f_submatch;
|
||||
|
||||
@@ -1220,6 +1220,30 @@ func Test_recalling_cmdline()
|
||||
cunmap <Plug>(save-cmdline)
|
||||
endfunc
|
||||
|
||||
" this was going over the end of IObuff
|
||||
func Test_report_error_with_composing()
|
||||
let caught = 'no'
|
||||
try
|
||||
exe repeat('0', 987) .. "0\xdd\x80\xdd\x80\xdd\x80\xdd\x80"
|
||||
catch /E492:/
|
||||
let caught = 'yes'
|
||||
endtry
|
||||
call assert_equal('yes', caught)
|
||||
endfunc
|
||||
|
||||
" Test for expanding 2-letter and 3-letter :substitute command arguments.
|
||||
" These commands don't accept an argument.
|
||||
func Test_cmdline_complete_substitute_short()
|
||||
for cmd in ['sc', 'sce', 'scg', 'sci', 'scI', 'scn', 'scp', 'scl',
|
||||
\ 'sgc', 'sge', 'sg', 'sgi', 'sgI', 'sgn', 'sgp', 'sgl', 'sgr',
|
||||
\ 'sic', 'sie', 'si', 'siI', 'sin', 'sip', 'sir',
|
||||
\ 'sIc', 'sIe', 'sIg', 'sIi', 'sI', 'sIn', 'sIp', 'sIl', 'sIr',
|
||||
\ 'src', 'srg', 'sri', 'srI', 'srn', 'srp', 'srl', 'sr']
|
||||
call feedkeys(':' .. cmd .. " \<Tab>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"' .. cmd .. " \<Tab>", @:)
|
||||
endfor
|
||||
endfunc
|
||||
|
||||
func Check_completion()
|
||||
call assert_equal('let a', getcmdline())
|
||||
call assert_equal(6, getcmdpos())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
" Tests for multi-line regexps with ":s".
|
||||
" Tests for the substitute (:s) command
|
||||
|
||||
func Test_multiline_subst()
|
||||
enew!
|
||||
@@ -831,12 +831,317 @@ func Test_using_old_sub()
|
||||
~
|
||||
s/
|
||||
endfunc
|
||||
silent! s/\%')/\=Repl()
|
||||
silent! s/\%')/\=Repl()
|
||||
|
||||
delfunc Repl
|
||||
bwipe!
|
||||
set nocompatible
|
||||
endfunc
|
||||
|
||||
" This was switching windows in between computing the length and using it.
|
||||
func Test_sub_change_window()
|
||||
silent! lfile
|
||||
sil! norm o0000000000000000000000000000000000000000000000000000
|
||||
func Repl()
|
||||
lopen
|
||||
endfunc
|
||||
silent! s/\%')/\=Repl()
|
||||
bwipe!
|
||||
bwipe!
|
||||
delfunc Repl
|
||||
endfunc
|
||||
|
||||
" Test for the 2-letter and 3-letter :substitute commands
|
||||
func Test_substitute_short_cmd()
|
||||
new
|
||||
call setline(1, ['one', 'one one one'])
|
||||
s/one/two
|
||||
call cursor(2, 1)
|
||||
|
||||
" :sc
|
||||
call feedkeys(":sc\<CR>y", 'xt')
|
||||
call assert_equal('two one one', getline(2))
|
||||
|
||||
" :scg
|
||||
call setline(2, 'one one one')
|
||||
call feedkeys(":scg\<CR>nyq", 'xt')
|
||||
call assert_equal('one two one', getline(2))
|
||||
|
||||
" :sci
|
||||
call setline(2, 'ONE One onE')
|
||||
call feedkeys(":sci\<CR>y", 'xt')
|
||||
call assert_equal('two One onE', getline(2))
|
||||
|
||||
" :scI
|
||||
set ignorecase
|
||||
call setline(2, 'ONE One one')
|
||||
call feedkeys(":scI\<CR>y", 'xt')
|
||||
call assert_equal('ONE One two', getline(2))
|
||||
set ignorecase&
|
||||
|
||||
" :scn
|
||||
call setline(2, 'one one one')
|
||||
let t = execute('scn')->split("\n")
|
||||
call assert_equal(['1 match on 1 line'], t)
|
||||
call assert_equal('one one one', getline(2))
|
||||
|
||||
" :scp
|
||||
call setline(2, "\tone one one")
|
||||
redir => output
|
||||
call feedkeys(":scp\<CR>y", 'xt')
|
||||
redir END
|
||||
call assert_equal(' two one one', output->split("\n")[-1])
|
||||
call assert_equal("\ttwo one one", getline(2))
|
||||
|
||||
" :scl
|
||||
call setline(2, "\tone one one")
|
||||
redir => output
|
||||
call feedkeys(":scl\<CR>y", 'xt')
|
||||
redir END
|
||||
call assert_equal("^Itwo one one$", output->split("\n")[-1])
|
||||
call assert_equal("\ttwo one one", getline(2))
|
||||
|
||||
" :sgc
|
||||
call setline(2, 'one one one one one')
|
||||
call feedkeys(":sgc\<CR>nyyq", 'xt')
|
||||
call assert_equal('one two two one one', getline(2))
|
||||
|
||||
" :sg
|
||||
call setline(2, 'one one one')
|
||||
sg
|
||||
call assert_equal('two two two', getline(2))
|
||||
|
||||
" :sgi
|
||||
call setline(2, 'ONE One onE')
|
||||
sgi
|
||||
call assert_equal('two two two', getline(2))
|
||||
|
||||
" :sgI
|
||||
set ignorecase
|
||||
call setline(2, 'ONE One one')
|
||||
sgI
|
||||
call assert_equal('ONE One two', getline(2))
|
||||
set ignorecase&
|
||||
|
||||
" :sgn
|
||||
call setline(2, 'one one one')
|
||||
let t = execute('sgn')->split("\n")
|
||||
call assert_equal(['3 matches on 1 line'], t)
|
||||
call assert_equal('one one one', getline(2))
|
||||
|
||||
" :sgp
|
||||
call setline(2, "\tone one one")
|
||||
redir => output
|
||||
sgp
|
||||
redir END
|
||||
call assert_equal(' two two two', output->split("\n")[-1])
|
||||
call assert_equal("\ttwo two two", getline(2))
|
||||
|
||||
" :sgl
|
||||
call setline(2, "\tone one one")
|
||||
redir => output
|
||||
sgl
|
||||
redir END
|
||||
call assert_equal("^Itwo two two$", output->split("\n")[-1])
|
||||
call assert_equal("\ttwo two two", getline(2))
|
||||
|
||||
" :sgr
|
||||
call setline(2, "one one one")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
sgr
|
||||
call assert_equal('xyz xyz xyz', getline(2))
|
||||
|
||||
" :sic
|
||||
call cursor(1, 1)
|
||||
s/one/two/e
|
||||
call setline(2, "ONE One one")
|
||||
call cursor(2, 1)
|
||||
call feedkeys(":sic\<CR>y", 'xt')
|
||||
call assert_equal('two One one', getline(2))
|
||||
|
||||
" :si
|
||||
call setline(2, "ONE One one")
|
||||
si
|
||||
call assert_equal('two One one', getline(2))
|
||||
|
||||
" :siI
|
||||
call setline(2, "ONE One one")
|
||||
siI
|
||||
call assert_equal('ONE One two', getline(2))
|
||||
|
||||
" :sin
|
||||
call setline(2, 'ONE One onE')
|
||||
let t = execute('sin')->split("\n")
|
||||
call assert_equal(['1 match on 1 line'], t)
|
||||
call assert_equal('ONE One onE', getline(2))
|
||||
|
||||
" :sip
|
||||
call setline(2, "\tONE One onE")
|
||||
redir => output
|
||||
sip
|
||||
redir END
|
||||
call assert_equal(' two One onE', output->split("\n")[-1])
|
||||
call assert_equal("\ttwo One onE", getline(2))
|
||||
|
||||
" :sir
|
||||
call setline(2, "ONE One onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
sir
|
||||
call assert_equal('xyz One onE', getline(2))
|
||||
|
||||
" :sIc
|
||||
call cursor(1, 1)
|
||||
s/one/two/e
|
||||
call setline(2, "ONE One one")
|
||||
call cursor(2, 1)
|
||||
call feedkeys(":sIc\<CR>y", 'xt')
|
||||
call assert_equal('ONE One two', getline(2))
|
||||
|
||||
" :sIg
|
||||
call setline(2, "ONE one onE one")
|
||||
sIg
|
||||
call assert_equal('ONE two onE two', getline(2))
|
||||
|
||||
" :sIi
|
||||
call setline(2, "ONE One one")
|
||||
sIi
|
||||
call assert_equal('two One one', getline(2))
|
||||
|
||||
" :sI
|
||||
call setline(2, "ONE One one")
|
||||
sI
|
||||
call assert_equal('ONE One two', getline(2))
|
||||
|
||||
" :sIn
|
||||
call setline(2, 'ONE One one')
|
||||
let t = execute('sIn')->split("\n")
|
||||
call assert_equal(['1 match on 1 line'], t)
|
||||
call assert_equal('ONE One one', getline(2))
|
||||
|
||||
" :sIp
|
||||
call setline(2, "\tONE One one")
|
||||
redir => output
|
||||
sIp
|
||||
redir END
|
||||
call assert_equal(' ONE One two', output->split("\n")[-1])
|
||||
call assert_equal("\tONE One two", getline(2))
|
||||
|
||||
" :sIl
|
||||
call setline(2, "\tONE onE one")
|
||||
redir => output
|
||||
sIl
|
||||
redir END
|
||||
call assert_equal("^IONE onE two$", output->split("\n")[-1])
|
||||
call assert_equal("\tONE onE two", getline(2))
|
||||
|
||||
" :sIr
|
||||
call setline(2, "ONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
sIr
|
||||
call assert_equal('ONE xyz onE', getline(2))
|
||||
|
||||
" :src
|
||||
call setline(2, "ONE one one")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
call feedkeys(":src\<CR>y", 'xt')
|
||||
call assert_equal('ONE xyz one', getline(2))
|
||||
|
||||
" :srg
|
||||
call setline(2, "one one one")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
srg
|
||||
call assert_equal('xyz xyz xyz', getline(2))
|
||||
|
||||
" :sri
|
||||
call setline(2, "ONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
sri
|
||||
call assert_equal('xyz one onE', getline(2))
|
||||
|
||||
" :srI
|
||||
call setline(2, "ONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
srI
|
||||
call assert_equal('ONE xyz onE', getline(2))
|
||||
|
||||
" :srn
|
||||
call setline(2, "ONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
let t = execute('srn')->split("\n")
|
||||
call assert_equal(['1 match on 1 line'], t)
|
||||
call assert_equal('ONE one onE', getline(2))
|
||||
|
||||
" :srp
|
||||
call setline(2, "\tONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
redir => output
|
||||
srp
|
||||
redir END
|
||||
call assert_equal(' ONE xyz onE', output->split("\n")[-1])
|
||||
call assert_equal("\tONE xyz onE", getline(2))
|
||||
|
||||
" :srl
|
||||
call setline(2, "\tONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
redir => output
|
||||
srl
|
||||
redir END
|
||||
call assert_equal("^IONE xyz onE$", output->split("\n")[-1])
|
||||
call assert_equal("\tONE xyz onE", getline(2))
|
||||
|
||||
" :sr
|
||||
call setline(2, "ONE one onE")
|
||||
call cursor(2, 1)
|
||||
s/abc/xyz/e
|
||||
let @/ = 'one'
|
||||
sr
|
||||
call assert_equal('ONE xyz onE', getline(2))
|
||||
|
||||
" :sce
|
||||
s/abc/xyz/e
|
||||
call assert_fails("sc", 'E486:')
|
||||
sce
|
||||
" :sge
|
||||
call assert_fails("sg", 'E486:')
|
||||
sge
|
||||
" :sie
|
||||
call assert_fails("si", 'E486:')
|
||||
sie
|
||||
" :sIe
|
||||
call assert_fails("sI", 'E486:')
|
||||
sIe
|
||||
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
" This should be done last to reveal a memory leak when vim_regsub_both() is
|
||||
" called to evaluate an expression but it is not used in a second call.
|
||||
func Test_z_substitute_expr_leak()
|
||||
func SubExpr()
|
||||
~n
|
||||
endfunc
|
||||
silent! s/\%')/\=SubExpr()
|
||||
delfunc SubExpr
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
Reference in New Issue
Block a user