mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(terminal): interrupt/got_int hangs terminal (#30056)
Upon `terminal_enter`, `mapped_ctrl_c` is set in order to avoid `CTRL-C` interrupts (which is proxied to the terminal process instead), `os_inchar` will then test `mapped_ctrl_c` against `State` and set `ctrl_c_interrupts=false` which prevents `process_ctrl_c` from setting `got_int=true` in a terminal state. However, if `got_int` is set outside of `process_ctrl_c`, e.g. via `interrupt()`, this will hang the neovim process as `terminal_execute` will enter an endless loop as `got_int` will never be cleared causing `safe_vgetc` to always return `Ctrl_C`. A minimal example reproducing this bug: ```vim :autocmd TermEnter * call timer_start(500, {-> interrupt()}) :terminal :startinsert ``` To fix, we make sure `got_int` is cleared inside `terminal_execute` when it detects `Ctrl_C`. Closes #20726 Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
parent
169f37b94f
commit
1d11808bfd
@ -782,6 +782,12 @@ static int terminal_execute(VimState *state, int key)
|
|||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (key == Ctrl_C) {
|
||||||
|
// terminal_enter() always sets `mapped_ctrl_c` to avoid `got_int`. 8eeda7169aa4
|
||||||
|
// But `got_int` may be set elsewhere, e.g. by interrupt() or an autocommand,
|
||||||
|
// so ensure that it is cleared.
|
||||||
|
got_int = false;
|
||||||
|
}
|
||||||
if (key == Ctrl_BSL && !s->got_bsl) {
|
if (key == Ctrl_BSL && !s->got_bsl) {
|
||||||
s->got_bsl = true;
|
s->got_bsl = true;
|
||||||
break;
|
break;
|
||||||
|
@ -312,6 +312,16 @@ describe(':terminal buffer', function()
|
|||||||
pcall_err(command, 'write test/functional/fixtures/tty-test.c')
|
pcall_err(command, 'write test/functional/fixtures/tty-test.c')
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('external interrupt (got_int) does not hang #20726', function()
|
||||||
|
eq({ mode = 't', blocking = false }, api.nvim_get_mode())
|
||||||
|
command('call timer_start(0, {-> interrupt()})')
|
||||||
|
feed('<Ignore>') -- Add input to separate two RPC requests
|
||||||
|
eq({ mode = 't', blocking = false }, api.nvim_get_mode())
|
||||||
|
feed([[<C-\><C-N>]])
|
||||||
|
eq({ mode = 'nt', blocking = false }, api.nvim_get_mode())
|
||||||
|
command('bd!')
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe(':terminal buffer', function()
|
describe(':terminal buffer', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user