From afb4c447b4e94a70b80209124d71eb0c512be464 Mon Sep 17 00:00:00 2001 From: Itamar Date: Fri, 7 Jan 2022 16:28:56 +0200 Subject: [PATCH] HackStudio: Add optional parameters to TerminalWrapper::run() The optional parameters allow specifying a working directory and controlling whether or not to block until the command returns. --- .../DevTools/HackStudio/TerminalWrapper.cpp | 30 +++++++++++++++++-- .../DevTools/HackStudio/TerminalWrapper.h | 10 +++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Userland/DevTools/HackStudio/TerminalWrapper.cpp b/Userland/DevTools/HackStudio/TerminalWrapper.cpp index 1d1fd6433d..e820c359c5 100644 --- a/Userland/DevTools/HackStudio/TerminalWrapper.cpp +++ b/Userland/DevTools/HackStudio/TerminalWrapper.cpp @@ -7,6 +7,7 @@ #include "TerminalWrapper.h" #include #include +#include #include #include #include @@ -22,7 +23,7 @@ namespace HackStudio { -void TerminalWrapper::run_command(const String& command) +void TerminalWrapper::run_command(const String& command, Optional working_directory, WaitForExit wait_for_exit) { if (m_pid != -1) { GUI::MessageBox::show(window(), @@ -39,6 +40,8 @@ void TerminalWrapper::run_command(const String& command) } int ptm_fd = ptm_res.value(); + m_child_exited = false; + m_child_exit_status.clear(); m_pid = fork(); if (m_pid < 0) { @@ -46,8 +49,21 @@ void TerminalWrapper::run_command(const String& command) return; } - if (m_pid > 0) + if (m_pid > 0) { + if (wait_for_exit == WaitForExit::Yes) { + GUI::Application::the()->event_loop().spin_until([this]() { + return m_child_exited; + }); + } return; + } + + if (working_directory.has_value()) { + if (chdir(working_directory->characters())) { + perror("chdir"); + exit(1); + } + } if (setup_slave_pseudoterminal(ptm_fd).is_error()) { perror("setup_pseudoterminal"); @@ -93,6 +109,7 @@ ErrorOr TerminalWrapper::setup_master_pseudoterminal(WaitForChildOnExit wai perror("waitpid"); VERIFY_NOT_REACHED(); } + if (WIFEXITED(wstatus)) { m_terminal_widget->inject_string(String::formatted("\033[{};1m(Command exited with code {})\033[0m\r\n", wstatus == 0 ? 32 : 31, WEXITSTATUS(wstatus))); } else if (WIFSTOPPED(wstatus)) { @@ -100,6 +117,9 @@ ErrorOr TerminalWrapper::setup_master_pseudoterminal(WaitForChildOnExit wai } else if (WIFSIGNALED(wstatus)) { m_terminal_widget->inject_string(String::formatted("\033[34;1m(Command signaled with {}!)\033[0m\r\n", strsignal(WTERMSIG(wstatus)))); } + + m_child_exit_status = WEXITSTATUS(wstatus); + m_child_exited = true; } m_pid = -1; @@ -187,4 +207,10 @@ TerminalWrapper::~TerminalWrapper() { } +int TerminalWrapper::child_exit_status() const +{ + VERIFY(m_child_exit_status.has_value()); + return m_child_exit_status.value(); +} + } diff --git a/Userland/DevTools/HackStudio/TerminalWrapper.h b/Userland/DevTools/HackStudio/TerminalWrapper.h index 9918f9335b..a2636fb844 100644 --- a/Userland/DevTools/HackStudio/TerminalWrapper.h +++ b/Userland/DevTools/HackStudio/TerminalWrapper.h @@ -16,8 +16,11 @@ class TerminalWrapper final : public GUI::Widget { C_OBJECT(TerminalWrapper) public: virtual ~TerminalWrapper() override; - - void run_command(const String&); + enum class WaitForExit { + No, + Yes + }; + void run_command(const String&, Optional working_directory = {}, WaitForExit = WaitForExit::No); void kill_running_command(); void clear_including_history(); @@ -30,6 +33,7 @@ public: }; ErrorOr setup_master_pseudoterminal(WaitForChildOnExit = WaitForChildOnExit::Yes); static ErrorOr setup_slave_pseudoterminal(int master_fd); + int child_exit_status() const; Function on_command_exit; @@ -39,6 +43,8 @@ private: RefPtr m_terminal_widget; pid_t m_pid { -1 }; bool m_user_spawned { true }; + bool m_child_exited { false }; + Optional m_child_exit_status; }; }