diff options
-rw-r--r-- | src/nvim/ex_cmds.c | 10 | ||||
-rw-r--r-- | src/nvim/regexp.c | 15 | ||||
-rw-r--r-- | test/functional/ui/inccommand_spec.lua | 64 |
3 files changed, 84 insertions, 5 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 95390b1a70..66e9738f98 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3629,8 +3629,14 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle // We do it here once to avoid it to be replaced over and over again. // But don't do it when it starts with "\=", then it's an expression. assert(sub != NULL); + + bool sub_needs_free = false; if (!(sub[0] == '\\' && sub[1] == '=')) { + char_u *source = sub; sub = regtilde(sub, p_magic); + // When previewing, the new pattern allocated by regtilde() needs to be freed + // in this function because it will not be used or freed by regtilde() later. + sub_needs_free = preview && sub != source; } // Check for a match on each line. @@ -4425,6 +4431,10 @@ skip: kv_destroy(preview_lines.subresults); + if (sub_needs_free) { + xfree(sub); + } + return preview_buf; #undef ADJUST_SUB_FIRSTLNUM #undef PUSH_PREVIEW_LINES diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 45e580dbee..9bea54ad2c 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -6538,11 +6538,16 @@ char_u *regtilde(char_u *source, int magic) } } - xfree(reg_prev_sub); - if (newsub != source) /* newsub was allocated, just keep it */ - reg_prev_sub = newsub; - else /* no ~ found, need to save newsub */ - reg_prev_sub = vim_strsave(newsub); + // Only change reg_prev_sub when not previewing. + if (!(State & CMDPREVIEW)) { + xfree(reg_prev_sub); + if (newsub != source) { // newsub was allocated, just keep it + reg_prev_sub = newsub; + } else { // no ~ found, need to save newsub + reg_prev_sub = vim_strsave(newsub); + } + } + return newsub; } diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index b6e2f2311f..10700d9508 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -293,6 +293,70 @@ describe(":substitute, 'inccommand' preserves", function() end) end + for _, case in ipairs({'', 'split', 'nosplit'}) do + it('previous substitute string ~ (inccommand='..case..') #12109', function() + local screen = Screen.new(30,10) + common_setup(screen, case, default_text) + + feed(':%s/Inc/SUB<CR>') + expect([[ + SUB substitution on + two lines + ]]) + + feed(':%s/line/') + poke_eventloop() + feed('~') + poke_eventloop() + feed('<CR>') + expect([[ + SUB substitution on + two SUBs + ]]) + + feed(':%s/sti/') + poke_eventloop() + feed('~') + poke_eventloop() + feed('B') + poke_eventloop() + feed('<CR>') + expect([[ + SUB subSUBBtution on + two SUBs + ]]) + + feed(':%s/ion/NEW<CR>') + expect([[ + SUB subSUBBtutNEW on + two SUBs + ]]) + + feed(':%s/two/') + poke_eventloop() + feed('N') + poke_eventloop() + feed('~') + poke_eventloop() + feed('<CR>') + expect([[ + SUB subSUBBtutNEW on + NNEW SUBs + ]]) + + feed(':%s/bS/') + poke_eventloop() + feed('~') + poke_eventloop() + feed('W') + poke_eventloop() + feed('<CR>') + expect([[ + SUB suNNEWWUBBtutNEW on + NNEW SUBs + ]]) + end) + end end) describe(":substitute, 'inccommand' preserves undo", function() |