mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	Merge pull request #23527 from zeertzjq/vim-8.2.1978
vim-patch:8.2.{1978,2062,3887},9.0.{1516,1521}
			
			
This commit is contained in:
		@@ -290,7 +290,7 @@ Therefore the following is blocked for <expr> mappings:
 | 
				
			|||||||
- Moving the cursor is allowed, but it is restored afterwards.
 | 
					- Moving the cursor is allowed, but it is restored afterwards.
 | 
				
			||||||
- If the cmdline is changed, the old text and cursor position are restored.
 | 
					- If the cmdline is changed, the old text and cursor position are restored.
 | 
				
			||||||
If you want the mapping to do any of these let the returned characters do
 | 
					If you want the mapping to do any of these let the returned characters do
 | 
				
			||||||
that. (Or use a |<Cmd>| mapping instead.)
 | 
					that, or use a |<Cmd>| mapping instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can use getchar(), it consumes typeahead if there is any. E.g., if you
 | 
					You can use getchar(), it consumes typeahead if there is any. E.g., if you
 | 
				
			||||||
have these mappings: >
 | 
					have these mappings: >
 | 
				
			||||||
@@ -324,19 +324,21 @@ be seen as a special key.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
						*<Cmd>* *:map-cmd*
 | 
											*<Cmd>* *:map-cmd*
 | 
				
			||||||
The <Cmd> pseudokey begins a "command mapping", which executes the command
 | 
					The <Cmd> pseudokey begins a "command mapping", which executes the command
 | 
				
			||||||
directly (without changing modes).  Where you might use ":...<CR>" in the
 | 
					directly without changing modes.  Where you might use ":...<CR>" in the
 | 
				
			||||||
{rhs} of a mapping, you can instead use "<Cmd>...<CR>".
 | 
					{rhs} of a mapping, you can instead use "<Cmd>...<CR>".
 | 
				
			||||||
Example: >
 | 
					Example: >
 | 
				
			||||||
	noremap x <Cmd>echo mode(1)<cr>
 | 
						noremap x <Cmd>echo mode(1)<CR>
 | 
				
			||||||
<
 | 
					<
 | 
				
			||||||
This is more flexible than `:<C-U>` in visual and operator-pending mode, or
 | 
					This is more flexible than `:<C-U>` in Visual and Operator-pending mode, or
 | 
				
			||||||
`<C-O>:` in insert-mode, because the commands are executed directly in the
 | 
					`<C-O>:` in Insert mode, because the commands are executed directly in the
 | 
				
			||||||
current mode (instead of always going to normal-mode).  Visual-mode is
 | 
					current mode, instead of always going to Normal mode.  Visual mode is
 | 
				
			||||||
preserved, so tricks with |gv| are not needed.  Commands can be invoked
 | 
					preserved, so tricks with |gv| are not needed.  Commands can be invoked
 | 
				
			||||||
directly in cmdline-mode (which would otherwise require timer hacks).
 | 
					directly in Command-line mode (which would otherwise require timer hacks).
 | 
				
			||||||
 | 
					Example of using <Cmd> halfway Insert mode: >
 | 
				
			||||||
 | 
						nnoremap <F3> aText <Cmd>echo mode(1)<CR> Added<Esc>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Unlike <expr> mappings, there are no special restrictions on the <Cmd>
 | 
					Unlike <expr> mappings, there are no special restrictions on the <Cmd>
 | 
				
			||||||
command: it is executed as if an (unrestricted) |autocommand| was invoked
 | 
					command: it is executed as if an (unrestricted) |autocmd| was invoked
 | 
				
			||||||
or an async event event was processed.
 | 
					or an async event event was processed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note:
 | 
					Note:
 | 
				
			||||||
@@ -350,7 +352,7 @@ Note:
 | 
				
			|||||||
- In Visual mode  you can use `line('v')` and `col('v')` to get one end of the
 | 
					- In Visual mode  you can use `line('v')` and `col('v')` to get one end of the
 | 
				
			||||||
  Visual area, the cursor is at the other end.
 | 
					  Visual area, the cursor is at the other end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							*E5520*
 | 
												*E1255* *E1136*
 | 
				
			||||||
<Cmd> commands must terminate, that is, they must be followed by <CR> in the
 | 
					<Cmd> commands must terminate, that is, they must be followed by <CR> in the
 | 
				
			||||||
{rhs} of the mapping definition.  |Command-line| mode is never entered.
 | 
					{rhs} of the mapping definition.  |Command-line| mode is never entered.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -876,7 +876,7 @@ static int insert_handle_key(InsertState *s)
 | 
				
			|||||||
    state_handle_k_event();
 | 
					    state_handle_k_event();
 | 
				
			||||||
    goto check_pum;
 | 
					    goto check_pum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  case K_COMMAND:       // some command
 | 
					  case K_COMMAND:     // <Cmd>command<CR>
 | 
				
			||||||
    do_cmdline(NULL, getcmdkeycmd, NULL, 0);
 | 
					    do_cmdline(NULL, getcmdkeycmd, NULL, 0);
 | 
				
			||||||
    goto check_pum;
 | 
					    goto check_pum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,8 +92,8 @@ static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int typeahead_char = 0;          // typeahead char that's not flushed
 | 
					static int typeahead_char = 0;          // typeahead char that's not flushed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// when block_redo is true redo buffer will not be changed
 | 
					/// When block_redo is true the redo buffer will not be changed.
 | 
				
			||||||
