diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 707b43da87..9e6074aaca 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -403,8 +403,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) bool msg_didout_before_start = false; int count = 0; // line number count bool did_inc = false; // incremented RedrawingDisabled - int block_indent = -1; // indent for ext_cmdline block event - char *block_line = NULL; // block_line for ext_cmdline block event + bool did_block = false; // emitted cmdline_block event int retval = OK; cstack_T cstack = { // conditional stack .cs_idx = -1, @@ -573,18 +572,18 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // 2. If no line given, get an allocated line with fgetline(). if (next_cmdline == NULL) { int indent = cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2; - if (count >= 1 && getline_equal(fgetline, cookie, getexline)) { + + if (count == 1 && getline_equal(fgetline, cookie, getexline)) { if (ui_has(kUICmdline)) { - char *line = block_line == last_cmdline ? "" : last_cmdline; - ui_ext_cmdline_block_append((size_t)MAX(0, block_indent), line); - block_line = last_cmdline; - block_indent = indent; - } else if (count == 1) { - // Need to set msg_didout for the first line after an ":if", - // otherwise the ":if" will be overwritten. - msg_didout = true; + // Emit cmdline_block event for loop/conditional block. + ui_ext_cmdline_block_append(0, last_cmdline); + did_block = true; } + // Need to set msg_didout for the first line after an ":if", + // otherwise the ":if" will be overwritten. + msg_didout = true; } + if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, indent, true)) == NULL) { // Don't call wait_return() for aborted command line. The NULL // returned for the end of a sourced file or executed function @@ -597,6 +596,12 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } used_getline = true; + // Emit all but the first cmdline_block event immediately; waiting until after + // command execution would mess up event ordering with nested command lines. + if (ui_has(kUICmdline) && count > 0 && getline_equal(fgetline, cookie, getexline)) { + ui_ext_cmdline_block_append((size_t)indent, next_cmdline); + } + // Keep the first typed line. Clear it when more lines are typed. if (flags & DOCMD_KEEPLINE) { xfree(repeat_cmdline); @@ -941,7 +946,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } } - if (block_indent >= 0) { + if (did_block) { ui_ext_cmdline_block_leave(); } diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 04c4d45271..caa930f89f 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -673,6 +673,36 @@ local function test_cmdline(linegrid) cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, cmdline_block = { { { 'if 1' } }, { { ' let x = 1' } }, { { ' ' } } }, }) + feed('call input("foo:")') + screen:expect({ + grid = [[ + ^ | + {1:~ }|*3 + | + ]], + cmdline = { { content = { { '' } }, pos = 0, prompt = 'foo:' } }, + cmdline_block = { + { { 'if 1' } }, + { { ' let x = 1' } }, + { { ' ' } }, + { { ' call input("foo:")' } }, + }, + }) + feed('bar') + screen:expect({ + grid = [[ + ^ | + {1:~ }|*3 + | + ]], + cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, + cmdline_block = { + { { 'if 1' } }, + { { ' let x = 1' } }, + { { ' ' } }, + { { ' call input("foo:")' } }, + }, + }) feed('endif') screen:expect({ grid = [[ @@ -681,7 +711,12 @@ local function test_cmdline(linegrid) | ]], cmdline = { { content = { { 'endif' } }, firstc = ':', indent = 2, pos = 5 } }, - cmdline_block = { { { 'if 1' } }, { { ' let x = 1' } }, { { ' ' } } }, + cmdline_block = { + { { 'if 1' } }, + { { ' let x = 1' } }, + { { ' ' } }, + { { ' call input("foo:")' } }, + }, }) feed('') screen:expect([[