From 5ed9e1b356799006fecacb3734e4025a034fde60 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 27 Jun 2021 16:33:34 +1000 Subject: [PATCH] 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. --- src/shell_manager.cc | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 298412b7..e53d4d5c 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -321,34 +321,43 @@ std::pair ShellManager::eval( int status = 0; // check for termination now that SIGCHLD is blocked bool terminated = waitpid(pid, &status, WNOHANG) != 0; + bool failed = false; using namespace std::chrono; static constexpr seconds wait_timeout{1}; Optional previous_status; - Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer) - { - auto wait_duration = Clock::now() - wait_time; - if (context.has_client()) - { - auto& client = context.client(); - if (not previous_status) - previous_status = client.current_status(); + Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer) { + if (not context.has_client()) + return; - client.print_status({ format("waiting for shell command to finish ({}s)", - duration_cast(wait_duration).count()), - context.faces()["Information"] }); - client.redraw_ifn(); - } - timer.set_next_date(Clock::now() + wait_timeout); + const auto now = Clock::now(); + timer.set_next_date(now + wait_timeout); + auto& client = context.client(); + if (not previous_status) + previous_status = client.current_status(); + + client.print_status({format("waiting for shell command to finish{} ({}s)", + terminated ? " (shell terminated)" : "", + duration_cast(now - wait_time).count()), + context.faces()[failed ? "Error" : "Information"]}); + client.redraw_ifn(); }, EventMode::Urgent}; while (not terminated or child_stdin.write_fd() != -1 or ((flags & Flags::WaitForStdout) and (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) - terminated = waitpid(pid, &status, WNOHANG) != 0; + terminated = waitpid(pid, &status, WNOHANG) == pid; } if (not stderr_contents.empty())