// used by edit() to repeat insertions and 'V' command for redoing
 | 
					/// Used by edit() to repeat insertions.
 | 
				
			||||||
static int block_redo = false;
 | 
					static int block_redo = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int KeyNoremap = 0;                  // remapping flags
 | 
					static int KeyNoremap = 0;                  // remapping flags
 | 
				
			||||||
@@ -134,6 +134,10 @@ static size_t last_recorded_len = 0;      // number of last recorded chars
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char e_recursive_mapping[] = N_("E223: Recursive mapping");
 | 
					static const char e_recursive_mapping[] = N_("E223: Recursive mapping");
 | 
				
			||||||
 | 
					static const char e_cmd_mapping_must_end_with_cr[]
 | 
				
			||||||
 | 
					  = N_("E1255: <Cmd> mapping must end with <CR>");
 | 
				
			||||||
 | 
					static const char e_cmd_mapping_must_end_with_cr_before_second_cmd[]
 | 
				
			||||||
 | 
					  = N_("E1136: <Cmd> mapping must end with <CR> before second <Cmd>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Free and clear a buffer.
 | 
					// Free and clear a buffer.
 | 
				
			||||||
void free_buff(buffheader_T *buf)
 | 
					void free_buff(buffheader_T *buf)
 | 
				
			||||||
@@ -550,6 +554,25 @@ void AppendToRedobuffLit(const char *str, int len)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Append "s" to the redo buffer, leaving 3-byte special key codes unmodified
 | 
				
			||||||
 | 
					/// and escaping other K_SPECIAL bytes.
 | 
				
			||||||
 | 
					void AppendToRedobuffSpec(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (block_redo) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (*s != NUL) {
 | 
				
			||||||
 | 
					    if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
 | 
				
			||||||
 | 
					      // Insert special key literally.
 | 
				
			||||||
 | 
					      add_buff(&redobuff, s, 3L);
 | 
				
			||||||
 | 
					      s += 3;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      add_char_buff(&redobuff, mb_cptr2char_adv(&s));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Append a character to the redo buffer.
 | 
					/// Append a character to the redo buffer.
 | 
				
			||||||
/// Translates special keys, NUL, K_SPECIAL and multibyte characters.
 | 
					/// Translates special keys, NUL, K_SPECIAL and multibyte characters.
 | 
				
			||||||
void AppendCharToRedobuff(int c)
 | 
					void AppendCharToRedobuff(int c)
 | 
				
			||||||
@@ -2884,7 +2907,8 @@ int fix_input_buffer(uint8_t *buf, int len)
 | 
				
			|||||||
  return len;
 | 
					  return len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Get command argument for <Cmd> key
 | 
					/// Function passed to do_cmdline() to get the command after a <Cmd> key from
 | 
				
			||||||
 | 
					/// typeahead.
 | 
				
			||||||
char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
 | 
					char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  garray_T line_ga;
 | 
					  garray_T line_ga;
 | 
				
			||||||
@@ -2894,6 +2918,7 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  ga_init(&line_ga, 1, 32);
 | 
					  ga_init(&line_ga, 1, 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // no mapping for these characters
 | 
				
			||||||
  no_mapping++;
 | 
					  no_mapping++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  got_int = false;
 | 
					  got_int = false;
 | 
				
			||||||
@@ -2903,16 +2928,17 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
 | 
				
			|||||||
    if (vgetorpeek(false) == NUL) {
 | 
					    if (vgetorpeek(false) == NUL) {
 | 
				
			||||||
      // incomplete <Cmd> is an error, because there is not much the user
 | 
					      // incomplete <Cmd> is an error, because there is not much the user
 | 
				
			||||||
      // could do in this state.
 | 
					      // could do in this state.
 | 
				
			||||||
      emsg(e_cmdmap_err);
 | 
					      emsg(_(e_cmd_mapping_must_end_with_cr));
 | 
				
			||||||
      aborted = true;
 | 
					      aborted = true;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get one character at a time.
 | 
					    // Get one character at a time.
 | 
				
			||||||
    c1 = vgetorpeek(true);
 | 
					    c1 = vgetorpeek(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get two extra bytes for special keys
 | 
					    // Get two extra bytes for special keys
 | 
				
			||||||
    if (c1 == K_SPECIAL) {
 | 
					    if (c1 == K_SPECIAL) {
 | 
				
			||||||
      c1 = vgetorpeek(true);          // no mapping for these chars
 | 
					      c1 = vgetorpeek(true);
 | 
				
			||||||
      c2 = vgetorpeek(true);
 | 
					      c2 = vgetorpeek(true);
 | 
				
			||||||
      if (c1 == KS_MODIFIER) {
 | 
					      if (c1 == KS_MODIFIER) {
 | 
				
			||||||
        cmod = c2;
 | 
					        cmod = c2;
 | 
				
			||||||
@@ -2928,8 +2954,8 @@ char *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
 | 
				
			|||||||
    } else if (c1 == ESC) {
 | 
					    } else if (c1 == ESC) {
 | 
				
			||||||
      aborted = true;
 | 
					      aborted = true;
 | 
				
			||||||
    } else if (c1 == K_COMMAND) {
 | 
					    } else if (c1 == K_COMMAND) {
 | 
				
			||||||
      // special case to give nicer error message
 | 
					      // give a nicer error message for this special case
 | 
				
			||||||
      emsg(e_cmdmap_repeated);
 | 
					      emsg(_(e_cmd_mapping_must_end_with_cr_before_second_cmd));
 | 
				
			||||||
      aborted = true;
 | 
					      aborted = true;
 | 
				
			||||||
    } else if (c1 == K_SNR) {
 | 
					    } else if (c1 == K_SNR) {
 | 
				
			||||||
      ga_concat(&line_ga, "<SNR>");
 | 
					      ga_concat(&line_ga, "<SNR>");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1003,10 +1003,6 @@ EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit
 | 
				
			|||||||
EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
 | 
					EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d"));
 | 
				
			||||||
EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
 | 
					EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTERN const char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>"));
 | 
					 | 
				
			||||||
EXTERN const char e_cmdmap_repeated[]
 | 
					 | 
				
			||||||
INIT(= N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
 | 
					EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
 | 
					EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5858,7 +5858,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
 | 
				
			|||||||
        if (repeat_cmdline == NULL) {
 | 
					        if (repeat_cmdline == NULL) {
 | 
				
			||||||
          ResetRedobuff();
 | 
					          ResetRedobuff();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          AppendToRedobuffLit(repeat_cmdline, -1);
 | 
					          if (cap->cmdchar == ':') {
 | 
				
			||||||
 | 
					            AppendToRedobuffLit(repeat_cmdline, -1);
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            AppendToRedobuffSpec(repeat_cmdline);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          AppendToRedobuff(NL_STR);
 | 
					          AppendToRedobuff(NL_STR);
 | 
				
			||||||
          XFREE_CLEAR(repeat_cmdline);
 | 
					          XFREE_CLEAR(repeat_cmdline);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,7 +90,7 @@ describe('mappings with <Cmd>', function()
 | 
				
			|||||||
      {1:~                                                                }|
 | 
					      {1:~                                                                }|
 | 
				
			||||||
      {1:~                                                                }|
 | 
					      {1:~                                                                }|
 | 
				
			||||||
      {1:~                                                                }|
 | 
					      {1:~                                                                }|
 | 
				
			||||||
      {2:E5521: <Cmd> mapping must end with <CR> before second <Cmd>}      |
 | 
					      {2:E1136: <Cmd> mapping must end with <CR> before second <Cmd>}      |
 | 
				
			||||||
    ]])
 | 
					    ]])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    command('noremap <F3> <Cmd>let x = 3')
 | 
					    command('noremap <F3> <Cmd>let x = 3')
 | 
				
			||||||
@@ -103,7 +103,7 @@ describe('mappings with <Cmd>', function()
 | 
				
			|||||||
      {1:~                                                                }|
 | 
					      {1:~                                                                }|
 | 
				
			||||||
      {1:~                                                                }|
 | 
					      {1:~                                                                }|
 | 
				
			||||||
      {1:~                                                                }|
 | 
					      {1:~                                                                }|
 | 
				
			||||||
      {2:E5520: <Cmd> mapping must end with <CR>}                          |
 | 
					      {2:E1255: <Cmd> mapping must end with <CR>}                          |
 | 
				
			||||||
    ]])
 | 
					    ]])
 | 
				
			||||||
    eq(0, eval('x'))
 | 
					    eq(0, eval('x'))
 | 
				
			||||||
  end)
 | 
					  end)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
source shared.vim
 | 
					source shared.vim
 | 
				
			||||||
source check.vim
 | 
					source check.vim
 | 
				
			||||||
source screendump.vim
 | 
					source screendump.vim
 | 
				
			||||||
 | 
					source term_util.vim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_abbreviation()
 | 
					func Test_abbreviation()
 | 
				
			||||||
  " abbreviation with 0x80 should work
 | 
					  " abbreviation with 0x80 should work
 | 
				
			||||||
@@ -968,6 +969,469 @@ func Test_map_cpo_special_keycode()
 | 
				
			|||||||
  mapclear!
 | 
					  mapclear!
 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> key in maps to execute commands
 | 
				
			||||||
 | 
					func Test_map_cmdkey()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " Error cases
 | 
				
			||||||
 | 
					  let x = 0
 | 
				
			||||||
 | 
					  noremap <F3> <Cmd><Cmd>let x = 1<CR>
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("\<F3>", "xt")', 'E1136:')
 | 
				
			||||||
 | 
					  call assert_equal(0, x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  noremap <F3> <Cmd>let x = 3
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("\<F3>", "xt!")', 'E1255:')
 | 
				
			||||||
 | 
					  call assert_equal(0, x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " works in various modes and sees the correct mode()
 | 
				
			||||||
 | 
					  noremap <F3> <Cmd>let m = mode(1)<CR>
 | 
				
			||||||
 | 
					  noremap! <F3> <Cmd>let m = mode(1)<CR>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " normal mode
 | 
				
			||||||
 | 
					  call feedkeys("\<F3>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('n', m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " visual mode
 | 
				
			||||||
 | 
					  call feedkeys("v\<F3>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('v', m)
 | 
				
			||||||
 | 
					  " shouldn't leave the visual mode
 | 
				
			||||||
 | 
					  call assert_equal('v', mode(1))
 | 
				
			||||||
 | 
					  call feedkeys("\<Esc>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('n', mode(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " visual mapping in select mode
 | 
				
			||||||
 | 
					  call feedkeys("gh\<F3>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('v', m)
 | 
				
			||||||
 | 
					  " shouldn't leave select mode
 | 
				
			||||||
 | 
					  call assert_equal('s', mode(1))
 | 
				
			||||||
 | 
					  call feedkeys("\<Esc>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('n', mode(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " select mode mapping
 | 
				
			||||||
 | 
					  snoremap <F3> <Cmd>let m = mode(1)<cr>
 | 
				
			||||||
 | 
					  call feedkeys("gh\<F3>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('s', m)
 | 
				
			||||||
 | 
					  " shouldn't leave select mode
 | 
				
			||||||
 | 
					  call assert_equal('s', mode(1))
 | 
				
			||||||
 | 
					  call feedkeys("\<Esc>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('n', mode(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " operator-pending mode
 | 
				
			||||||
 | 
					  call feedkeys("d\<F3>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('no', m)
 | 
				
			||||||
 | 
					  " leaves the operator-pending mode
 | 
				
			||||||
 | 
					  call assert_equal('n', mode(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " insert mode
 | 
				
			||||||
 | 
					  call feedkeys("i\<F3>abc", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('i', m)
 | 
				
			||||||
 | 
					  call assert_equal('abc', getline('.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " replace mode
 | 
				
			||||||
 | 
					  call feedkeys("0R\<F3>two", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('R', m)
 | 
				
			||||||
 | 
					  call assert_equal('two', getline('.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " virtual replace mode
 | 
				
			||||||
 | 
					  call setline('.', "one\ttwo")
 | 
				
			||||||
 | 
					  call feedkeys("4|gR\<F3>xxx", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('Rv', m)
 | 
				
			||||||
 | 
					  call assert_equal("onexxx\ttwo", getline('.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " cmdline mode
 | 
				
			||||||
 | 
					  call feedkeys(":\<F3>\"xxx\<CR>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('c', m)
 | 
				
			||||||
 | 
					  call assert_equal('"xxx', @:)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " terminal mode
 | 
				
			||||||
 | 
					  if CanRunVimInTerminal()
 | 
				
			||||||
 | 
					    tnoremap <F3> <Cmd>let m = mode(1)<CR>
 | 
				
			||||||
 | 
					    let buf = Run_shell_in_terminal({})
 | 
				
			||||||
 | 
					    call feedkeys("\<F3>", 'xt')
 | 
				
			||||||
 | 
					    call assert_equal('t', m)
 | 
				
			||||||
 | 
					    call assert_equal('t', mode(1))
 | 
				
			||||||
 | 
					    call StopShellInTerminal(buf)
 | 
				
			||||||
 | 
					    call TermWait(buf)
 | 
				
			||||||
 | 
					    close!
 | 
				
			||||||
 | 
					    tunmap <F3>
 | 
				
			||||||
 | 
					  endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " invoke cmdline mode recursively
 | 
				
			||||||
 | 
					  noremap! <F2> <Cmd>norm! :foo<CR>
 | 
				
			||||||
 | 
					  %d
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  call feedkeys(":bar\<F2>x\<C-B>\"\r", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('"barx', @:)
 | 
				
			||||||
 | 
					  unmap! <F2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " test for calling a <SID> function
 | 
				
			||||||
 | 
					  let lines =<< trim END
 | 
				
			||||||
 | 
					    map <F2> <Cmd>call <SID>do_it()<CR>
 | 
				
			||||||
 | 
					    func s:do_it()
 | 
				
			||||||
 | 
					      let g:x = 32
 | 
				
			||||||
 | 
					    endfunc
 | 
				
			||||||
 | 
					  END
 | 
				
			||||||
 | 
					  call writefile(lines, 'Xscript')
 | 
				
			||||||
 | 
					  source Xscript
 | 
				
			||||||
 | 
					  call feedkeys("\<F2>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(32, g:x)
 | 
				
			||||||
 | 
					  call delete('Xscript')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unmap <F3>
 | 
				
			||||||
 | 
					  unmap! <F3>
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" text object enters visual mode
 | 
				
			||||||
 | 
					func TextObj()
 | 
				
			||||||
 | 
					  if mode() !=# "v"
 | 
				
			||||||
 | 
					    normal! v
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					  call cursor(1, 3)
 | 
				
			||||||
 | 
					  normal! o
 | 
				
			||||||
 | 
					  call cursor(2, 4)
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func s:cmdmap(lhs, rhs)
 | 
				
			||||||
 | 
					  exe 'noremap ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
 | 
				
			||||||
 | 
					  exe 'noremap! ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func s:cmdunmap(lhs)
 | 
				
			||||||
 | 
					  exe 'unmap ' .. a:lhs
 | 
				
			||||||
 | 
					  exe 'unmap! ' .. a:lhs
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Map various <Fx> keys used by the <Cmd> key tests
 | 
				
			||||||
 | 
					func s:setupMaps()
 | 
				
			||||||
 | 
					  call s:cmdmap('<F3>', 'let m = mode(1)')
 | 
				
			||||||
 | 
					  call s:cmdmap('<F4>', 'normal! ww')
 | 
				
			||||||
 | 
					  call s:cmdmap('<F5>', 'normal! "ay')
 | 
				
			||||||
 | 
					  call s:cmdmap('<F6>', 'throw "very error"')
 | 
				
			||||||
 | 
					  call s:cmdmap('<F7>', 'call TextObj()')
 | 
				
			||||||
 | 
					  call s:cmdmap('<F8>', 'startinsert')
 | 
				
			||||||
 | 
					  call s:cmdmap('<F9>', 'stopinsert')
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Remove the mappings setup by setupMaps()
 | 
				
			||||||
 | 
					func s:cleanupMaps()
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F3>')
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F4>')
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F5>')
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F6>')
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F7>')
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F8>')
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F9>')
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in normal mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_normal_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " check v:count and v:register works
 | 
				
			||||||
 | 
					  call s:cmdmap('<F2>', 'let s = [mode(1), v:count, v:register]')
 | 
				
			||||||
 | 
					  call feedkeys("\<F2>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['n', 0, '"'], s)
 | 
				
			||||||
 | 
					  call feedkeys("7\<F2>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['n', 7, '"'], s)
 | 
				
			||||||
 | 
					  call feedkeys("\"e\<F2>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['n', 0, 'e'], s)
 | 
				
			||||||
 | 
					  call feedkeys("5\"k\<F2>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['n', 5, 'k'], s)
 | 
				
			||||||
 | 
					  call s:cmdunmap('<F2>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  call feedkeys("\<F7>y", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal("me short lines\nof t", @")
 | 
				
			||||||
 | 
					  call assert_equal('v', getregtype('"'))
 | 
				
			||||||
 | 
					  call assert_equal([0, 1, 3, 0], getpos("'<"))
 | 
				
			||||||
 | 
					  call assert_equal([0, 2, 4, 0], getpos("'>"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " startinsert
 | 
				
			||||||
 | 
					  %d
 | 
				
			||||||
 | 
					  call feedkeys("\<F8>abc", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('abc', getline(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " feedkeys are not executed immediately
 | 
				
			||||||
 | 
					  noremap ,a <Cmd>call feedkeys("aalpha") \| let g:a = getline(2)<CR>
 | 
				
			||||||
 | 
					  %d
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  call cursor(2, 3)
 | 
				
			||||||
 | 
					  call feedkeys(",a\<F3>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('of test text', g:a)
 | 
				
			||||||
 | 
					  call assert_equal('n', m)
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'of alphatest text'], getline(1, '$'))
 | 
				
			||||||
 | 
					  nunmap ,a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " feedkeys(..., 'x') is executed immediately, but insert mode is aborted
 | 
				
			||||||
 | 
					  noremap ,b <Cmd>call feedkeys("abeta", 'x') \| let g:b = getline(2)<CR>
 | 
				
			||||||
 | 
					  call feedkeys(",b\<F3>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('n', m)
 | 
				
			||||||
 | 
					  call assert_equal('of alphabetatest text', g:b)
 | 
				
			||||||
 | 
					  nunmap ,b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping with the :normal command
 | 
				
			||||||
 | 
					func Test_map_cmdkey_normal_cmd()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  noremap ,x <Cmd>call append(1, "xx") \| call append(1, "aa")<CR>
 | 
				
			||||||
 | 
					  noremap ,f <Cmd>nosuchcommand<CR>
 | 
				
			||||||
 | 
					  noremap ,e <Cmd>throw "very error" \| call append(1, "yy")<CR>
 | 
				
			||||||
 | 
					  noremap ,m <Cmd>echoerr "The message." \| call append(1, "zz")<CR>
 | 
				
			||||||
 | 
					  noremap ,w <Cmd>for i in range(5) \| if i==1 \| echoerr "Err" \| endif \| call append(1, i) \| endfor<CR>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  exe "norm ,x\r"
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call assert_fails('norm ,f', 'E492:')
 | 
				
			||||||
 | 
					  call assert_fails('norm ,e', 'very error')
 | 
				
			||||||
 | 
					  call assert_fails('norm ,m', 'The message.')
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  %d
 | 
				
			||||||
 | 
					  let caught_err = 0
 | 
				
			||||||
 | 
					  try
 | 
				
			||||||
 | 
					    exe "normal ,w"
 | 
				
			||||||
 | 
					  catch /Vim(echoerr):Err/
 | 
				
			||||||
 | 
					    let caught_err = 1
 | 
				
			||||||
 | 
					  endtry
 | 
				
			||||||
 | 
					  call assert_equal(1, caught_err)
 | 
				
			||||||
 | 
					  call assert_equal(['', '0'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  %d
 | 
				
			||||||
 | 
					  call assert_fails('normal ,w', 'Err')
 | 
				
			||||||
 | 
					  call assert_equal(['', '4', '3', '2' ,'1', '0'], getline(1, '$'))
 | 
				
			||||||
 | 
					  call assert_equal(1, line('.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  nunmap ,x
 | 
				
			||||||
 | 
					  nunmap ,f
 | 
				
			||||||
 | 
					  nunmap ,e
 | 
				
			||||||
 | 
					  nunmap ,m
 | 
				
			||||||
 | 
					  nunmap ,w
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in visual mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_visual_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  set showmode
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  call feedkeys("v\<F4>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal(['v', 1, 12], [mode(1), col('v'), col('.')])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " can invoke an opeartor, ending the visual mode
 | 
				
			||||||
 | 
					  let @a = ''
 | 
				
			||||||
 | 
					  call feedkeys("\<F5>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('n', mode(1))
 | 
				
			||||||
 | 
					  call assert_equal('some short l', @a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " error doesn't interrupt visual mode
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("ggvw\<F6>", "xt!")', 'E605:')
 | 
				
			||||||
 | 
					  call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
 | 
				
			||||||
 | 
					  call feedkeys("\<F7>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " startinsert gives "-- (insert) VISUAL --" mode
 | 
				
			||||||
 | 
					  call feedkeys("\<F8>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
 | 
				
			||||||
 | 
					  redraw!
 | 
				
			||||||
 | 
					  call assert_match('^-- (insert) VISUAL --', Screenline(&lines))
 | 
				
			||||||
 | 
					  call feedkeys("\<Esc>new ", 'x')
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'of new test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  set showmode&
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in select mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_select_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  set showmode
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  snoremap <F1> <cmd>throw "very error"<CR>
 | 
				
			||||||
 | 
					  snoremap <F2> <cmd>normal! <c-g>"by<CR>
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call feedkeys("gh\<F4>", "xt!")
 | 
				
			||||||
 | 
					  call assert_equal(['s', 1, 12], [mode(1), col('v'), col('.')])
 | 
				
			||||||
 | 
					  redraw!
 | 
				
			||||||
 | 
					  call assert_match('^-- SELECT --', Screenline(&lines))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " visual mapping in select mode restarts select mode after operator
 | 
				
			||||||
 | 
					  let @a = ''
 | 
				
			||||||
 | 
					  call feedkeys("\<F5>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('s', mode(1))
 | 
				
			||||||
 | 
					  call assert_equal('some short l', @a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " select mode mapping works, and does not restart select mode
 | 
				
			||||||
 | 
					  let @b = ''
 | 
				
			||||||
 | 
					  call feedkeys("\<F2>", 'xt!')
 | 
				
			||||||
 | 
					  call assert_equal('n', mode(1))
 | 
				
			||||||
 | 
					  call assert_equal('some short l', @b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " error doesn't interrupt temporary visual mode
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F6>", "xt!")', 'E605:')
 | 
				
			||||||
 | 
					  redraw!
 | 
				
			||||||
 | 
					  call assert_match('^-- VISUAL --', Screenline(&lines))
 | 
				
			||||||
 | 
					  " quirk: restoration of select mode is not performed
 | 
				
			||||||
 | 
					  call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " error doesn't interrupt select mode
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F1>", "xt!")', 'E605:')
 | 
				
			||||||
 | 
					  redraw!
 | 
				
			||||||
 | 
					  call assert_match('^-- SELECT --', Screenline(&lines))
 | 
				
			||||||
 | 
					  call assert_equal(['s', 1, 6], [mode(1), col('v'), col('.')])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call feedkeys("\<F7>", 'xt!')
 | 
				
			||||||
 | 
					  redraw!
 | 
				
			||||||
 | 
					  call assert_match('^-- SELECT --', Screenline(&lines))
 | 
				
			||||||
 | 
					  call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " startinsert gives "-- SELECT (insert) --" mode
 | 
				
			||||||
 | 
					  call feedkeys("\<F8>", 'xt!')
 | 
				
			||||||
 | 
					  redraw!
 | 
				
			||||||
 | 
					  call assert_match('^-- (insert) SELECT --', Screenline(&lines))
 | 
				
			||||||
 | 
					  call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), line('.'), col('.')])
 | 
				
			||||||
 | 
					  call feedkeys("\<Esc>new ", 'x')
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'of new test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  sunmap <F1>
 | 
				
			||||||
 | 
					  sunmap <F2>
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  set showmode&
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in operator-pending mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_op_pending_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  call feedkeys("d\<F4>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['lines', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					  call assert_equal(['some short '], getreg('"', 1, 1))
 | 
				
			||||||
 | 
					  " create a new undo point
 | 
				
			||||||
 | 
					  let &undolevels = &undolevels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call feedkeys(".", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					  call assert_equal(['lines', 'of '], getreg('"', 1, 1))
 | 
				
			||||||
 | 
					  " create a new undo point
 | 
				
			||||||
 | 
					  let &undolevels = &undolevels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call feedkeys("uu", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " error aborts operator-pending, operator not performed
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("d\<F6>", "xt")', 'E605:')
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call feedkeys("\"bd\<F7>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['soest text'], getline(1, '$'))
 | 
				
			||||||
 | 
					  call assert_equal(['me short lines', 'of t'], getreg('b', 1, 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " startinsert aborts operator
 | 
				
			||||||
 | 
					  call feedkeys("d\<F8>cc", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['soccest text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in insert mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_insert_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  " works the same as <C-O>w<C-O>w
 | 
				
			||||||
 | 
					  call feedkeys("iindeed \<F4>little ", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['indeed some short little lines', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys("i\<F6> 2", "xt")', 'E605:')
 | 
				
			||||||
 | 
					  call assert_equal(['indeed some short little 2 lines', 'of test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " Note when entering visual mode from InsertEnter autocmd, an async event,
 | 
				
			||||||
 | 
					  " or a <Cmd> mapping, vim ends up in undocumented "INSERT VISUAL" mode.
 | 
				
			||||||
 | 
					  call feedkeys("i\<F7>stuff ", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['indeed some short little 2 lines', 'of stuff test text'], getline(1, '$'))
 | 
				
			||||||
 | 
					  call assert_equal(['v', 1, 3, 2, 9], [mode(1), line('v'), col('v'), line('.'), col('.')])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call feedkeys("\<F5>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['deed some short little 2 lines', 'of stuff '], getreg('a', 1, 1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " also works as part of abbreviation
 | 
				
			||||||
 | 
					  abbr foo <Cmd>let g:y = 17<CR>bar
 | 
				
			||||||
 | 
					  exe "normal i\<space>foo "
 | 
				
			||||||
 | 
					  call assert_equal(17, g:y)
 | 
				
			||||||
 | 
					  call assert_equal('in bar deed some short little 2 lines', getline(1))
 | 
				
			||||||
 | 
					  unabbr foo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " :startinsert does nothing
 | 
				
			||||||
 | 
					  call setline(1, 'foo bar')
 | 
				
			||||||
 | 
					  call feedkeys("ggi\<F8>vim", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('vimfoo bar', getline(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " :stopinsert works
 | 
				
			||||||
 | 
					  call feedkeys("ggi\<F9>Abc", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('vimfoo barbc', getline(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in insert-completion mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_insert_complete_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, 'some short lines')
 | 
				
			||||||
 | 
					  call feedkeys("os\<C-X>\<C-N>\<F3>\<C-N> ", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('ic', m)
 | 
				
			||||||
 | 
					  call assert_equal(['some short lines', 'short '], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					" Test for <Cmd> mapping in cmdline mode
 | 
				
			||||||
 | 
					func Test_map_cmdkey_cmdline_mode()
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  call s:setupMaps()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['some short lines', 'of test text'])
 | 
				
			||||||
 | 
					  let x = 0
 | 
				
			||||||
 | 
					  call feedkeys(":let x\<F3>= 10\r", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('c', m)
 | 
				
			||||||
 | 
					  call assert_equal(10, x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " exception doesn't leave cmdline mode
 | 
				
			||||||
 | 
					  call assert_fails('call feedkeys(":let x\<F6>= 20\r", "xt")', 'E605:')
 | 
				
			||||||
 | 
					  call assert_equal(20, x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " move cursor in the buffer from cmdline mode
 | 
				
			||||||
 | 
					  call feedkeys(":let x\<F4>= 30\r", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(30, x)
 | 
				
			||||||
 | 
					  call assert_equal(12, col('.'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " :startinsert takes effect after leaving cmdline mode
 | 
				
			||||||
 | 
					  call feedkeys(":let x\<F8>= 40\rnew ", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(40, x)
 | 
				
			||||||
 | 
					  call assert_equal('some short new lines', getline(1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call s:cleanupMaps()
 | 
				
			||||||
 | 
					  %bw!
 | 
				
			||||||
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Test_map_cmdkey_redo()
 | 
					func Test_map_cmdkey_redo()
 | 
				
			||||||
  func SelectDash()
 | 
					  func SelectDash()
 | 
				
			||||||
    call search('^---\n\zs', 'bcW')
 | 
					    call search('^---\n\zs', 'bcW')
 | 
				
			||||||
@@ -1002,6 +1466,24 @@ func Test_map_cmdkey_redo()
 | 
				
			|||||||
  call delete('Xcmdtext')
 | 
					  call delete('Xcmdtext')
 | 
				
			||||||
  delfunc SelectDash
 | 
					  delfunc SelectDash
 | 
				
			||||||
  ounmap i-
 | 
					  ounmap i-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  new
 | 
				
			||||||
 | 
					  call setline(1, 'aaa bbb ccc ddd')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " command can contain special keys
 | 
				
			||||||
 | 
					  onoremap ix <Cmd>let g:foo ..= '…'<Bar>normal! <C-Right><CR>
 | 
				
			||||||
 | 
					  let g:foo = ''
 | 
				
			||||||
 | 
					  call feedkeys('0dix.', 'xt')
 | 
				
			||||||
 | 
					  call assert_equal('……', g:foo)
 | 
				
			||||||
 | 
					  call assert_equal('ccc ddd', getline(1))
 | 
				
			||||||
 | 
					  unlet g:foo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  " command line ending in "0" is handled without errors
 | 
				
			||||||
 | 
					  onoremap ix <Cmd>eval 0<CR>
 | 
				
			||||||
 | 
					  call feedkeys('dix.', 'xt')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ounmap ix
 | 
				
			||||||
 | 
					  bwipe!
 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
" Test for using <script> with a map to remap characters in rhs
 | 
					" Test for using <script> with a map to remap characters in rhs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3648,11 +3648,32 @@ func Test_horiz_motion()
 | 
				
			|||||||
  bwipe!
 | 
					  bwipe!
 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
" Test for using a : command in operator pending mode
 | 
					" Test for using a ":" command in operator pending mode
 | 
				
			||||||
func Test_normal_colon_op()
 | 
					func Test_normal_colon_op()
 | 
				
			||||||
  new
 | 
					  new
 | 
				
			||||||
  call setline(1, ['one', 'two'])
 | 
					  call setline(1, ['one', 'two'])
 | 
				
			||||||
  call assert_beeps("normal! Gc:d\<CR>")
 | 
					  call assert_beeps("normal! Gc:d\<CR>")
 | 
				
			||||||
 | 
					  call assert_equal(['one'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['one…two…three!'])
 | 
				
			||||||
 | 
					  normal! $
 | 
				
			||||||
 | 
					  " Using ":" as a movement is characterwise exclusive
 | 
				
			||||||
 | 
					  call feedkeys("d:normal! F…\<CR>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['one…two!'], getline(1, '$'))
 | 
				
			||||||
 | 
					  " Check that redoing a command with 0x80 bytes works
 | 
				
			||||||
 | 
					  call feedkeys('.', 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['one!'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  call setline(1, ['one', 'two', 'three', 'four', 'five'])
 | 
				
			||||||
 | 
					  " Add this to the command history
 | 
				
			||||||
 | 
					  call feedkeys(":normal! G0\<CR>", 'xt')
 | 
				
			||||||
 | 
					  " Use :normal! with control characters in operator pending mode
 | 
				
			||||||
 | 
					  call feedkeys("d:normal! \<C-V>\<C-P>\<C-V>\<C-P>\<CR>", 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['one', 'two', 'five'], getline(1, '$'))
 | 
				
			||||||
 | 
					  " Check that redoing a command with control characters works
 | 
				
			||||||
 | 
					  call feedkeys('.', 'xt')
 | 
				
			||||||
 | 
					  call assert_equal(['five'], getline(1, '$'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bwipe!
 | 
					  bwipe!
 | 
				
			||||||
endfunc
 | 
					endfunc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user