Catch errors while executing shell commands

Log error to debug buffer and Change the 'waiting for shell' face
to 'Error'.

Update the 'waiting for shell' message when the shell has exited
but Kakoune is still waiting on stdin/stdout/stderr to be closed.
This commit is contained in:
Maxime Coste 2021-06-27 16:33:34 +10:00
parent 2b68b6737c
commit 5ed9e1b356

View File

@ -321,34 +321,43 @@ std::pair<String, int> ShellManager::eval(
int status = 0; int status = 0;
// check for termination now that SIGCHLD is blocked // check for termination now that SIGCHLD is blocked
bool terminated = waitpid(pid, &status, WNOHANG) != 0; bool terminated = waitpid(pid, &status, WNOHANG) != 0;
bool failed = false;
using namespace std::chrono; using namespace std::chrono;
static constexpr seconds wait_timeout{1}; static constexpr seconds wait_timeout{1};
Optional<DisplayLine> previous_status; Optional<DisplayLine> previous_status;
Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer) Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer) {
{ if (not context.has_client())
auto wait_duration = Clock::now() - wait_time; return;
if (context.has_client())
{
auto& client = context.client();
if (not previous_status)
previous_status = client.current_status();
client.print_status({ format("waiting for shell command to finish ({}s)", const auto now = Clock::now();
duration_cast<seconds>(wait_duration).count()), timer.set_next_date(now + wait_timeout);
context.faces()["Information"] }); auto& client = context.client();
client.redraw_ifn(); if (not previous_status)
} previous_status = client.current_status();
timer.set_next_date(Clock::now() + wait_timeout);
client.print_status({format("waiting for shell command to finish{} ({}s)",
terminated ? " (shell terminated)" : "",
duration_cast<seconds>(now - wait_time).count()),
context.faces()[failed ? "Error" : "Information"]});
client.redraw_ifn();
}, EventMode::Urgent}; }, EventMode::Urgent};
while (not terminated or child_stdin.write_fd() != -1 or while (not terminated or child_stdin.write_fd() != -1 or
((flags & Flags::WaitForStdout) and ((flags & Flags::WaitForStdout) and
(child_stdout.read_fd() != -1 or child_stderr.read_fd() != -1))) (child_stdout.read_fd() != -1 or child_stderr.read_fd() != -1)))
{ {
EventManager::instance().handle_next_events(EventMode::Urgent, &orig_mask); try
{
EventManager::instance().handle_next_events(EventMode::Urgent, &orig_mask);
}
catch (runtime_error& error)
{
write_to_debug_buffer(format("error while waiting for shell: {}", error.what()));
failed = true;
}
if (not terminated) if (not terminated)
terminated = waitpid(pid, &status, WNOHANG) != 0; terminated = waitpid(pid, &status, WNOHANG) == pid;
} }
if (not stderr_contents.empty()) if (not stderr_contents.empty())