mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge pull request #19584 from bfredl/terminal_c_BSL_c_O
implement <c-\><c-o> key for terminal mode
This commit is contained in:
		| @@ -5311,6 +5311,7 @@ mode([expr])	Return a string that indicates the current mode. | |||||||
| 		   niV	    Normal using |i_CTRL-O| in |Virtual-Replace-mode| | 		   niV	    Normal using |i_CTRL-O| in |Virtual-Replace-mode| | ||||||
| 		   nt	    Normal in |terminal-emulator| (insert goes to | 		   nt	    Normal in |terminal-emulator| (insert goes to | ||||||
| 				Terminal mode) | 				Terminal mode) | ||||||
|  | 		   ntT	    Normal using |t_CTRL-\_CTRL-O| in |terminal-mode| | ||||||
| 		   v	    Visual by character | 		   v	    Visual by character | ||||||
| 		   vs	    Visual by character using |v_CTRL-O| in Select mode | 		   vs	    Visual by character using |v_CTRL-O| in Select mode | ||||||
| 		   V	    Visual by line | 		   V	    Visual by line | ||||||
|   | |||||||
| @@ -1101,8 +1101,11 @@ tag		command		action in Command-line editing mode	~ | |||||||
| 5. Terminal mode				*terminal-mode-index* | 5. Terminal mode				*terminal-mode-index* | ||||||
|  |  | ||||||
| In a |terminal| buffer all keys except CTRL-\ are forwarded to the terminal | In a |terminal| buffer all keys except CTRL-\ are forwarded to the terminal | ||||||
| job.  If CTRL-\ is pressed, the next key is forwarded unless it is CTRL-N. | job.  If CTRL-\ is pressed, the next key is forwarded unless it is CTRL-N | ||||||
|  | or CTRL-O. | ||||||
| Use |CTRL-\_CTRL-N| to go to Normal mode. | Use |CTRL-\_CTRL-N| to go to Normal mode. | ||||||
|  | Use |t_CTRL-\_CTRL-O| to execute one normal mode command and then return | ||||||
|  | to terminal mode. | ||||||
|  |  | ||||||
|  |  | ||||||
| You found it, Arthur!				*holy-grail* | You found it, Arthur!				*holy-grail* | ||||||
|   | |||||||
| @@ -458,7 +458,7 @@ Ex mode			Like Command-line mode, but after entering a command | |||||||
| Terminal mode		In Terminal mode all input (except CTRL-\) is sent to | Terminal mode		In Terminal mode all input (except CTRL-\) is sent to | ||||||
| 			the process running in the current |terminal| buffer. | 			the process running in the current |terminal| buffer. | ||||||
| 			If CTRL-\ is pressed, the next key is sent unless it | 			If CTRL-\ is pressed, the next key is sent unless it | ||||||
| 			is CTRL-N (|CTRL-\_CTRL-N|). | 			is CTRL-N (|CTRL-\_CTRL-N|) or CTRL-O (|t_CTRL-\_CTRL-O|). | ||||||
| 			If the 'showmode' option is on "-- TERMINAL --" is shown | 			If the 'showmode' option is on "-- TERMINAL --" is shown | ||||||
| 			at the bottom of the window. | 			at the bottom of the window. | ||||||
|  |  | ||||||
| @@ -550,7 +550,8 @@ Ex		 :vi	  --	  --	 --	    --	      -- | |||||||
| *6 Go from Select mode to Insert mode by typing a printable character.  The | *6 Go from Select mode to Insert mode by typing a printable character.  The | ||||||
|    selection is deleted and the character is inserted. |    selection is deleted and the character is inserted. | ||||||
|  |  | ||||||
| 	*CTRL-\_CTRL-N* *i_CTRL-\_CTRL-N* *c_CTRL-\_CTRL-N* *v_CTRL-\_CTRL-N* | 			*CTRL-\_CTRL-N* *i_CTRL-\_CTRL-N* *c_CTRL-\_CTRL-N* | ||||||
|  | 				      *v_CTRL-\_CTRL-N* *t_CTRL-\_CTRL-N* | ||||||
| Additionally the command CTRL-\ CTRL-N or <C-\><C-N> can be used to go to | Additionally the command CTRL-\ CTRL-N or <C-\><C-N> can be used to go to | ||||||
| Normal mode from any other mode.  This can be used to make sure Vim is in | Normal mode from any other mode.  This can be used to make sure Vim is in | ||||||
| Normal mode, without causing a beep like <Esc> would.  However, this does not | Normal mode, without causing a beep like <Esc> would.  However, this does not | ||||||
|   | |||||||
| @@ -47,8 +47,10 @@ Input						*terminal-input* | |||||||
|  |  | ||||||
| To send input, enter |Terminal-mode| with |i|, |I|, |a|, |A| or | To send input, enter |Terminal-mode| with |i|, |I|, |a|, |A| or | ||||||
| |:startinsert|. In this mode all keys except <C-\> are sent to the underlying | |:startinsert|. In this mode all keys except <C-\> are sent to the underlying | ||||||
| program. If <C-\> is pressed, the next key is sent unless it is <C-N>. Use | program. If <C-\> is pressed, the next key is sent unless it is <C-N> or <C-O>. | ||||||
| <C-\><C-N> to return to normal-mode. |CTRL-\_CTRL-N| | Use <C-\><C-N> to return to normal mode. |CTRL-\_CTRL-N| | ||||||
|  | Use <C-\><C-O> to execute one normal mode command and then return to terminal | ||||||
|  | mode. *t_CTRL-\_CTRL-O* | ||||||
|  |  | ||||||
| Terminal-mode forces these local options: | Terminal-mode forces these local options: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -239,7 +239,8 @@ g8			Print the hex values of the bytes used in the | |||||||
|  |  | ||||||
| 			Type |i| to enter |Terminal-mode|, then keys are sent to | 			Type |i| to enter |Terminal-mode|, then keys are sent to | ||||||
| 			the job running in the terminal. Type <C-\><C-N> to | 			the job running in the terminal. Type <C-\><C-N> to | ||||||
| 			leave Terminal-mode. |CTRL-\_CTRL-N| | 			leave Terminal-mode. |CTRL-\_CTRL-N|. Type <C-\><C-O> | ||||||
|  | 			to execute a single normal mode command |t_CTRL-\_CTRL-O| | ||||||
|  |  | ||||||
| 			Fails if changes have been made to the current buffer, | 			Fails if changes have been made to the current buffer, | ||||||
| 			unless 'hidden' is set. | 			unless 'hidden' is set. | ||||||
|   | |||||||
| @@ -1223,10 +1223,10 @@ bool edit(int cmdchar, bool startln, long count) | |||||||
|       // the value of `restart_edit` before `ex_normal` returns. |       // the value of `restart_edit` before `ex_normal` returns. | ||||||
|       restart_edit = 'i'; |       restart_edit = 'i'; | ||||||
|       force_restart_edit = true; |       force_restart_edit = true; | ||||||
|  |       return false; | ||||||
|     } else { |     } else { | ||||||
|       terminal_enter(); |       return terminal_enter(); | ||||||
|     } |     } | ||||||
|     return false; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Don't allow inserting in the sandbox. |   // Don't allow inserting in the sandbox. | ||||||
|   | |||||||
| @@ -6026,7 +6026,11 @@ int showmode(void) | |||||||
|           msg_puts_attr(_(" INSERT"), attr); |           msg_puts_attr(_(" INSERT"), attr); | ||||||
|         } else if (restart_edit == 'I' || restart_edit == 'i' |         } else if (restart_edit == 'I' || restart_edit == 'i' | ||||||
|                    || restart_edit == 'a' || restart_edit == 'A') { |                    || restart_edit == 'a' || restart_edit == 'A') { | ||||||
|           msg_puts_attr(_(" (insert)"), attr); |           if (curbuf->terminal) { | ||||||
|  |             msg_puts_attr(_(" (terminal)"), attr); | ||||||
|  |           } else { | ||||||
|  |             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') { | ||||||
|   | |||||||
| @@ -211,12 +211,15 @@ void get_mode(char *buf) | |||||||
|       buf[i++] = 'o'; |       buf[i++] = 'o'; | ||||||
|       // to be able to detect force-linewise/blockwise/charwise operations |       // to be able to detect force-linewise/blockwise/charwise operations | ||||||
|       buf[i++] = (char)motion_force; |       buf[i++] = (char)motion_force; | ||||||
|  |     } else if (curbuf->terminal) { | ||||||
|  |       buf[i++] = 't'; | ||||||
|  |       if (restart_edit == 'I') { | ||||||
|  |         buf[i++] = 'T'; | ||||||
|  |       } | ||||||
|     } else if (restart_edit == 'I' || restart_edit == 'R' |     } else if (restart_edit == 'I' || restart_edit == 'R' | ||||||
|                || restart_edit == 'V') { |                || restart_edit == 'V') { | ||||||
|       buf[i++] = 'i'; |       buf[i++] = 'i'; | ||||||
|       buf[i++] = (char)restart_edit; |       buf[i++] = (char)restart_edit; | ||||||
|     } else if (curbuf->terminal) { |  | ||||||
|       buf[i++] = 't'; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -82,6 +82,7 @@ typedef struct terminal_state { | |||||||
|   int save_rd;              // saved value of RedrawingDisabled |   int save_rd;              // saved value of RedrawingDisabled | ||||||
|   bool close; |   bool close; | ||||||
|   bool got_bsl;             // if the last input was <C-\> |   bool got_bsl;             // if the last input was <C-\> | ||||||
|  |   bool got_bsl_o;           // if left terminal mode with <c-\><c-o> | ||||||
| } TerminalState; | } TerminalState; | ||||||
|  |  | ||||||
| #ifdef INCLUDE_GENERATED_DECLARATIONS | #ifdef INCLUDE_GENERATED_DECLARATIONS | ||||||
| @@ -388,12 +389,11 @@ void terminal_check_size(Terminal *term) | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Implements MODE_TERMINAL state. :help Terminal-mode | /// Implements MODE_TERMINAL state. :help Terminal-mode | ||||||
| void terminal_enter(void) | bool terminal_enter(void) | ||||||
| { | { | ||||||
|   buf_T *buf = curbuf; |   buf_T *buf = curbuf; | ||||||
|   assert(buf->terminal);  // Should only be called when curbuf has a terminal. |   assert(buf->terminal);  // Should only be called when curbuf has a terminal. | ||||||
|   TerminalState state, *s = &state; |   TerminalState s[1] = { 0 }; | ||||||
|   memset(s, 0, sizeof(TerminalState)); |  | ||||||
|   s->term = buf->terminal; |   s->term = buf->terminal; | ||||||
|   stop_insert_mode = false; |   stop_insert_mode = false; | ||||||
|  |  | ||||||
| @@ -443,7 +443,9 @@ void terminal_enter(void) | |||||||
|   s->state.check = terminal_check; |   s->state.check = terminal_check; | ||||||
|   state_enter(&s->state); |   state_enter(&s->state); | ||||||
|  |  | ||||||
|   restart_edit = 0; |   if (!s->got_bsl_o) { | ||||||
|  |     restart_edit = 0; | ||||||
|  |   } | ||||||
|   State = save_state; |   State = save_state; | ||||||
|   RedrawingDisabled = s->save_rd; |   RedrawingDisabled = s->save_rd; | ||||||
|   apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf); |   apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf); | ||||||
| @@ -467,7 +469,11 @@ void terminal_enter(void) | |||||||
|   if (curbuf->terminal == s->term && !s->close) { |   if (curbuf->terminal == s->term && !s->close) { | ||||||
|     terminal_check_cursor(); |     terminal_check_cursor(); | ||||||
|   } |   } | ||||||
|   unshowmode(true); |   if (restart_edit) { | ||||||
|  |     showmode(); | ||||||
|  |   } else { | ||||||
|  |     unshowmode(true); | ||||||
|  |   } | ||||||
|   ui_busy_stop(); |   ui_busy_stop(); | ||||||
|   if (s->close) { |   if (s->close) { | ||||||
|     bool wipe = s->term->buf_handle != 0; |     bool wipe = s->term->buf_handle != 0; | ||||||
| @@ -477,6 +483,8 @@ void terminal_enter(void) | |||||||
|       do_cmdline_cmd("bwipeout!"); |       do_cmdline_cmd("bwipeout!"); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   return s->got_bsl_o; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void terminal_check_cursor(void) | static void terminal_check_cursor(void) | ||||||
| @@ -564,6 +572,14 @@ static int terminal_execute(VimState *state, int key) | |||||||
|     } |     } | ||||||
|     FALLTHROUGH; |     FALLTHROUGH; | ||||||
|  |  | ||||||
|  |   case Ctrl_O: | ||||||
|  |     if (s->got_bsl) { | ||||||
|  |       s->got_bsl_o = true; | ||||||
|  |       restart_edit = 'I'; | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     FALLTHROUGH; | ||||||
|  |  | ||||||
|   default: |   default: | ||||||
|     if (key == Ctrl_BSL && !s->got_bsl) { |     if (key == Ctrl_BSL && !s->got_bsl) { | ||||||
|       s->got_bsl = true; |       s->got_bsl = true; | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ local exc_exec = helpers.exc_exec | |||||||
| local matches = helpers.matches | local matches = helpers.matches | ||||||
| local exec_lua = helpers.exec_lua | local exec_lua = helpers.exec_lua | ||||||
| local sleep = helpers.sleep | local sleep = helpers.sleep | ||||||
|  | local funcs = helpers.funcs | ||||||
|  |  | ||||||
| describe(':terminal buffer', function() | describe(':terminal buffer', function() | ||||||
|   local screen |   local screen | ||||||
| @@ -300,6 +301,44 @@ describe(':terminal buffer', function() | |||||||
|     feed_command('put a')  -- register a is empty |     feed_command('put a')  -- register a is empty | ||||||
|     helpers.assert_alive() |     helpers.assert_alive() | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|  |   it([[can use temporary normal mode <c-\><c-o>]], function() | ||||||
|  |     eq('t', funcs.mode(1)) | ||||||
|  |     feed [[<c-\><c-o>]] | ||||||
|  |     screen:expect{grid=[[ | ||||||
|  |       tty ready                                         | | ||||||
|  |       {2:^ }                                                 | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |       {3:-- (terminal) --}                                  | | ||||||
|  |     ]]} | ||||||
|  |     eq('ntT', funcs.mode(1)) | ||||||
|  |  | ||||||
|  |     feed [[:let g:x = 17]] | ||||||
|  |     screen:expect{grid=[[ | ||||||
|  |       tty ready                                         | | ||||||
|  |       {2: }                                                 | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |       :let g:x = 17^                                     | | ||||||
|  |     ]]} | ||||||
|  |  | ||||||
|  |     feed [[<cr>]] | ||||||
|  |     screen:expect{grid=[[ | ||||||
|  |       tty ready                                         | | ||||||
|  |       {1: }                                                 | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |                                                         | | ||||||
|  |       {3:-- TERMINAL --}                                    | | ||||||
|  |     ]]} | ||||||
|  |     eq('t', funcs.mode(1)) | ||||||
|  |   end) | ||||||
| end) | end) | ||||||
|  |  | ||||||
| describe('No heap-buffer-overflow when using', function() | describe('No heap-buffer-overflow when using', function() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bfredl
					bfredl