mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge #4419 'implement <Cmd> key'
This commit is contained in:
		| @@ -232,8 +232,10 @@ For this reason the following is blocked: | |||||||
| - Editing another buffer. | - Editing another buffer. | ||||||
| - The |:normal| command. | - The |:normal| command. | ||||||
| - 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 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. | that. Alternatively use a |<Cmd>| mapping which doesn't have these | ||||||
|  | restrictions. | ||||||
|  |  | ||||||
| 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: > | ||||||
| @@ -272,6 +274,29 @@ again for using <expr>.  This does work: > | |||||||
| Using 0x80 as a single byte before other text does not work, it will be seen | Using 0x80 as a single byte before other text does not work, it will be seen | ||||||
| as a special key. | as a special key. | ||||||
|  |  | ||||||
|  | 						*<Cmd>* *:map-command* | ||||||
|  | A command mapping is a mapping that directly executes a command. Command | ||||||
|  | mappings are written by placing a command in between <Cmd> and <CR> in the | ||||||
|  | rhs of a mapping (in any mode): > | ||||||
|  | 	noremap <f3> <Cmd>echo mode(1)<cr> | ||||||
|  | < | ||||||
|  | 							*E5520* | ||||||
|  | The command must be complete and ended with a <CR>. If the command is | ||||||
|  | incomplete, an error is raised. |Command-line| mode is never entered. | ||||||
|  |  | ||||||
|  | This is more flexible than using `:<c-u>` in visual and operator pending | ||||||
|  | mode, or `<c-o>:` in insert mode, as the commands are exectued directly in the | ||||||
|  | mode, and not normal mode. Also visual mode is not aborted. Commands can be | ||||||
|  | invoked directly in cmdline mode, which is not simple otherwise (a timer has | ||||||
|  | to be used). Unlike <expr> mappings, there are not any specific restrictions | ||||||
|  | what the command can do, except for what is normally possible to do in every | ||||||
|  | specific mode. The command should be executed the same way as if an | ||||||
|  | (unrestricted) |autocmd| was invoked or an async event event was processed. | ||||||
|  |  | ||||||
|  | Note: In select mode, |:map| or |:vmap| command mappings will be executed in | ||||||
|  | visual mode. If a mapping is intended to work in select mode, it is | ||||||
|  | recomendend to map it using |:smap|, possibly in addition to the same mapping | ||||||
|  | with |:map| or |:xmap|. | ||||||
|  |  | ||||||
| 1.3 MAPPING AND MODES					*:map-modes* | 1.3 MAPPING AND MODES					*:map-modes* | ||||||
| 		*mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* *mapmode-t* | 		*mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* *mapmode-t* | ||||||
|   | |||||||
| @@ -974,6 +974,10 @@ static int insert_handle_key(InsertState *s) | |||||||
|     multiqueue_process_events(main_loop.events); |     multiqueue_process_events(main_loop.events); | ||||||
|     break; |     break; | ||||||
|  |  | ||||||
|  |   case K_COMMAND:       // some command | ||||||
|  |     do_cmdline(NULL, getcmdkeycmd, NULL, 0); | ||||||
|  |     break; | ||||||
|  |  | ||||||
|   case K_HOME:        // <Home> |   case K_HOME:        // <Home> | ||||||
|   case K_KHOME: |   case K_KHOME: | ||||||
|   case K_S_HOME: |   case K_S_HOME: | ||||||
|   | |||||||
| @@ -8156,6 +8156,10 @@ static void ex_startinsert(exarg_T *eap) | |||||||
|       restart_edit = 'i'; |       restart_edit = 'i'; | ||||||
|     curwin->w_curswant = 0;         /* avoid MAXCOL */ |     curwin->w_curswant = 0;         /* avoid MAXCOL */ | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if (VIsual_active) { | ||||||
|  |     showmode(); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|   | |||||||
| @@ -512,8 +512,12 @@ static int command_line_execute(VimState *state, int key) | |||||||
|   CommandLineState *s = (CommandLineState *)state; |   CommandLineState *s = (CommandLineState *)state; | ||||||
|   s->c = key; |   s->c = key; | ||||||
|  |  | ||||||
|   if (s->c == K_EVENT) { |   if (s->c == K_EVENT || s->c == K_COMMAND) { | ||||||
|     multiqueue_process_events(main_loop.events); |     if (s->c == K_EVENT) { | ||||||
|  |       multiqueue_process_events(main_loop.events); | ||||||
|  |     } else { | ||||||
|  |       do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT); | ||||||
|  |     } | ||||||
|     redrawcmdline(); |     redrawcmdline(); | ||||||
|     return 1; |     return 1; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -4247,3 +4247,70 @@ mapblock_T *get_maphash(int index, buf_T *buf) | |||||||
|  |  | ||||||
|   return (buf == NULL) ? maphash[index] : buf->b_maphash[index]; |   return (buf == NULL) ? maphash[index] : buf->b_maphash[index]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Get command argument for <Cmd> key | ||||||
|  | char_u * getcmdkeycmd(int promptc, void *cookie, int indent) | ||||||
|  | { | ||||||
|  |   garray_T line_ga; | ||||||
|  |   int c1 = -1, c2; | ||||||
|  |   int cmod = 0; | ||||||
|  |   bool aborted = false; | ||||||
|  |  | ||||||
|  |   ga_init(&line_ga, 1, 32); | ||||||
|  |  | ||||||
|  |   no_mapping++; | ||||||
|  |  | ||||||
|  |   got_int = false; | ||||||
|  |   while (c1 != NUL && !aborted) { | ||||||
|  |     ga_grow(&line_ga, 32); | ||||||
|  |  | ||||||
|  |     if (vgetorpeek(false) == NUL) { | ||||||
|  |       // incomplete <Cmd> is an error, because there is not much the user | ||||||
|  |       // could do in this state. | ||||||
|  |       EMSG(e_cmdmap_err); | ||||||
|  |       aborted = true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Get one character at a time. | ||||||
|  |     c1 = vgetorpeek(true); | ||||||
|  |     // Get two extra bytes for special keys | ||||||
|  |     if (c1 == K_SPECIAL) { | ||||||
|  |       c1 = vgetorpeek(true);          // no mapping for these chars | ||||||
|  |       c2 = vgetorpeek(true); | ||||||
|  |       if (c1 == KS_MODIFIER) { | ||||||
|  |         cmod = c2; | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       c1 = TO_SPECIAL(c1, c2); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if (got_int) { | ||||||
|  |       aborted = true; | ||||||
|  |     } else if (c1 == '\r' || c1 == '\n') { | ||||||
|  |       c1 = NUL;  // end the line | ||||||
|  |     } else if (c1 == ESC) { | ||||||
|  |       aborted = true; | ||||||
|  |     } else if (c1 == K_COMMAND) { | ||||||
|  |       // special case to give nicer error message | ||||||
|  |       EMSG(e_cmdmap_repeated); | ||||||
|  |       aborted = true; | ||||||
|  |     } else if (IS_SPECIAL(c1)) { | ||||||
|  |       EMSG2(e_cmdmap_key, get_special_key_name(c1, cmod)); | ||||||
|  |       aborted = true; | ||||||
|  |     } else { | ||||||
|  |       ga_append(&line_ga, (char)c1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     cmod = 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   no_mapping--; | ||||||
|  |  | ||||||
|  |   if (aborted) { | ||||||
|  |     ga_clear(&line_ga); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return (char_u *)line_ga.ga_data; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1154,6 +1154,12 @@ EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long")); | |||||||
| EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String")); | EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String")); | ||||||
| EXTERN char_u e_autocmd_err[] INIT(=N_( | EXTERN char_u e_autocmd_err[] INIT(=N_( | ||||||
|     "E5500: autocmd has thrown an exception: %s")); |     "E5500: autocmd has thrown an exception: %s")); | ||||||
|  | EXTERN char_u e_cmdmap_err[] INIT(=N_( | ||||||
|  |     "E5520: <Cmd> mapping must end with <CR>")); | ||||||
|  | EXTERN char_u e_cmdmap_repeated[] INIT(=N_( | ||||||
|  |     "E5521: <Cmd> mapping must end with <CR> before second <Cmd>")); | ||||||
|  | EXTERN char_u e_cmdmap_key[] INIT(=N_( | ||||||
|  |     "E5522: <Cmd> mapping must not include %s key")); | ||||||
|  |  | ||||||
|  |  | ||||||
| EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); | EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); | ||||||
|   | |||||||
| @@ -285,6 +285,7 @@ static const struct key_name_entry { | |||||||
|   { K_SNR,             "SNR" }, |   { K_SNR,             "SNR" }, | ||||||
|   { K_PLUG,            "Plug" }, |   { K_PLUG,            "Plug" }, | ||||||
|   { K_PASTE,           "Paste" }, |   { K_PASTE,           "Paste" }, | ||||||
|  |   { K_COMMAND,         "Cmd" }, | ||||||
|   { 0,                 NULL } |   { 0,                 NULL } | ||||||
|   // NOTE: When adding a long name update MAX_KEY_NAME_LEN. |   // NOTE: When adding a long name update MAX_KEY_NAME_LEN. | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -243,6 +243,7 @@ enum key_extra { | |||||||
|   , KE_EVENT            // event |   , KE_EVENT            // event | ||||||
|   , KE_PASTE            // special key to toggle the 'paste' option. |   , KE_PASTE            // special key to toggle the 'paste' option. | ||||||
|                         // sent only by UIs |                         // sent only by UIs | ||||||
|  |   , KE_COMMAND          // special key to execute command in any mode | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -431,6 +432,7 @@ enum key_extra { | |||||||
|  |  | ||||||
| #define K_EVENT         TERMCAP2KEY(KS_EXTRA, KE_EVENT) | #define K_EVENT         TERMCAP2KEY(KS_EXTRA, KE_EVENT) | ||||||
| #define K_PASTE         TERMCAP2KEY(KS_EXTRA, KE_PASTE) | #define K_PASTE         TERMCAP2KEY(KS_EXTRA, KE_PASTE) | ||||||
|  | #define K_COMMAND       TERMCAP2KEY(KS_EXTRA, KE_COMMAND) | ||||||
|  |  | ||||||
| /* Bits for modifier mask */ | /* Bits for modifier mask */ | ||||||
| /* 0x01 cannot be used, because the modifier must be 0x02 or higher */ | /* 0x01 cannot be used, because the modifier must be 0x02 or higher */ | ||||||
|   | |||||||
| @@ -345,6 +345,7 @@ static const struct nv_cmd { | |||||||
|   { K_F8,      farsi_f8,       0,                      0 }, |   { K_F8,      farsi_f8,       0,                      0 }, | ||||||
|   { K_F9,      farsi_f9,       0,                      0 }, |   { K_F9,      farsi_f9,       0,                      0 }, | ||||||
|   { K_EVENT,   nv_event,       NV_KEEPREG,             0 }, |   { K_EVENT,   nv_event,       NV_KEEPREG,             0 }, | ||||||
|  |   { K_COMMAND, nv_colon,       0,                      0 }, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Number of commands in nv_cmds[]. */ | /* Number of commands in nv_cmds[]. */ | ||||||
| @@ -1473,13 +1474,13 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) | |||||||
|           AppendToRedobuffLit(cap->searchbuf, -1); |           AppendToRedobuffLit(cap->searchbuf, -1); | ||||||
|         } |         } | ||||||
|         AppendToRedobuff(NL_STR); |         AppendToRedobuff(NL_STR); | ||||||
|       } else if (cap->cmdchar == ':') { |       } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) { | ||||||
|         /* do_cmdline() has stored the first typed line in |         // do_cmdline() has stored the first typed line in | ||||||
|          * "repeat_cmdline".  When several lines are typed repeating |         // "repeat_cmdline".  When several lines are typed repeating | ||||||
|          * won't be possible. */ |         // won't be possible. | ||||||
|         if (repeat_cmdline == NULL) |         if (repeat_cmdline == NULL) { | ||||||
|           ResetRedobuff(); |           ResetRedobuff(); | ||||||
|         else { |         } else { | ||||||
|           AppendToRedobuffLit(repeat_cmdline, -1); |           AppendToRedobuffLit(repeat_cmdline, -1); | ||||||
|           AppendToRedobuff(NL_STR); |           AppendToRedobuff(NL_STR); | ||||||
|           xfree(repeat_cmdline); |           xfree(repeat_cmdline); | ||||||
| @@ -4524,23 +4525,22 @@ static void nv_exmode(cmdarg_T *cap) | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /// Handle a ":" command and <Cmd>. | ||||||
|  * Handle a ":" command. |  | ||||||
|  */ |  | ||||||
| static void nv_colon(cmdarg_T *cap) | static void nv_colon(cmdarg_T *cap) | ||||||
| { | { | ||||||
|   int old_p_im; |   int old_p_im; | ||||||
|   bool cmd_result; |   bool cmd_result; | ||||||
|  |   bool is_cmdkey = cap->cmdchar == K_COMMAND; | ||||||
|  |  | ||||||
|   if (VIsual_active) |   if (VIsual_active && !is_cmdkey) { | ||||||
|     nv_operator(cap); |     nv_operator(cap); | ||||||
|   else { |   } else { | ||||||
|     if (cap->oap->op_type != OP_NOP) { |     if (cap->oap->op_type != OP_NOP) { | ||||||
|       // Using ":" as a movement is characterwise exclusive. |       // Using ":" as a movement is characterwise exclusive. | ||||||
|       cap->oap->motion_type = kMTCharWise; |       cap->oap->motion_type = kMTCharWise; | ||||||
|       cap->oap->inclusive = false; |       cap->oap->inclusive = false; | ||||||
|     } else if (cap->count0) { |     } else if (cap->count0 && !is_cmdkey) { | ||||||
|       /* translate "count:" into ":.,.+(count - 1)" */ |       // translate "count:" into ":.,.+(count - 1)" | ||||||
|       stuffcharReadbuff('.'); |       stuffcharReadbuff('.'); | ||||||
|       if (cap->count0 > 1) { |       if (cap->count0 > 1) { | ||||||
|         stuffReadbuff(",.+"); |         stuffReadbuff(",.+"); | ||||||
| @@ -4554,9 +4554,9 @@ static void nv_colon(cmdarg_T *cap) | |||||||
|  |  | ||||||
|     old_p_im = p_im; |     old_p_im = p_im; | ||||||
|  |  | ||||||
|     /* get a command line and execute it */ |     // get a command line and execute it | ||||||
|     cmd_result = do_cmdline(NULL, getexline, NULL, |     cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL, | ||||||
|         cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); |                             cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); | ||||||
|  |  | ||||||
|     /* If 'insertmode' changed, enter or exit Insert mode */ |     /* If 'insertmode' changed, enter or exit Insert mode */ | ||||||
|     if (p_im != old_p_im) { |     if (p_im != old_p_im) { | ||||||
|   | |||||||
| @@ -6748,16 +6748,20 @@ int showmode(void) | |||||||
|           if (p_ri) |           if (p_ri) | ||||||
|             MSG_PUTS_ATTR(_(" REVERSE"), attr); |             MSG_PUTS_ATTR(_(" REVERSE"), attr); | ||||||
|           MSG_PUTS_ATTR(_(" INSERT"), attr); |           MSG_PUTS_ATTR(_(" INSERT"), attr); | ||||||
|         } else if (restart_edit == 'I') |         } else if (restart_edit == 'I' || restart_edit == 'i' | ||||||
|  |                    || restart_edit == 'a') { | ||||||
|           MSG_PUTS_ATTR(_(" (insert)"), attr); |           MSG_PUTS_ATTR(_(" (insert)"), attr); | ||||||
|         else if (restart_edit == 'R') |         } else if (restart_edit == 'R') { | ||||||
|           MSG_PUTS_ATTR(_(" (replace)"), attr); |           MSG_PUTS_ATTR(_(" (replace)"), attr); | ||||||
|         else if (restart_edit == 'V') |         } else if (restart_edit == 'V') { | ||||||
|           MSG_PUTS_ATTR(_(" (vreplace)"), attr); |           MSG_PUTS_ATTR(_(" (vreplace)"), attr); | ||||||
|         if (p_hkmap) |         } | ||||||
|  |         if (p_hkmap) { | ||||||
|           MSG_PUTS_ATTR(_(" Hebrew"), attr); |           MSG_PUTS_ATTR(_(" Hebrew"), attr); | ||||||
|         if (p_fkmap) |         } | ||||||
|  |         if (p_fkmap) { | ||||||
|           MSG_PUTS_ATTR(farsi_text_5, attr); |           MSG_PUTS_ATTR(farsi_text_5, attr); | ||||||
|  |         } | ||||||
|         if (State & LANGMAP) { |         if (State & LANGMAP) { | ||||||
|           if (curwin->w_p_arab) { |           if (curwin->w_p_arab) { | ||||||
|             MSG_PUTS_ATTR(_(" Arabic"), attr); |             MSG_PUTS_ATTR(_(" Arabic"), attr); | ||||||
|   | |||||||
| @@ -461,6 +461,10 @@ static int terminal_execute(VimState *state, int key) | |||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|  |  | ||||||
|  |     case K_COMMAND: | ||||||
|  |       do_cmdline(NULL, getcmdkeycmd, NULL, 0); | ||||||
|  |       break; | ||||||
|  |  | ||||||
|     case Ctrl_N: |     case Ctrl_N: | ||||||
|       if (s->got_bsl) { |       if (s->got_bsl) { | ||||||
|         return 0; |         return 0; | ||||||
|   | |||||||
							
								
								
									
										771
									
								
								test/functional/ex_cmds/cmd_map_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										771
									
								
								test/functional/ex_cmds/cmd_map_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,771 @@ | |||||||
|  | local helpers = require('test.functional.helpers')(after_each) | ||||||
|  | local clear = helpers.clear | ||||||
|  | local feed_command = helpers.feed_command | ||||||
|  | local feed = helpers.feed | ||||||
|  | local eq = helpers.eq | ||||||
|  | local expect = helpers.expect | ||||||
|  | local eval = helpers.eval | ||||||
|  | local funcs = helpers.funcs | ||||||
|  | local insert = helpers.insert | ||||||
|  | local exc_exec = helpers.exc_exec | ||||||
|  | local Screen = require('test.functional.ui.screen') | ||||||
|  |  | ||||||
|  | describe('mappings with <Cmd>', function() | ||||||
|  |   local screen | ||||||
|  |   local function cmdmap(lhs, rhs) | ||||||
|  |     feed_command('noremap '..lhs..' <Cmd>'..rhs..'<cr>') | ||||||
|  |     feed_command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>') | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   before_each(function() | ||||||
|  |     clear() | ||||||
|  |     screen = Screen.new(65, 8) | ||||||
|  |     screen:set_default_attr_ids({ | ||||||
|  |       [1] = {bold = true, foreground = Screen.colors.Blue1}, | ||||||
|  |       [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, | ||||||
|  |       [3] = {bold = true, foreground = Screen.colors.SeaGreen4}, | ||||||
|  |       [4] = {bold = true}, | ||||||
|  |       [5] = {background = Screen.colors.LightGrey}, | ||||||
|  |       [6] = {foreground = Screen.colors.Blue1}, | ||||||
|  |     }) | ||||||
|  |     screen:attach() | ||||||
|  |  | ||||||
|  |     cmdmap('<F3>', 'let m = mode(1)') | ||||||
|  |     cmdmap('<F4>', 'normal! ww') | ||||||
|  |     cmdmap('<F5>', 'normal! "ay') | ||||||
|  |     cmdmap('<F6>', 'throw "very error"') | ||||||
|  |     feed_command([[ | ||||||
|  |         function! TextObj() | ||||||
|  |             if mode() !=# "v" | ||||||
|  |                 normal! v | ||||||
|  |             end | ||||||
|  |             call cursor(1,3) | ||||||
|  |             normal! o | ||||||
|  |             call cursor(2,4) | ||||||
|  |         endfunction]]) | ||||||
|  |     cmdmap('<F7>', 'call TextObj()') | ||||||
|  |     insert([[ | ||||||
|  |         some short lines | ||||||
|  |         of test text]]) | ||||||
|  |     feed('gg') | ||||||
|  |     cmdmap('<F8>', 'startinsert') | ||||||
|  |     cmdmap('<F9>', 'stopinsert') | ||||||
|  |     feed_command("abbr foo <Cmd>let g:y = 17<cr>bar") | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('can be displayed', function() | ||||||
|  |     feed_command('map <F3>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |          {6:<F3>}        {6:*} {6:<Cmd>}let m = mode(1){6:<CR>}                        | | ||||||
|  |     ]]) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('handles invalid mappings', function() | ||||||
|  |     feed_command('let x = 0') | ||||||
|  |     feed_command('noremap <F3> <Cmd><Cmd>let x = 1<cr>') | ||||||
|  |     feed('<F3>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:E5521: <Cmd> mapping must end with <CR> before second <Cmd>}      | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     feed_command('noremap <F3> <Cmd><F3>let x = 2<cr>') | ||||||
|  |     feed('<F3>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:E5522: <Cmd> mapping must not include <F3> key}                   | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     feed_command('noremap <F3> <Cmd>let x = 3') | ||||||
|  |     feed('<F3>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:E5520: <Cmd> mapping must end with <CR>}                          | | ||||||
|  |     ]]) | ||||||
|  |     eq(0, eval('x')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in various modes and sees correct `mode()` value', function() | ||||||
|  |     -- normal mode | ||||||
|  |     feed('<F3>') | ||||||
|  |     eq('n', eval('m')) | ||||||
|  |  | ||||||
|  |     -- visual mode | ||||||
|  |     feed('v<F3>') | ||||||
|  |     eq('v', eval('m')) | ||||||
|  |     -- didn't leave visual mode | ||||||
|  |     eq('v', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- visual mapping in select mode | ||||||
|  |     feed('gh<F3>') | ||||||
|  |     eq('v', eval('m')) | ||||||
|  |     -- didn't leave select mode | ||||||
|  |     eq('s', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- select mode mapping | ||||||
|  |     feed_command('snoremap <F3> <Cmd>let m = mode(1)<cr>') | ||||||
|  |     feed('gh<F3>') | ||||||
|  |     eq('s', eval('m')) | ||||||
|  |     -- didn't leave select mode | ||||||
|  |     eq('s', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- operator-pending mode | ||||||
|  |     feed("d<F3>") | ||||||
|  |     eq('no', eval('m')) | ||||||
|  |     -- did leave operator-pending mode | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     --insert mode | ||||||
|  |     feed('i<F3>') | ||||||
|  |     eq('i', eval('m')) | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- replace mode | ||||||
|  |     feed("<Ins><F3>") | ||||||
|  |     eq('R', eval('m')) | ||||||
|  |     eq('R', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- virtual replace mode | ||||||
|  |     feed("gR<F3>") | ||||||
|  |     eq('Rv', eval('m')) | ||||||
|  |     eq('Rv', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- langmap works, but is not distinguished in mode(1) | ||||||
|  |     feed(":set iminsert=1<cr>i<F3>") | ||||||
|  |     eq('i', eval('m')) | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     feed(':<F3>') | ||||||
|  |     eq('c', eval('m')) | ||||||
|  |     eq('c', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- terminal mode | ||||||
|  |     feed_command('tnoremap <F3> <Cmd>let m = mode(1)<cr>') | ||||||
|  |     feed_command('split | terminal') | ||||||
|  |     feed('i') | ||||||
|  |     eq('t', eval('mode(1)')) | ||||||
|  |     feed('<F3>') | ||||||
|  |     eq('t', eval('m')) | ||||||
|  |     eq('t', eval('mode(1)')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in normal mode', function() | ||||||
|  |     cmdmap('<F2>', 'let s = [mode(1), v:count, v:register]') | ||||||
|  |  | ||||||
|  |     -- check v:count and v:register works | ||||||
|  |     feed('<F2>') | ||||||
|  |     eq({'n', 0, '"'}, eval('s')) | ||||||
|  |     feed('7<F2>') | ||||||
|  |     eq({'n', 7, '"'}, eval('s')) | ||||||
|  |     feed('"e<F2>') | ||||||
|  |     eq({'n', 0, 'e'}, eval('s')) | ||||||
|  |     feed('5"k<F2>') | ||||||
|  |     eq({'n', 5, 'k'}, eval('s')) | ||||||
|  |     feed('"+2<F2>') | ||||||
|  |     eq({'n', 2, '+'}, eval('s')) | ||||||
|  |  | ||||||
|  |     -- text object enters visual mode | ||||||
|  |     feed('<F7>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       so{5:me short lines}                                                 | | ||||||
|  |       {5:of }^test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- VISUAL --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     feed('<esc>') | ||||||
|  |  | ||||||
|  |     -- startinsert | ||||||
|  |     feed('<F8>') | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |  | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |     cmdmap(',a', 'call feedkeys("aalpha") \\| let g:a = getline(2)') | ||||||
|  |     cmdmap(',b', 'call feedkeys("abeta", "x") \\| let g:b = getline(2)') | ||||||
|  |  | ||||||
|  |     feed(',a<F3>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       some short lines                                                 | | ||||||
|  |       of alpha^test text                                                | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     -- feedkeys were not executed immediately | ||||||
|  |     eq({'n', 'of test text'}, eval('[m,a]')) | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |  | ||||||
|  |     feed(',b<F3>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       some short lines                                                 | | ||||||
|  |       of alphabet^atest text                                            | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |                                                                        | | ||||||
|  |     ]]) | ||||||
|  |     -- feedkeys(..., 'x') was executed immediately, but insert mode gets aborted | ||||||
|  |     eq({'n', 'of alphabetatest text'}, eval('[m,b]')) | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in :normal command', function() | ||||||
|  |     feed_command('noremap ,x <Cmd>call append(1, "xx")\\| call append(1, "aa")<cr>') | ||||||
|  |     feed_command('noremap ,f <Cmd>nosuchcommand<cr>') | ||||||
|  |     feed_command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>') | ||||||
|  |     feed_command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>') | ||||||
|  |     feed_command('noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>') | ||||||
|  |  | ||||||
|  |     feed(":normal ,x<cr>") | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       aa                                                               | | ||||||
|  |       xx                                                               | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |                                                                        | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     eq('Vim:E492: Not an editor command: nosuchcommand', exc_exec("normal ,f")) | ||||||
|  |     eq('very error', exc_exec("normal ,e")) | ||||||
|  |     eq('Vim(echoerr):The message.', exc_exec("normal ,m")) | ||||||
|  |     feed('w') | ||||||
|  |     screen:expect([[ | ||||||
|  |       some ^short lines                                                 | | ||||||
|  |       aa                                                               | | ||||||
|  |       xx                                                               | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |                                                                        | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     feed_command(':%d') | ||||||
|  |     eq('Vim(echoerr):Err', exc_exec("normal ,w")) | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^                                                                 | | ||||||
|  |       0                                                                | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       --No lines in buffer--                                           | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     feed_command(':%d') | ||||||
|  |     feed_command(':normal ,w') | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^                                                                 | | ||||||
|  |       4                                                                | | ||||||
|  |       3                                                                | | ||||||
|  |       2                                                                | | ||||||
|  |       1                                                                | | ||||||
|  |       0                                                                | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:Err}                                                              | | ||||||
|  |     ]]) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in visual mode', function() | ||||||
|  |     -- can extend visual mode | ||||||
|  |     feed('v<F4>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {5:some short }^lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- VISUAL --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('v', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     -- can invoke operator, ending visual mode | ||||||
|  |     feed('<F5>') | ||||||
|  |     eq('n', funcs.mode(1)) | ||||||
|  |     eq({'some short l'}, funcs.getreg('a',1,1)) | ||||||
|  |  | ||||||
|  |     -- error doesn't interrupt visual mode | ||||||
|  |     feed('ggvw<F6>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       {3:Press ENTER or type command to continue}^                          | | ||||||
|  |     ]]) | ||||||
|  |     feed('<cr>') | ||||||
|  |     eq('E605: Exception not caught: very error', eval('v:errmsg')) | ||||||
|  |     -- still in visual mode, <cr> was consumed by the error prompt | ||||||
|  |     screen:expect([[ | ||||||
|  |       {5:some }^short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- VISUAL --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('v', funcs.mode(1)) | ||||||
|  |     feed('<F7>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       so{5:me short lines}                                                 | | ||||||
|  |       {5:of }^test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- VISUAL --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('v', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     -- startinsert gives "-- (insert) VISUAL --" mode | ||||||
|  |     feed('<F8>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       so{5:me short lines}                                                 | | ||||||
|  |       {5:of }^test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- (insert) VISUAL --}                                            | | ||||||
|  |     ]]) | ||||||
|  |     eq('v', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in select mode', function() | ||||||
|  |     feed_command('snoremap <F1> <cmd>throw "very error"<cr>') | ||||||
|  |     feed_command('snoremap <F2> <cmd>normal! <c-g>"by<cr>') | ||||||
|  |     -- can extend select mode | ||||||
|  |     feed('gh<F4>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {5:some short }^lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- SELECT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('s', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     -- visual mapping in select mode restart selct mode after operator | ||||||
|  |     feed('<F5>') | ||||||
|  |     eq('s', funcs.mode(1)) | ||||||
|  |     eq({'some short l'}, funcs.getreg('a',1,1)) | ||||||
|  |  | ||||||
|  |     -- select mode mapping works, and does not restart select mode | ||||||
|  |     feed('<F2>') | ||||||
|  |     eq('n', funcs.mode(1)) | ||||||
|  |     eq({'some short l'}, funcs.getreg('b',1,1)) | ||||||
|  |  | ||||||
|  |     -- error doesn't interrupt temporary visual mode | ||||||
|  |     feed('<esc>ggvw<c-g><F6>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       {3:Press ENTER or type command to continue}^                          | | ||||||
|  |     ]]) | ||||||
|  |     feed('<cr>') | ||||||
|  |     eq('E605: Exception not caught: very error', eval('v:errmsg')) | ||||||
|  |     -- still in visual mode, <cr> was consumed by the error prompt | ||||||
|  |     screen:expect([[ | ||||||
|  |       {5:some }^short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- VISUAL --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     -- quirk: restoration of select mode is not performed | ||||||
|  |     eq('v', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     -- error doesn't interrupt select mode | ||||||
|  |     feed('<esc>ggvw<c-g><F1>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       {3:Press ENTER or type command to continue}^                          | | ||||||
|  |     ]]) | ||||||
|  |     feed('<cr>') | ||||||
|  |     eq('E605: Exception not caught: very error', eval('v:errmsg')) | ||||||
|  |     -- still in select mode, <cr> was consumed by the error prompt | ||||||
|  |     screen:expect([[ | ||||||
|  |       {5:some }^short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- SELECT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     -- quirk: restoration of select mode is not performed | ||||||
|  |     eq('s', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     feed('<F7>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       so{5:me short lines}                                                 | | ||||||
|  |       {5:of }^test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- SELECT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('s', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     -- startinsert gives "-- SELECT (insert) --" mode | ||||||
|  |     feed('<F8>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       so{5:me short lines}                                                 | | ||||||
|  |       {5:of }^test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- (insert) SELECT --}                                            | | ||||||
|  |     ]]) | ||||||
|  |     eq('s', eval('mode(1)')) | ||||||
|  |     feed('<esc>') | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   it('works in operator-pending mode', function() | ||||||
|  |     feed('d<F4>') | ||||||
|  |     expect([[ | ||||||
|  |         lines | ||||||
|  |         of test text]]) | ||||||
|  |     eq({'some short '}, funcs.getreg('"',1,1)) | ||||||
|  |     feed('.') | ||||||
|  |     expect([[ | ||||||
|  |         test text]]) | ||||||
|  |     eq({'lines', 'of '}, funcs.getreg('"',1,1)) | ||||||
|  |     feed('uu') | ||||||
|  |     expect([[ | ||||||
|  |         some short lines | ||||||
|  |         of test text]]) | ||||||
|  |  | ||||||
|  |     -- error aborts operator-pending, operator not performed | ||||||
|  |     feed('d<F6>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       {3:Press ENTER or type command to continue}^                          | | ||||||
|  |     ]]) | ||||||
|  |     feed('<cr>') | ||||||
|  |     eq('E605: Exception not caught: very error', eval('v:errmsg')) | ||||||
|  |     expect([[ | ||||||
|  |         some short lines | ||||||
|  |         of test text]]) | ||||||
|  |  | ||||||
|  |     feed('"bd<F7>') | ||||||
|  |     expect([[ | ||||||
|  |         soest text]]) | ||||||
|  |     eq(funcs.getreg('b',1,1), {'me short lines', 'of t'}) | ||||||
|  |  | ||||||
|  |     -- startinsert aborts operator | ||||||
|  |     feed('d<F8>') | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |     expect([[ | ||||||
|  |         soest text]]) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in insert mode', function() | ||||||
|  |  | ||||||
|  |     -- works the same as <c-o>w<c-o>w | ||||||
|  |     feed('iindeed <F4>little ') | ||||||
|  |     screen:expect([[ | ||||||
|  |       indeed some short little ^lines                                   | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     feed('<F6>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       {3:Press ENTER or type command to continue}^                          | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     feed('<cr>') | ||||||
|  |     eq('E605: Exception not caught: very error', eval('v:errmsg')) | ||||||
|  |     -- still in insert | ||||||
|  |     screen:expect([[ | ||||||
|  |       indeed some short little ^lines                                   | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- When entering visual mode from InsertEnter autocmd, an async event, or | ||||||
|  |     -- a <cmd> mapping, vim ends up in undocumented "INSERT VISUAL" mode. If a | ||||||
|  |     -- vim patch decides to disable this mode, this test is expected to fail. | ||||||
|  |     feed('<F7>stuff ') | ||||||
|  |     screen:expect([[ | ||||||
|  |       in{5:deed some short little lines}                                   | | ||||||
|  |       {5:of stuff }^test text                                               | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT VISUAL --}                                              | | ||||||
|  |     ]]) | ||||||
|  |     expect([[ | ||||||
|  |       indeed some short little lines | ||||||
|  |       of stuff test text]]) | ||||||
|  |  | ||||||
|  |     feed('<F5>') | ||||||
|  |     eq(funcs.getreg('a',1,1), {'deed some short little lines', 'of stuff t'}) | ||||||
|  |  | ||||||
|  |     -- still in insert | ||||||
|  |     screen:expect([[ | ||||||
|  |       in^deed some short little lines                                   | | ||||||
|  |       of stuff test text                                               | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- also works as part of abbreviation | ||||||
|  |     feed('<space>foo ') | ||||||
|  |     screen:expect([[ | ||||||
|  |       in bar ^deed some short little lines                              | | ||||||
|  |       of stuff test text                                               | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq(17, eval('g:y')) | ||||||
|  |  | ||||||
|  |     -- :startinsert does nothing | ||||||
|  |     feed('<F8>') | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     -- :stopinsert works | ||||||
|  |     feed('<F9>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('works in cmdline mode', function() | ||||||
|  |     cmdmap('<F2>', 'call setcmdpos(2)') | ||||||
|  |     feed(':text<F3>') | ||||||
|  |     eq('c', eval('m')) | ||||||
|  |     -- didn't leave cmdline mode | ||||||
|  |     eq('c', eval('mode(1)')) | ||||||
|  |     feed('<cr>') | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {2:E492: Not an editor command: text}                                | | ||||||
|  |     ]]) | ||||||
|  |  | ||||||
|  |     feed(':echo 2<F6>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       :echo 2                                                          | | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       :echo 2^                                                          | | ||||||
|  |     ]]) | ||||||
|  |     eq('E605: Exception not caught: very error', eval('v:errmsg')) | ||||||
|  |     -- didn't leave cmdline mode | ||||||
|  |     eq('c', eval('mode(1)')) | ||||||
|  |     feed('+2<cr>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       :echo 2                                                          | | ||||||
|  |       {2:Error detected while processing :}                                | | ||||||
|  |       {2:E605: Exception not caught: very error}                           | | ||||||
|  |       4                                                                | | ||||||
|  |       {3:Press ENTER or type command to continue}^                          | | ||||||
|  |     ]]) | ||||||
|  |     -- however, message scrolling may cause extra CR prompt | ||||||
|  |     -- This is consistent with output from async events. | ||||||
|  |     feed('<cr>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       ^some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |                                                                        | | ||||||
|  |     ]]) | ||||||
|  |     eq('n', eval('mode(1)')) | ||||||
|  |  | ||||||
|  |     feed(':let g:x = 3<F4>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       :let g:x = 3^                                                     | | ||||||
|  |     ]]) | ||||||
|  |     feed('+2<cr>') | ||||||
|  |     -- cursor was moved in the background | ||||||
|  |     screen:expect([[ | ||||||
|  |       some short ^lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       :let g:x = 3+2                                                   | | ||||||
|  |     ]]) | ||||||
|  |     eq(5, eval('g:x')) | ||||||
|  |  | ||||||
|  |     feed(':let g:y = 7<F8>') | ||||||
|  |     screen:expect([[ | ||||||
|  |       some short lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       :let g:y = 7^                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('c', eval('mode(1)')) | ||||||
|  |     feed('+2<cr>') | ||||||
|  |     -- startinsert takes effect after leaving cmdline mode | ||||||
|  |     screen:expect([[ | ||||||
|  |       some short ^lines                                                 | | ||||||
|  |       of test text                                                     | | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {1:~                                                                }| | ||||||
|  |       {4:-- INSERT --}                                                     | | ||||||
|  |     ]]) | ||||||
|  |     eq('i', eval('mode(1)')) | ||||||
|  |     eq(9, eval('g:y')) | ||||||
|  |  | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  | end) | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user
	 Justin M. Keyes
					Justin M. Keyes