From 6d0f87a0bd9c683f21c20e29145f375ca77c2792 Mon Sep 17 00:00:00 2001 From: KillTheMule Date: Sat, 9 Sep 2017 11:38:19 +0200 Subject: [PATCH 1/5] 'inccommand': fix 'gdefault' lockup #7261 closes #7244 ref #7249 --- src/nvim/ex_cmds.c | 38 ++++++++++++++++++++------ test/functional/ui/inccommand_spec.lua | 27 ++++++++++++++++++ 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") + 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") + expect("A\nA") + eq({mode='n', blocking=false}, nvim("get_mode")) + end) +end) From 2736f0cb5631dec43064c77f504a7bc160aaeeb1 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 12 Sep 2017 23:45:31 +0200 Subject: [PATCH 2/5] ex_cmds.c:do_sub(): macroize duplicate code --- src/nvim/ex_cmds.c | 76 +++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 99bf07c3fb..918e7a0c91 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3672,31 +3672,38 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout) skip_match = true; } +#define ADJUST_SUB_FIRSTLNUM() \ + do { \ + /* 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; \ + } \ + } while (0) + + if (preview && !has_second_delim) { + ADJUST_SUB_FIRSTLNUM(); + goto skip; + } + // 3. Substitute the string. During 'inccommand' preview only do this if // there is a replace pattern. - 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 (!preview || has_second_delim) { if (subflags.do_count) { // prevent accidentally changing the buffer by a function save_ma = curbuf->b_p_ma; @@ -3750,30 +3757,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout) // is beyond the end of the line after the substitution. curwin->w_cursor.col = 0; - // 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; - } - } - // Remember next character to be copied. copycol = regmatch.endpos[0].col; - 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; - } + ADJUST_SUB_FIRSTLNUM(); // Now the trick is to replace CTRL-M chars with a real line // break. This would make it impossible to insert a CTRL-M in @@ -4030,6 +4017,7 @@ skip: kv_destroy(matched_lines); return preview_buf; +#undef ADJUST_SUB_FIRSTLNUM } // NOLINT(readability/fn_size) /* From 1cebf17fbe6943a2151a37e054b1475e049bad5f Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sat, 16 Sep 2017 03:54:49 -0500 Subject: [PATCH 3/5] build: show a hint for BSD make (#7275) BSD Make will give preference to a BSDmakefile in the same directory over a generic Makefile; this can be used to instruct BSD users to build neovim with GNU Make (gmake) instead. Otherwise, a flood of syntax errors stemming from the GNU-specific Makefile will be displayed - which most BSD users are accustomed to, but may confuse beginners nevertheless. --- BSDmakefile | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 BSDmakefile diff --git a/BSDmakefile b/BSDmakefile new file mode 100644 index 0000000000..93b7dc7f3d --- /dev/null +++ b/BSDmakefile @@ -0,0 +1,4 @@ +.DONE: + @echo "Please use GNU Make (gmake) to build neovim" +.DEFAULT: + @echo "Please use GNU Make (gmake) to build neovim" From 47019bb167e2b2d28c8648d39781c66e3ec02c00 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 16 Sep 2017 11:20:26 +0200 Subject: [PATCH 4/5] getchar.c: add TERM_FOCUS to MAP_HASH (#7271) vim-patch:8.0.1108 https://github.com/vim/vim/commit/69fbc9e1dab176f345719436cd89d854df0a2abd --- src/nvim/getchar.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index a22b716bb6..f5949333bd 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -92,17 +92,15 @@ static int typeahead_char = 0; /* typeahead char that's not flushed */ */ static int block_redo = FALSE; -/* - * Make a hash value for a mapping. - * "mode" is the lower 4 bits of the State for the mapping. - * "c1" is the first character of the "lhs". - * Returns a value between 0 and 255, index in maphash. - * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode. - */ +// Make a hash value for a mapping. +// "mode" is the lower 4 bits of the State for the mapping. +// "c1" is the first character of the "lhs". +// Returns a value between 0 and 255, index in maphash. +// Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode. #define MAP_HASH(mode, \ c1) (((mode) & \ (NORMAL + VISUAL + SELECTMODE + \ - OP_PENDING)) ? (c1) : ((c1) ^ 0x80)) + OP_PENDING + TERM_FOCUS)) ? (c1) : ((c1) ^ 0x80)) // Each mapping is put in one of the MAX_MAPHASH hash lists, // to speed up finding it. From 9d6bac3219a0cc1647b560b0d28b0a3fce9dc96a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 16 Sep 2017 12:17:59 +0200 Subject: [PATCH 5/5] test: more coverage for RPC + op-pending #3732 --- test/functional/api/vim_spec.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a4b643589a..b849304d45 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -364,6 +364,24 @@ describe('api', function() first line second line]]) end) + + it('does not complete ("interrupt") `d` #3732', function() + local screen = Screen.new(20, 4) + screen:attach() + command('set listchars=eol:$') + command('set list') + feed('iabckkk') + feed('d') + -- Make any RPC request (can be non-async: op-pending does not block). + nvim('get_current_buf') + screen:expect([[ + ^a$ | + b$ | + c$ | + | + ]]) + end) + it('does not complete ("interrupt") normal-mode map-pending', function() command("nnoremap dd :let g:foo='it worked...'") helpers.insert([[