mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	insert-mode: interpret unmapped META as ESC
closes #2454 closes #8213 ref #7972
This commit is contained in:
		| @@ -40,10 +40,11 @@ char		action	~ | |||||||
| 						*i_CTRL-[* *i_<Esc>* | 						*i_CTRL-[* *i_<Esc>* | ||||||
| <Esc> or CTRL-[	End insert or Replace mode, go back to Normal mode.  Finish | <Esc> or CTRL-[	End insert or Replace mode, go back to Normal mode.  Finish | ||||||
| 		abbreviation. | 		abbreviation. | ||||||
| 		Note: If your <Esc> key is hard to hit on your keyboard, train | 		Note: If your <Esc> key is hard to hit, try CTRL-[ instead. | ||||||
| 		yourself to use CTRL-[. | 						*i_META* *i_ALT* | ||||||
| 		If Esc doesn't work and you are using a Mac, try CTRL-Esc. |                 |ALT| (|META|) acts like <Esc> if the chord is not mapped. | ||||||
| 		Or disable Listening under Accessibility preferences. | 		For example <A-x> acts like <Esc>x if <A-x> does not have an | ||||||
|  |                 insert-mode mapping. | ||||||
| 						*i_CTRL-C* | 						*i_CTRL-C* | ||||||
| CTRL-C		Quit insert mode, go back to Normal mode.  Do not check for | CTRL-C		Quit insert mode, go back to Normal mode.  Do not check for | ||||||
| 		abbreviations.  Does not trigger the |InsertLeave| autocommand | 		abbreviations.  Does not trigger the |InsertLeave| autocommand | ||||||
|   | |||||||
| @@ -6290,15 +6290,14 @@ A jump table for the options with a short description can be found at |Q_op|. | |||||||
| 						*'timeoutlen'* *'tm'* | 						*'timeoutlen'* *'tm'* | ||||||
| 'timeoutlen' 'tm'	number	(default 1000) | 'timeoutlen' 'tm'	number	(default 1000) | ||||||
| 			global | 			global | ||||||
| 	The time in milliseconds that is waited for a mapped sequence to | 	Time in milliseconds to wait for a mapped sequence to complete. | ||||||
| 	complete. |  | ||||||
|  |  | ||||||
| 						*'ttimeoutlen'* *'ttm'* | 						*'ttimeoutlen'* *'ttm'* | ||||||
| 'ttimeoutlen' 'ttm'	number	(default 50) | 'ttimeoutlen' 'ttm'	number	(default 50) | ||||||
| 			global | 			global | ||||||
| 	The time in milliseconds that is waited for a key code | 	Time in milliseconds to wait for a key code sequence to complete. Also | ||||||
| 	sequence to complete. Also used for CTRL-\ CTRL-N and CTRL-\ CTRL-G | 	used for CTRL-\ CTRL-N and CTRL-\ CTRL-G when part of a command has | ||||||
| 	when part of a command has been typed. | 	been typed. | ||||||
|  |  | ||||||
| 						*'title'* *'notitle'* | 						*'title'* *'notitle'* | ||||||
| 'title'			boolean	(default off) | 'title'			boolean	(default off) | ||||||
|   | |||||||
| @@ -847,7 +847,7 @@ static int insert_handle_key(InsertState *s) | |||||||
|  |  | ||||||
|  |  | ||||||
|   case ' ': |   case ' ': | ||||||
|     if (mod_mask != 4) { |     if (mod_mask != MOD_MASK_CTRL) { | ||||||
|       goto normalchar; |       goto normalchar; | ||||||
|     } |     } | ||||||
|   // FALLTHROUGH |   // FALLTHROUGH | ||||||
| @@ -1180,6 +1180,14 @@ static int insert_handle_key(InsertState *s) | |||||||
|  |  | ||||||
| normalchar: | normalchar: | ||||||
|     // Insert a normal character. |     // Insert a normal character. | ||||||
|  |  | ||||||
|  |     if (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META) { | ||||||
|  |       // Unmapped ALT/META chord behaves like ESC+c. #8213 | ||||||
|  |       stuffcharReadbuff(ESC); | ||||||
|  |       stuffcharReadbuff(s->c); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (!p_paste) { |     if (!p_paste) { | ||||||
|       // Trigger InsertCharPre. |       // Trigger InsertCharPre. | ||||||
|       char_u *str = do_insert_char_pre(s->c); |       char_u *str = do_insert_char_pre(s->c); | ||||||
| @@ -1432,7 +1440,7 @@ static void ins_ctrl_v(void) | |||||||
|      * line and will not removed by the redraw */ |      * line and will not removed by the redraw */ | ||||||
|     edit_unputchar(); |     edit_unputchar(); | ||||||
|   clear_showcmd(); |   clear_showcmd(); | ||||||
|   insert_special(c, FALSE, TRUE); |   insert_special(c, true, true); | ||||||
|   revins_chars++; |   revins_chars++; | ||||||
|   revins_legal++; |   revins_legal++; | ||||||
| } | } | ||||||
| @@ -5054,13 +5062,11 @@ static void insert_special(int c, int allow_modmask, int ctrlv) | |||||||
|   char_u  *p; |   char_u  *p; | ||||||
|   int len; |   int len; | ||||||
|  |  | ||||||
|   /* |   // Special function key, translate into "<Key>". Up to the last '>' is | ||||||
|    * Special function key, translate into "<Key>". Up to the last '>' is |   // inserted with ins_str(), so as not to replace characters in replace | ||||||
|    * inserted with ins_str(), so as not to replace characters in replace |   // mode. | ||||||
|    * mode. |   // Only use mod_mask for special keys, to avoid things like <S-Space>, | ||||||
|    * Only use mod_mask for special keys, to avoid things like <S-Space>, |   // unless 'allow_modmask' is TRUE. | ||||||
|    * unless 'allow_modmask' is TRUE. |  | ||||||
|    */ |  | ||||||
|   if (mod_mask & MOD_MASK_CMD) {  // Command-key never produces a normal key. |   if (mod_mask & MOD_MASK_CMD) {  // Command-key never produces a normal key. | ||||||
|     allow_modmask = true; |     allow_modmask = true; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1577,7 +1577,7 @@ vungetc ( /* unget one character (can only be done once!) */ | |||||||
|   old_mouse_col = mouse_col; |   old_mouse_col = mouse_col; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// get a character: | /// Gets a character: | ||||||
| /// 1. from the stuffbuffer | /// 1. from the stuffbuffer | ||||||
| ///    This is used for abbreviated commands like "D" -> "d$". | ///    This is used for abbreviated commands like "D" -> "d$". | ||||||
| ///    Also used to redo a command for ".". | ///    Also used to redo a command for ".". | ||||||
| @@ -1595,7 +1595,7 @@ vungetc ( /* unget one character (can only be done once!) */ | |||||||
| /// if "advance" is FALSE (vpeekc()): | /// if "advance" is FALSE (vpeekc()): | ||||||
| ///    just look whether there is a character available. | ///    just look whether there is a character available. | ||||||
| /// | /// | ||||||
| /// When "no_mapping" is zero, checks for mappings in the current mode. | /// When `no_mapping` (global) is zero, checks for mappings in the current mode. | ||||||
| /// Only returns one byte (of a multi-byte character). | /// Only returns one byte (of a multi-byte character). | ||||||
| /// K_SPECIAL and CSI may be escaped, need to get two more bytes then. | /// K_SPECIAL and CSI may be escaped, need to get two more bytes then. | ||||||
| static int vgetorpeek(int advance) | static int vgetorpeek(int advance) | ||||||
|   | |||||||
| @@ -443,7 +443,7 @@ enum key_extra { | |||||||
| #define MOD_MASK_2CLICK     0x20        // use MOD_MASK_MULTI_CLICK | #define MOD_MASK_2CLICK     0x20        // use MOD_MASK_MULTI_CLICK | ||||||
| #define MOD_MASK_3CLICK     0x40        // use MOD_MASK_MULTI_CLICK | #define MOD_MASK_3CLICK     0x40        // use MOD_MASK_MULTI_CLICK | ||||||
| #define MOD_MASK_4CLICK     0x60        // use MOD_MASK_MULTI_CLICK | #define MOD_MASK_4CLICK     0x60        // use MOD_MASK_MULTI_CLICK | ||||||
| #define MOD_MASK_CMD        0x80        // "super" key (OSX/Mac: command-key) | #define MOD_MASK_CMD        0x80        // "super" key (macOS: command-key) | ||||||
|  |  | ||||||
| #define MOD_MASK_MULTI_CLICK    (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \ | #define MOD_MASK_MULTI_CLICK    (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \ | ||||||
|                                  MOD_MASK_4CLICK) |                                  MOD_MASK_4CLICK) | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								test/functional/insert/insert_spec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								test/functional/insert/insert_spec.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | local helpers = require('test.functional.helpers')(after_each) | ||||||
|  | local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert | ||||||
|  | local command = helpers.command | ||||||
|  | local eq = helpers.eq | ||||||
|  | local expect = helpers.expect | ||||||
|  | local funcs = helpers.funcs | ||||||
|  |  | ||||||
|  | describe('insert-mode', function() | ||||||
|  |   before_each(function() | ||||||
|  |     clear() | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('CTRL-@', function() | ||||||
|  |     -- Inserts last-inserted text, leaves insert-mode. | ||||||
|  |     insert('hello') | ||||||
|  |     feed('i<C-@>x') | ||||||
|  |     expect('hellhello') | ||||||
|  |  | ||||||
|  |     -- C-Space is the same as C-@. | ||||||
|  |     -- CTRL-SPC inserts last-inserted text, leaves insert-mode. | ||||||
|  |     feed('i<C-Space>x') | ||||||
|  |     expect('hellhellhello') | ||||||
|  |  | ||||||
|  |     -- CTRL-A inserts last inserted text | ||||||
|  |     feed('i<C-A>x') | ||||||
|  |     expect('hellhellhellhelloxo') | ||||||
|  |   end) | ||||||
|  |  | ||||||
|  |   it('ALT/META #8213', function() | ||||||
|  |     -- Mapped ALT-chord behaves as mapped. | ||||||
|  |     command('inoremap <M-l> meta-l') | ||||||
|  |     command('inoremap <A-j> alt-j') | ||||||
|  |     feed('i<M-l> xxx <A-j><M-h>a<A-h>') | ||||||
|  |     expect('meta-l xxx alt-j') | ||||||
|  |     eq({ 0, 1, 14, 0, }, funcs.getpos('.')) | ||||||
|  |     -- Unmapped ALT-chord behaves as ESC+c. | ||||||
|  |     command('iunmap <M-l>') | ||||||
|  |     feed('0i<M-l>') | ||||||
|  |     eq({ 0, 1, 2, 0, }, funcs.getpos('.')) | ||||||
|  |   end) | ||||||
|  | end) | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| local helpers = require('test.functional.helpers')(after_each) |  | ||||||
| local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert |  | ||||||
| local expect = helpers.expect |  | ||||||
|  |  | ||||||
| clear() |  | ||||||
|  |  | ||||||
| describe('insert-mode', function() |  | ||||||
|   it('CTRL-@ inserts last-inserted text, leaves insert-mode', function() |  | ||||||
|     insert('hello') |  | ||||||
|     feed('i<C-@>x') |  | ||||||
|     expect('hellhello') |  | ||||||
|   end) |  | ||||||
|   -- C-Space is the same as C-@ |  | ||||||
|   it('CTRL-SPC inserts last-inserted text, leaves insert-mode', function() |  | ||||||
|     feed('i<C-Space>x') |  | ||||||
|     expect('hellhellhello') |  | ||||||
|   end) |  | ||||||
|   it('CTRL-A inserts last inserted text', function() |  | ||||||
|     feed('i<C-A>x') |  | ||||||
|     expect('hellhellhellhelloxo') |  | ||||||
|   end) |  | ||||||
| end) |  | ||||||
| @@ -115,16 +115,12 @@ describe('tui', function() | |||||||
|     ]]) |     ]]) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('does not mangle unmapped ALT-key chord', function() |   it('interprets ESC+key as ALT chord', function() | ||||||
|     -- Vim represents ALT/META by setting the "high bit" of the modified key; |     -- Vim represents ALT/META by setting the "high bit" of the modified key: | ||||||
|     -- we do _not_. #3982 |     -- ALT+j inserts "ê". Nvim does not (#3982). | ||||||
|     -- |     feed_data('i\022\027j') | ||||||
|     -- Example: for input ALT+j: |  | ||||||
|     --    * Vim (Nvim prior to #3982) sets high-bit, inserts "ê". |  | ||||||
|     --    * Nvim (after #3982) inserts "j". |  | ||||||
|     feed_data('i\027j') |  | ||||||
|     screen:expect([[ |     screen:expect([[ | ||||||
|       j{1: }                                                | |       <M-j>{1: }                                            | | ||||||
|       {4:~                                                 }| |       {4:~                                                 }| | ||||||
|       {4:~                                                 }| |       {4:~                                                 }| | ||||||
|       {4:~                                                 }| |       {4:~                                                 }| | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Justin M. Keyes
					Justin M. Keyes