aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKillTheMule <KillTheMule@users.noreply.github.com>2017-09-09 11:38:19 +0200
committerJustin M. Keyes <justinkz@gmail.com>2017-09-12 22:44:11 +0200
commit6d0f87a0bd9c683f21c20e29145f375ca77c2792 (patch)
tree93afedbfa49c9b2553a644a6a5582ef962199bd5
parentd2cbc311855114b7736919a344a82e303d4a8164 (diff)
downloadrneovim-6d0f87a0bd9c683f21c20e29145f375ca77c2792.tar.gz
rneovim-6d0f87a0bd9c683f21c20e29145f375ca77c2792.tar.bz2
rneovim-6d0f87a0bd9c683f21c20e29145f375ca77c2792.zip
'inccommand': fix 'gdefault' lockup #7261
closes #7244 ref #7249
-rw-r--r--src/nvim/ex_cmds.c38
-rw-r--r--test/functional/ui/inccommand_spec.lua27
2 files changed, 57 insertions, 8 deletions
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 4b3e02e5fd..99bf07c3fb 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3665,9 +3665,38 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
* use "\=col("."). */
curwin->w_cursor.col = regmatch.startpos[0].col;
+ // When the match included the "$" of the last line it may
+ // go beyond the last line of the buffer.
+ if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) {
+ nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
+ skip_match = true;
+ }
+
// 3. Substitute the string. During 'inccommand' preview only do this if
// there is a replace pattern.
- if (!preview || has_second_delim) {
+ if (preview && !has_second_delim) {
+ // For a multi-line match, make a copy of the last matched
+ // line and continue in that one.
+ if (nmatch > 1) {
+ sub_firstlnum += nmatch - 1;
+ xfree(sub_firstline);
+ sub_firstline = vim_strsave(ml_get(sub_firstlnum));
+ // When going beyond the last line, stop substituting.
+ if (sub_firstlnum <= line2) {
+ do_again = true;
+ } else {
+ subflags.do_all = false;
+ }
+ }
+
+ if (skip_match) {
+ // Already hit end of the buffer, sub_firstlnum is one
+ // less than what it ought to be.
+ xfree(sub_firstline);
+ sub_firstline = vim_strsave((char_u *)"");
+ copycol = 0;
+ }
+ } else if (!preview || has_second_delim) {
if (subflags.do_count) {
// prevent accidentally changing the buffer by a function
save_ma = curbuf->b_p_ma;
@@ -3691,13 +3720,6 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout)
goto skip;
}
- // When the match included the "$" of the last line it may
- // go beyond the last line of the buffer.
- if (nmatch > curbuf->b_ml.ml_line_count - sub_firstlnum + 1) {
- nmatch = curbuf->b_ml.ml_line_count - sub_firstlnum + 1;
- skip_match = true;
- }
-
// Need room for:
// - result so far in new_start (not for first sub in line)
// - original text up to match
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index e83bd72ad3..c8fa2888d1 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -14,6 +14,7 @@ local neq = helpers.neq
local ok = helpers.ok
local source = helpers.source
local wait = helpers.wait
+local nvim = helpers.nvim
local default_text = [[
Inc substitution on
@@ -1647,3 +1648,29 @@ describe("'inccommand' split windows", function()
end)
end)
+
+describe("'inccommand' with 'gdefault'", function()
+ before_each(function()
+ clear()
+ end)
+
+ it("does not lock up #7244", function()
+ common_setup(nil, "nosplit", "{")
+ command("set gdefault")
+ feed(":s/{\\n")
+ eq({mode='c', blocking=false}, nvim("get_mode"))
+ feed("/A<Enter>")
+ expect("A")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+
+ it("with multiline text and range, does not lock up #7244", function()
+ common_setup(nil, "nosplit", "{\n\n{")
+ command("set gdefault")
+ feed(":%s/{\\n")
+ eq({mode='c', blocking=false}, nvim("get_mode"))
+ feed("/A<Enter>")
+ expect("A\nA")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+end)