mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	fix(ui): proper event ordering for nested cmdline_block events (#35344)
Problem:  Wrong event order for nested cmdline in a conditional cmdline_block.
Solution: Emit all but the first cmdline_block event immediately after
          getting the next command, before executing it.
			
			
This commit is contained in:
		| @@ -403,8 +403,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) | |||||||
|   bool msg_didout_before_start = false; |   bool msg_didout_before_start = false; | ||||||
|   int count = 0;                        // line number count |   int count = 0;                        // line number count | ||||||
|   bool did_inc = false;                 // incremented RedrawingDisabled |   bool did_inc = false;                 // incremented RedrawingDisabled | ||||||
|   int block_indent = -1;                // indent for ext_cmdline block event |   bool did_block = false;               // emitted cmdline_block event | ||||||
|   char *block_line = NULL;              // block_line for ext_cmdline block event |  | ||||||
|   int retval = OK; |   int retval = OK; | ||||||
|   cstack_T cstack = {                   // conditional stack |   cstack_T cstack = {                   // conditional stack | ||||||
|     .cs_idx = -1, |     .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(). |     // 2. If no line given, get an allocated line with fgetline(). | ||||||
|     if (next_cmdline == NULL) { |     if (next_cmdline == NULL) { | ||||||
|       int indent = cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2; |       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)) { |         if (ui_has(kUICmdline)) { | ||||||
|           char *line = block_line == last_cmdline ? "" : last_cmdline; |           // Emit cmdline_block event for loop/conditional block. | ||||||
|           ui_ext_cmdline_block_append((size_t)MAX(0, block_indent), line); |           ui_ext_cmdline_block_append(0, last_cmdline); | ||||||
|           block_line = last_cmdline; |           did_block = true; | ||||||
|           block_indent = indent; |         } | ||||||
|         } else if (count == 1) { |  | ||||||
|         // Need to set msg_didout for the first line after an ":if", |         // Need to set msg_didout for the first line after an ":if", | ||||||
|         // otherwise the ":if" will be overwritten. |         // otherwise the ":if" will be overwritten. | ||||||
|         msg_didout = true; |         msg_didout = true; | ||||||
|       } |       } | ||||||
|       } |  | ||||||
|       if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, indent, true)) == NULL) { |       if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, indent, true)) == NULL) { | ||||||
|         // Don't call wait_return() for aborted command line.  The NULL |         // Don't call wait_return() for aborted command line.  The NULL | ||||||
|         // returned for the end of a sourced file or executed function |         // 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; |       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. |       // Keep the first typed line.  Clear it when more lines are typed. | ||||||
|       if (flags & DOCMD_KEEPLINE) { |       if (flags & DOCMD_KEEPLINE) { | ||||||
|         xfree(repeat_cmdline); |         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(); |     ui_ext_cmdline_block_leave(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -673,6 +673,36 @@ local function test_cmdline(linegrid) | |||||||
|       cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, |       cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, | ||||||
|       cmdline_block = { { { 'if 1' } }, { { '  let x = 1' } }, { { '  ' } } }, |       cmdline_block = { { { 'if 1' } }, { { '  let x = 1' } }, { { '  ' } } }, | ||||||
|     }) |     }) | ||||||
|  |     feed('call input("foo:")<CR>') | ||||||
|  |     screen:expect({ | ||||||
|  |       grid = [[ | ||||||
|  |         ^                         | | ||||||
|  |         {1:~                        }|*3 | ||||||
|  |                                  | | ||||||
|  |       ]], | ||||||
|  |       cmdline = { { content = { { '' } }, pos = 0, prompt = 'foo:' } }, | ||||||
|  |       cmdline_block = { | ||||||
|  |         { { 'if 1' } }, | ||||||
|  |         { { '  let x = 1' } }, | ||||||
|  |         { { '  ' } }, | ||||||
|  |         { { '  call input("foo:")' } }, | ||||||
|  |       }, | ||||||
|  |     }) | ||||||
|  |     feed('bar<CR>') | ||||||
|  |     screen:expect({ | ||||||
|  |       grid = [[ | ||||||
|  |         ^                         | | ||||||
|  |         {1:~                        }|*3 | ||||||
|  |                                  | | ||||||
|  |       ]], | ||||||
|  |       cmdline = { { content = { { '' } }, firstc = ':', indent = 2, pos = 0 } }, | ||||||
|  |       cmdline_block = { | ||||||
|  |         { { 'if 1' } }, | ||||||
|  |         { { '  let x = 1' } }, | ||||||
|  |         { { '  ' } }, | ||||||
|  |         { { '  call input("foo:")' } }, | ||||||
|  |       }, | ||||||
|  |     }) | ||||||
|     feed('endif') |     feed('endif') | ||||||
|     screen:expect({ |     screen:expect({ | ||||||
|       grid = [[ |       grid = [[ | ||||||
| @@ -681,7 +711,12 @@ local function test_cmdline(linegrid) | |||||||
|                                  | |                                  | | ||||||
|       ]], |       ]], | ||||||
|       cmdline = { { content = { { 'endif' } }, firstc = ':', indent = 2, pos = 5 } }, |       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('<CR>') |     feed('<CR>') | ||||||
|     screen:expect([[ |     screen:expect([[ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 luukvbaal
					luukvbaal