It would be great if each terminal object had an exitCode property that will resolve to the actual exit code of the process. Something like this:
Terminal {
exitCode: Thenable<number>
}
It would be especially useful when running commands in the terminal dynamically from extensions, this way we could easily detect when the terminal exited and if it the command exited without errors.
(Experimental duplicate detection)
Thanks for submitting this issue. Please also check if it is already covered by an existing one, like:
The upcoming Angular Console VS Code extension (https://angularconsole.com/) would greatly benefit from the addition of this API. Without it, we are forced to run commands and echo a message after wards to indicate the exit code and screen scrap the terminal to get it.
I'm not sure we would want a Thenable on the API for this as that's what onDidCloseTerminal is for. Maybe this?
class Terminal {
/**
* The exit code of the terminal process, if the process has not yet
* exited the value will be -1.
*/
exitCode: number
}
I'll bring it up in an upcoming API meeting so I can open this up to PRs.
@Tyriar To give some more context the use-case I've encountered the most is: being able to execute a command in a newly created terminal, closing it immediately after that and knowing if the command succeeded and what the output was.
I think currently most of this can be achieved reasonably easily via APIs, but retrieving the exit code is still a pain point.
Also if the proposed API were to be implemented, how would that work, should I execute my commands like so to retrieve the exit code?:
( my-command && exit $? ) || exit $?
@fabiospampinato you would run the command inside a shell: bash -c my-command
@Tyriar I'm not sure I'm following, aren't all terminal commands run inside a shell? Don't we have to explicitly exit it to get an exit code via Terminal#exitCode?
@fabiospampinato you'll need to do bash -c if you want to change the shell/shellArgs, you could also run exit as you suggest if you're using the configured shell via sendText. The latter comes with some significant downsides in that syntax for doing this differs between shells so it might not work on the user's config.
@Tyriar Thanks for the explanation. Is this ergonomic enough though? I imagine things will get unpleasant quickly if each extension author has to think about what shell is available where and what's each shell's syntax for executing a command 馃
I would be great if there was an official API that abstracts all this complexity away, at least for the most popular shells, so that we could just write something like:
const {output, exitCode} = await Terminal.execAndExit ( command, TerminalOptions );
@fabiospampinato well that's basically what the tasks API is meant to do. I'm beginning to think maybe we shouldn't have this API for this reason.
The tasks API doesn't expose Stdout though. The use case in which you want to have access to stdout and an exit code is not supported by either api right now
Proposal:
export interface Terminal {
/**
* The exit code of the terminal process, this will be undefined when the process was killed by
* the user or no exit code was specified (for example when using CustomExecution).
*/
readonly exitCode: Thenable<number | undefined>;
}
Adding to October to discuss, it won't happen in October though.
Discussed at the API meeting today and we ended up landing on this:
export interface TerminalExitStatus {
/**
* The exit code that a terminal exited with, it can have the following values:
* - Zero: the terminal process or custom execution succeeded.
* - Non-zero: the terminal process or custom execution failed.
* - `undefined`: the user forcefully closed the terminal or a custom execution exited without
* providing an exit code.
*/
code: number | undefined;
}
export interface Terminal {
/**
* The exit status of the terminal, this will be undefined while the terminal is active.
*
* TODO: Add an example here using onDidCloseTerminal
*/
exitStatus: TerminalExitStatus | undefined;
}
That way there's a single async listener for exit in onDidCloseTerminal and exitStatus can be fetched during that event:
window.onDidCloseTerminal(t => {
console.log('exit status', t.exitStatus!.code);
});
We should use readonly for exitStatus/code
This will be available for testing in the first 1.41 insiders (probably 1-2 days away), let me know how it goes. FYI @eamodio
The plan is to promote this to stable for December, any feedback/validation in the meantime would be appreciated.
Has anyone validated that this is working as expected? I'll hold off finalizing until I get some confirmation.
Most helpful comment
This will be available for testing in the first 1.41 insiders (probably 1-2 days away), let me know how it goes. FYI @eamodio