From 9f2b991331f1c1734fa3be88ea3af195e2a5d801 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 9 Jan 2026 07:36:47 +0800 Subject: [PATCH] vim-patch:9.1.2066: :wqall! doesn't close a terminal like :qall! does (#37314) Problem: :wqall! doesn't close a terminal buffer like :qall! does (after 8.0.1525). Solution: Check eap->forceit (zeertzjq). Ref: https://github.com/vim/vim/issues/2654#issuecomment-366803932 related: vim/vim#2654 related: neovim/neovim#14061 closes: vim/vim#19129 https://github.com/vim/vim/commit/d8558fdf4f2758163218289637e82c3ae2d617ec (cherry picked from commit 681d00654998baf2a743602e513062cf876f107b) --- src/nvim/buffer.c | 21 ++++++++++++++++----- src/nvim/errors.h | 5 +++++ src/nvim/ex_cmds.c | 4 ++-- test/functional/terminal/buffer_spec.lua | 6 +++++- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index e6e99465c1..a10ba3c176 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1350,7 +1350,7 @@ static int do_buffer_ext(int action, int start, int dir, int count, int flags) return FAIL; } } else { - semsg(_("E89: No write since last change for buffer %d (add ! to override)"), + semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), buf->b_fnum); return FAIL; } @@ -1806,13 +1806,24 @@ void do_autochdir(void) } } +void no_write_message_buf(buf_T *buf) +{ + if (buf->terminal + && channel_job_running((uint64_t)buf->b_p_channel)) { + emsg(_(e_job_still_running_add_bang_to_end_the_job)); + } else { + semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), + buf->b_fnum); + } +} + void no_write_message(void) { if (curbuf->terminal && channel_job_running((uint64_t)curbuf->b_p_channel)) { - emsg(_("E948: Job still running (add ! to end the job)")); + emsg(_(e_job_still_running_add_bang_to_end_the_job)); } else { - emsg(_("E37: No write since last change (add ! to override)")); + emsg(_(e_no_write_since_last_change_add_bang_to_override)); } } @@ -1821,9 +1832,9 @@ void no_write_message_nobang(const buf_T *const buf) { if (buf->terminal && channel_job_running((uint64_t)buf->b_p_channel)) { - emsg(_("E948: Job still running")); + emsg(_(e_job_still_running)); } else { - emsg(_("E37: No write since last change")); + emsg(_(e_no_write_since_last_change)); } } diff --git a/src/nvim/errors.h b/src/nvim/errors.h index 69c3cd1bea..5be692b79c 100644 --- a/src/nvim/errors.h +++ b/src/nvim/errors.h @@ -129,9 +129,14 @@ EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); +EXTERN const char e_no_write_since_last_change[] INIT(= N_("E37: No write since last change")); +EXTERN const char e_no_write_since_last_change_add_bang_to_override[] INIT(= N_("E37: No write since last change (add ! to override)")); +EXTERN const char e_no_write_since_last_change_for_buffer_nr_add_bang_to_override[] INIT(= N_("E89: No write since last change for buffer %d (add ! to override)")); EXTERN const char e_buffer_nr_not_found[] INIT(= N_("E92: Buffer %d not found")); EXTERN const char e_unknown_function_str[] INIT(= N_("E117: Unknown function: %s")); EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); +EXTERN const char e_job_still_running[] INIT(= N_("E948: Job still running")); +EXTERN const char e_job_still_running_add_bang_to_end_the_job[] INIT(= N_("E948: Job still running (add ! to end the job)")); EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index e402779137..64210d8b83 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1887,10 +1887,10 @@ void do_wqall(exarg_T *eap) } FOR_ALL_BUFFERS(buf) { - if (exiting + if (exiting && !eap->forceit && buf->terminal && channel_job_running((uint64_t)buf->b_p_channel)) { - no_write_message_nobang(buf); + no_write_message_buf(buf); error++; } else if (!bufIsChanged(buf) || bt_dontwrite(buf)) { continue; diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index f24fa3ac11..5907903162 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -243,7 +243,7 @@ describe(':terminal buffer', function() it('requires bang (!) to close a running job #15402', function() skip(is_os('win'), 'Test freezes the CI and makes it time out') - eq('Vim(wqall):E948: Job still running', exc_exec('wqall')) + eq('Vim(wqall):E948: Job still running (add ! to end the job)', exc_exec('wqall')) for _, cmd in ipairs({ 'bdelete', '%bdelete', 'bwipeout', 'bunload' }) do matches( '^Vim%(' @@ -257,6 +257,10 @@ describe(':terminal buffer', function() command('bdelete') end) + it(':wqall! closes a running job', function() + n.expect_exit(command, 'wqall!') + end) + it('stops running jobs with :quit', function() -- Open in a new window to avoid terminating the nvim instance command('split')