diff options
author | bfredl <bjorn.linse@gmail.com> | 2022-07-30 22:07:58 +0200 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2022-08-02 13:54:41 +0200 |
commit | 9092540315bef8a685a06825073d05c394bf6575 (patch) | |
tree | f3c6ad62ae0ad2133818949a06cbd39269129190 | |
parent | 0a049c322fda5f2bb124429086c2713ff99c7142 (diff) | |
download | rneovim-9092540315bef8a685a06825073d05c394bf6575.tar.gz rneovim-9092540315bef8a685a06825073d05c394bf6575.tar.bz2 rneovim-9092540315bef8a685a06825073d05c394bf6575.zip |
feat(terminal): implement <c-\><c-o> for terminal mode
this works similar to <c-o> or <c-\><c-o> in insert mode
-rw-r--r-- | runtime/doc/builtin.txt | 1 | ||||
-rw-r--r-- | runtime/doc/index.txt | 5 | ||||
-rw-r--r-- | runtime/doc/intro.txt | 5 | ||||
-rw-r--r-- | runtime/doc/nvim_terminal_emulator.txt | 6 | ||||
-rw-r--r-- | runtime/doc/various.txt | 3 | ||||
-rw-r--r-- | src/nvim/edit.c | 4 | ||||
-rw-r--r-- | src/nvim/screen.c | 6 | ||||
-rw-r--r-- | src/nvim/state.c | 7 | ||||
-rw-r--r-- | src/nvim/terminal.c | 26 | ||||
-rw-r--r-- | test/functional/terminal/buffer_spec.lua | 39 |
10 files changed, 86 insertions, 16 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index e2a8e098d2..61d04c6660 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -5311,6 +5311,7 @@ mode([expr]) Return a string that indicates the current mode. niV Normal using |i_CTRL-O| in |Virtual-Replace-mode| nt Normal in |terminal-emulator| (insert goes to Terminal mode) + ntT Normal using |t_CTRL-\_CTRL-O| in |terminal-mode| v Visual by character vs Visual by character using |v_CTRL-O| in Select mode V Visual by line diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 25b98ae4ab..7d8a89887a 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1101,8 +1101,11 @@ tag command action in Command-line editing mode ~ 5. Terminal mode *terminal-mode-index* 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 |t_CTRL-\_CTRL-O| to execute one normal mode command and then return +to terminal mode. You found it, Arthur! *holy-grail* diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index 92ba7b4079..ae80935032 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -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 the process running in the current |terminal| buffer. 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 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 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 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 diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index a7be9ff98f..546f92e92f 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -47,8 +47,10 @@ Input *terminal-input* 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 -program. If <C-\> is pressed, the next key is sent unless it is <C-N>. Use -<C-\><C-N> to return to normal-mode. |CTRL-\_CTRL-N| +program. If <C-\> is pressed, the next key is sent unless it is <C-N> or <C-O>. +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: diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 9eb6470962..cae9c76030 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -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 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, unless 'hidden' is set. diff --git a/src/nvim/edit.c b/src/nvim/edit.c index e7a8f81813..5861e4c52b 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1223,10 +1223,10 @@ bool edit(int cmdchar, bool startln, long count) // the value of `restart_edit` before `ex_normal` returns. restart_edit = 'i'; force_restart_edit = true; + return false; } else { - terminal_enter(); + return terminal_enter(); } - return false; } // Don't allow inserting in the sandbox. diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 80f6f75fea..0d3b936c48 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -6026,7 +6026,11 @@ int showmode(void) msg_puts_attr(_(" INSERT"), attr); } else if (restart_edit == 'I' || restart_edit == 'i' || 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') { msg_puts_attr(_(" (replace)"), attr); } else if (restart_edit == 'V') { diff --git a/src/nvim/state.c b/src/nvim/state.c index be8017ea83..d6cca71ad8 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -211,12 +211,15 @@ void get_mode(char *buf) buf[i++] = 'o'; // to be able to detect force-linewise/blockwise/charwise operations 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' || restart_edit == 'V') { buf[i++] = 'i'; buf[i++] = (char)restart_edit; - } else if (curbuf->terminal) { - buf[i++] = 't'; } } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index fc02d9d53a..c23aff00cb 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -82,6 +82,7 @@ typedef struct terminal_state { int save_rd; // saved value of RedrawingDisabled bool close; bool got_bsl; // if the last input was <C-\> + bool got_bsl_o; // if left terminal mode with <c-\><c-o> } TerminalState; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -388,12 +389,11 @@ void terminal_check_size(Terminal *term) } /// Implements MODE_TERMINAL state. :help Terminal-mode -void terminal_enter(void) +bool terminal_enter(void) { buf_T *buf = curbuf; assert(buf->terminal); // Should only be called when curbuf has a terminal. - TerminalState state, *s = &state; - memset(s, 0, sizeof(TerminalState)); + TerminalState s[1] = { 0 }; s->term = buf->terminal; stop_insert_mode = false; @@ -443,7 +443,9 @@ void terminal_enter(void) s->state.check = terminal_check; state_enter(&s->state); - restart_edit = 0; + if (!s->got_bsl_o) { + restart_edit = 0; + } State = save_state; RedrawingDisabled = s->save_rd; apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf); @@ -467,7 +469,11 @@ void terminal_enter(void) if (curbuf->terminal == s->term && !s->close) { terminal_check_cursor(); } - unshowmode(true); + if (restart_edit) { + showmode(); + } else { + unshowmode(true); + } ui_busy_stop(); if (s->close) { bool wipe = s->term->buf_handle != 0; @@ -477,6 +483,8 @@ void terminal_enter(void) do_cmdline_cmd("bwipeout!"); } } + + return s->got_bsl_o; } static void terminal_check_cursor(void) @@ -564,6 +572,14 @@ static int terminal_execute(VimState *state, int key) } FALLTHROUGH; + case Ctrl_O: + if (s->got_bsl) { + s->got_bsl_o = true; + restart_edit = 'I'; + return 0; + } + FALLTHROUGH; + default: if (key == Ctrl_BSL && !s->got_bsl) { s->got_bsl = true; diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index ec3066c20d..23430a620b 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -13,6 +13,7 @@ local exc_exec = helpers.exc_exec local matches = helpers.matches local exec_lua = helpers.exec_lua local sleep = helpers.sleep +local funcs = helpers.funcs describe(':terminal buffer', function() local screen @@ -300,6 +301,44 @@ describe(':terminal buffer', function() feed_command('put a') -- register a is empty helpers.assert_alive() 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) describe('No heap-buffer-overflow when using', function() |