mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 20:08:17 +00:00
Merge #15402 fix(terminal): close without ! if the job is stopped
This commit is contained in:
@@ -13,7 +13,7 @@ from the connected program.
|
|||||||
Terminal buffers behave like normal buffers, except:
|
Terminal buffers behave like normal buffers, except:
|
||||||
- With 'modifiable', lines can be edited but not deleted.
|
- With 'modifiable', lines can be edited but not deleted.
|
||||||
- 'scrollback' controls how many lines are kept.
|
- 'scrollback' controls how many lines are kept.
|
||||||
- Output is followed if the cursor is on the last line.
|
- Output is followed ("tailed") if cursor is on the last line.
|
||||||
- 'modified' is the default. You can set 'nomodified' to avoid a warning when
|
- 'modified' is the default. You can set 'nomodified' to avoid a warning when
|
||||||
closing the terminal buffer.
|
closing the terminal buffer.
|
||||||
- 'bufhidden' defaults to "hide".
|
- 'bufhidden' defaults to "hide".
|
||||||
|
@@ -1218,8 +1218,8 @@ do_buffer(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!forceit && (buf->terminal || bufIsChanged(buf))) {
|
if (!forceit && bufIsChanged(buf)) {
|
||||||
if ((p_confirm || cmdmod.confirm) && p_write && !buf->terminal) {
|
if ((p_confirm || cmdmod.confirm) && p_write) {
|
||||||
dialog_changed(buf, false);
|
dialog_changed(buf, false);
|
||||||
if (!bufref_valid(&bufref)) {
|
if (!bufref_valid(&bufref)) {
|
||||||
// Autocommand deleted buffer, oops! It's not changed now.
|
// Autocommand deleted buffer, oops! It's not changed now.
|
||||||
@@ -1231,22 +1231,22 @@ do_buffer(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (buf->terminal) {
|
EMSGN(_("E89: No write since last change for buffer %" PRId64
|
||||||
if (p_confirm || cmdmod.confirm) {
|
" (add ! to override)"),
|
||||||
if (!dialog_close_terminal(buf)) {
|
buf->b_fnum);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
EMSG2(_("E89: %s will be killed (add ! to override)"),
|
|
||||||
(char *)buf->b_fname);
|
if (!forceit && buf->terminal && terminal_running(buf->terminal)) {
|
||||||
return FAIL;
|
if (p_confirm || cmdmod.confirm) {
|
||||||
}
|
if (!dialog_close_terminal(buf)) {
|
||||||
} else {
|
|
||||||
EMSGN(_("E89: No write since last change for buffer %" PRId64
|
|
||||||
" (add ! to override)"),
|
|
||||||
buf->b_fnum);
|
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
EMSG2(_("E89: %s will be killed (add ! to override)"),
|
||||||
|
(char *)buf->b_fname);
|
||||||
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5404,14 +5404,19 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
TV_LIST_ITER_CONST(args, arg, {
|
TV_LIST_ITER_CONST(args, arg, {
|
||||||
Channel *chan = NULL;
|
Channel *chan = NULL;
|
||||||
if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER
|
if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER
|
||||||
|| !(chan = find_job(TV_LIST_ITEM_TV(arg)->vval.v_number, false))) {
|
|| !(chan = find_channel(TV_LIST_ITEM_TV(arg)->vval.v_number))
|
||||||
|
|| chan->streamtype != kChannelStreamProc) {
|
||||||
|
jobs[i] = NULL; // Invalid job.
|
||||||
|
} else if (process_is_stopped(&chan->stream.proc)) {
|
||||||
|
// Job is stopped but not fully destroyed.
|
||||||
|
// Ensure all callbacks on its event queue are executed. #15402
|
||||||
|
process_wait(&chan->stream.proc, -1, NULL);
|
||||||
jobs[i] = NULL; // Invalid job.
|
jobs[i] = NULL; // Invalid job.
|
||||||
} else {
|
} else {
|
||||||
jobs[i] = chan;
|
jobs[i] = chan;
|
||||||
channel_incref(chan);
|
channel_incref(chan);
|
||||||
if (chan->stream.proc.status < 0) {
|
if (chan->stream.proc.status < 0) {
|
||||||
// Process any pending events on the job's queue before temporarily
|
// Flush any events in the job's queue before temporarily replacing it.
|
||||||
// replacing it.
|
|
||||||
multiqueue_process_events(chan->events);
|
multiqueue_process_events(chan->events);
|
||||||
multiqueue_replace_parent(chan->events, waiting_jobs);
|
multiqueue_replace_parent(chan->events, waiting_jobs);
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@ local eq, neq = helpers.eq, helpers.neq
|
|||||||
local write_file = helpers.write_file
|
local write_file = helpers.write_file
|
||||||
local command= helpers.command
|
local command= helpers.command
|
||||||
local exc_exec = helpers.exc_exec
|
local exc_exec = helpers.exc_exec
|
||||||
|
local matches = helpers.matches
|
||||||
|
|
||||||
describe(':terminal buffer', function()
|
describe(':terminal buffer', function()
|
||||||
local screen
|
local screen
|
||||||
@@ -255,8 +256,23 @@ describe(':terminal buffer', function()
|
|||||||
command('bdelete!')
|
command('bdelete!')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('handles wqall', function()
|
it('requires bang (!) to close a running job #15402', function()
|
||||||
eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
|
eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
|
||||||
|
for _, cmd in ipairs({ 'bdelete', '%bdelete', 'bwipeout', 'bunload' }) do
|
||||||
|
matches('^Vim%('..cmd:gsub('%%', '')..'%):E89: term://.*tty%-test.* will be killed %(add %! to override%)$',
|
||||||
|
exc_exec(cmd))
|
||||||
|
end
|
||||||
|
command('call jobstop(&channel)')
|
||||||
|
assert(0 >= eval('jobwait([&channel], 1000)[0]'))
|
||||||
|
command('bdelete')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('stops running jobs with :quit', function()
|
||||||
|
-- Open in a new window to avoid terminating the nvim instance
|
||||||
|
command('split')
|
||||||
|
command('terminal')
|
||||||
|
command('set nohidden')
|
||||||
|
command('quit')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('does not segfault when pasting empty buffer #13955', function()
|
it('does not segfault when pasting empty buffer #13955', function()
|
||||||
|
Reference in New Issue
Block a user