mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
feat(terminal): TermClose: set exit code in v:event.status #15406
Closes #4713
This commit is contained in:
parent
599af74514
commit
50b30de200
@ -914,6 +914,8 @@ TermLeave After leaving |Terminal-mode|.
|
||||
After TermClose.
|
||||
*TermClose*
|
||||
TermClose When a |terminal| job ends.
|
||||
Sets these |v:event| keys:
|
||||
status
|
||||
*TermResponse*
|
||||
TermResponse After the response to t_RV is received from
|
||||
the terminal. The value of |v:termresponse|
|
||||
|
@ -1641,6 +1641,7 @@ v:event Dictionary of event data for the current |autocommand|. Valid
|
||||
|v:false| if not.
|
||||
changed_window Is |v:true| if the the event fired
|
||||
while changing window (or tab) on |DirChanged|.
|
||||
status Job status or exit code, -1 means "unknown". |TermClose|
|
||||
|
||||
*v:exception* *exception-variable*
|
||||
v:exception The value of the exception most recently caught and not
|
||||
|
@ -134,6 +134,10 @@ Example: >
|
||||
programs can set this by emitting an escape sequence.
|
||||
- |'channel'| Terminal PTY |job-id|. Can be used with |chansend()| to send
|
||||
input to the terminal.
|
||||
- The |TermClose| event gives the terminal job exit code in the |v:event|
|
||||
"status" field. For example, this autocmd closes terminal buffers if the job
|
||||
exited without error: >
|
||||
autocmd TermClose * if !v:event.status | exe 'bdelete! '..expand('<abuf>') | endif
|
||||
|
||||
Use |jobwait()| to check if the terminal job has finished: >
|
||||
let running = jobwait([&channel], 0)[0] == -1
|
||||
|
@ -532,7 +532,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
|
||||
}
|
||||
|
||||
if (buf->terminal) {
|
||||
terminal_close(buf->terminal, NULL);
|
||||
terminal_close(buf->terminal, -1);
|
||||
}
|
||||
|
||||
// Always remove the buffer when there is no file name.
|
||||
|
@ -698,9 +698,7 @@ static void channel_process_exit_cb(Process *proc, int status, void *data)
|
||||
{
|
||||
Channel *chan = data;
|
||||
if (chan->term) {
|
||||
char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
|
||||
snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status);
|
||||
terminal_close(chan->term, msg);
|
||||
terminal_close(chan->term, status);
|
||||
}
|
||||
|
||||
// If process did not exit, we only closed the handle of a detached process.
|
||||
|
@ -260,7 +260,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
|
||||
return rv;
|
||||
}
|
||||
|
||||
void terminal_close(Terminal *term, char *msg)
|
||||
void terminal_close(Terminal *term, int status)
|
||||
{
|
||||
if (term->closed) {
|
||||
return;
|
||||
@ -278,8 +278,8 @@ void terminal_close(Terminal *term, char *msg)
|
||||
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||
term->closed = true;
|
||||
|
||||
if (!msg || exiting) {
|
||||
// If no msg was given, this was called by close_buffer(buffer.c). Or if
|
||||
if (status == -1 || exiting) {
|
||||
// If status is -1, this was called by close_buffer(buffer.c). Or if
|
||||
// exiting, we must inform the buffer the terminal no longer exists so that
|
||||
// close_buffer() doesn't call this again.
|
||||
term->buf_handle = 0;
|
||||
@ -291,11 +291,16 @@ void terminal_close(Terminal *term, char *msg)
|
||||
term->opts.close_cb(term->opts.data);
|
||||
}
|
||||
} else {
|
||||
char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
|
||||
snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status);
|
||||
terminal_receive(term, msg, strlen(msg));
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
if (buf && !is_autocmd_blocked()) {
|
||||
dict_T *dict = get_vim_var_dict(VV_EVENT);
|
||||
tv_dict_add_nr(dict, S_LEN("status"), status);
|
||||
apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf);
|
||||
tv_dict_clear(dict);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ describe('autocmd TermClose', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
nvim('set_option', 'shell', nvim_dir .. '/shell-test')
|
||||
nvim('set_option', 'shellcmdflag', 'EXE')
|
||||
command('set shellcmdflag=EXE shellredir= shellpipe= shellquote= shellxquote=')
|
||||
end)
|
||||
|
||||
it('triggers when fast-exiting terminal job stops', function()
|
||||
@ -90,6 +90,17 @@ describe('autocmd TermClose', function()
|
||||
retry(nil, nil, function() eq('3', eval('g:abuf')) end)
|
||||
feed('<c-c>:qa!<cr>')
|
||||
end)
|
||||
|
||||
it('exposes v:event.status', function()
|
||||
command('set shellcmdflag=EXIT')
|
||||
command('autocmd TermClose * let g:status = v:event.status')
|
||||
|
||||
command('terminal 0')
|
||||
retry(nil, nil, function() eq(0, eval('g:status')) end)
|
||||
|
||||
command('terminal 42')
|
||||
retry(nil, nil, function() eq(42, eval('g:status')) end)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('autocmd TermEnter, TermLeave', function()
|
||||
|
@ -19,7 +19,7 @@ static void flush_wait(void)
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
puts("A simple implementation of a shell for testing termopen().");
|
||||
puts("Fake shell");
|
||||
puts("");
|
||||
puts("Usage:");
|
||||
puts(" shell-test --help");
|
||||
@ -42,6 +42,8 @@ static void help(void)
|
||||
puts(" 96: foo bar");
|
||||
puts(" shell-test INTERACT");
|
||||
puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input.");
|
||||
puts(" shell-test EXIT {code}");
|
||||
puts(" Exits immediately with exit code \"{code}\".");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@ -103,7 +105,6 @@ int main(int argc, char **argv)
|
||||
char input[256];
|
||||
char cmd[100];
|
||||
int arg;
|
||||
int input_argc;
|
||||
|
||||
while (1) {
|
||||
fprintf(stderr, "interact $ ");
|
||||
@ -112,8 +113,7 @@ int main(int argc, char **argv)
|
||||
break; // EOF
|
||||
}
|
||||
|
||||
input_argc = sscanf(input, "%99s %d", cmd, &arg);
|
||||
if(1 == input_argc) {
|
||||
if(1 == sscanf(input, "%99s %d", cmd, &arg)) {
|
||||
arg = 0;
|
||||
}
|
||||
if (strcmp(cmd, "exit") == 0) {
|
||||
@ -122,6 +122,15 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "command not found: %s\n", cmd);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(argv[1], "EXIT") == 0) {
|
||||
int code = 1;
|
||||
if (argc >= 3) {
|
||||
if (sscanf(argv[2], "%d", &code) != 1) {
|
||||
fprintf(stderr, "Invalid exit code: %s\n", argv[2]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown first argument: %s\n", argv[1]);
|
||||
return 3;
|
||||
|
Loading…
Reference in New Issue
Block a user