Do not throw SIGINT after catching SIGINT signal (#128)

This fixes:
https://github.com/ArthurSonzogni/FTXUI/issues/117
This commit is contained in:
Arthur Sonzogni 2021-06-26 00:42:08 +02:00 committed by GitHub
parent 1fc86d31db
commit 93922f102f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 12 deletions

View File

@ -226,6 +226,7 @@ if (FTXUI_BUILD_TESTS AND ${CMAKE_VERSION} VERSION_GREATER "3.11.4")
src/ftxui/component/input_test.cpp src/ftxui/component/input_test.cpp
src/ftxui/component/radiobox_test.cpp src/ftxui/component/radiobox_test.cpp
src/ftxui/component/receiver_test.cpp src/ftxui/component/receiver_test.cpp
src/ftxui/component/screen_interactive_test.cpp
src/ftxui/component/terminal_input_parser_test.cpp src/ftxui/component/terminal_input_parser_test.cpp
src/ftxui/component/toggle_test.cpp src/ftxui/component/toggle_test.cpp
src/ftxui/dom/gauge_test.cpp src/ftxui/dom/gauge_test.cpp

View File

@ -1,7 +1,8 @@
#include <stdio.h> // for fileno, stdin #include <stdio.h> // for fileno, stdin
#include <algorithm> // for copy, max, min #include <algorithm> // for copy, max, min
#include <csignal> // for signal, SIGINT, SIGWINCH #include <csignal> // for signal, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, SIGWINCH
#include <cstdlib> // for exit, NULL #include <cstdlib> // for NULL
#include <initializer_list> // for initializer_list
#include <iostream> // for cout, ostream, basic_ostream, operator<<, endl, flush #include <iostream> // for cout, ostream, basic_ostream, operator<<, endl, flush
#include <stack> // for stack #include <stack> // for stack
#include <thread> // for thread #include <thread> // for thread
@ -12,7 +13,7 @@
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/event.hpp" // for Event #include "ftxui/component/event.hpp" // for Event
#include "ftxui/component/mouse.hpp" // for Mouse #include "ftxui/component/mouse.hpp" // for Mouse
#include "ftxui/component/receiver.hpp" // for ReceiverImpl, SenderImpl, MakeReceiver #include "ftxui/component/receiver.hpp" // for ReceiverImpl, MakeReceiver, Sender, SenderImpl, Receiver
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputParser #include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputParser
#include "ftxui/dom/node.hpp" // for Node, Render #include "ftxui/dom/node.hpp" // for Node, Render
@ -31,8 +32,8 @@
#endif #endif
#else #else
#include <sys/select.h> // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set #include <sys/select.h> // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set
#include <termios.h> // for tcsetattr, tcgetattr, cc_t #include <termios.h> // for tcsetattr, termios, tcgetattr, TCSANOW, cc_t, ECHO, ICANON, VMIN, VTIME
#include <unistd.h> // for STDIN_FILENO, read #include <unistd.h> // for STDIN_FILENO, read
#endif #endif
// Quick exit is missing in standard CLang headers // Quick exit is missing in standard CLang headers
@ -201,12 +202,11 @@ const std::string DeviceStatusReport(DSRMode ps) {
using SignalHandler = void(int); using SignalHandler = void(int);
std::stack<std::function<void()>> on_exit_functions; std::stack<std::function<void()>> on_exit_functions;
void OnExit(int signal) { void OnExit(int signal) {
(void)signal;
while (!on_exit_functions.empty()) { while (!on_exit_functions.empty()) {
on_exit_functions.top()(); on_exit_functions.top()();
on_exit_functions.pop(); on_exit_functions.pop();
} }
if (signal)
std::raise(signal);
} }
auto install_signal_handler = [](int sig, SignalHandler handler) { auto install_signal_handler = [](int sig, SignalHandler handler) {
@ -279,12 +279,12 @@ CapturedMouse ScreenInteractive::CaptureMouse() {
void ScreenInteractive::Loop(Component component) { void ScreenInteractive::Loop(Component component) {
on_exit_functions.push([this] { ExitLoopClosure()(); }); on_exit_functions.push([this] { ExitLoopClosure()(); });
// Install a SIGINT handler and restore the old handler on exit. // Install signal handlers to restore the terminal state on exit. The default
auto old_sigint_handler = std::signal(SIGINT, OnExit); // signal handlers are restored on exit.
on_exit_functions.push( for (int signal : {SIGTERM, SIGSEGV, SIGINT, SIGILL, SIGABRT, SIGFPE})
[old_sigint_handler]() { std::signal(SIGINT, old_sigint_handler); }); install_signal_handler(signal, OnExit);
// Save the old terminal configuration and restore it on exit. // Save the old terminal configuration and restore it on exit.
#if defined(_WIN32) #if defined(_WIN32)
// Enable VT processing on stdout and stdin // Enable VT processing on stdout and stdin
auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);

View File

@ -0,0 +1,52 @@
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult
#include <csignal>
#include "ftxui/component/component.hpp"
#include "ftxui/component/screen_interactive.hpp"
#include "ftxui/dom/elements.hpp"
#include "gtest/gtest_pred_impl.h" // for AssertionResult, Test, EXPECT_EQ
using namespace ftxui;
namespace {
bool TestSignal(int signal) {
int called = 0;
// The tree of components. This defines how to navigate using the keyboard.
auto component = Renderer([&] {
called++;
std::raise(signal);
called++;
return text(L"");
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component);
EXPECT_EQ(called, 2);
return true;
}
} // namespace
TEST(ScreenInteractive, Signal_SIGTERM) {
TestSignal(SIGTERM);
}
TEST(ScreenInteractive, Signal_SIGSEGV) {
TestSignal(SIGSEGV);
}
TEST(ScreenInteractive, Signal_SIGINT) {
TestSignal(SIGINT);
}
TEST(ScreenInteractive, Signal_SIGILL) {
TestSignal(SIGILL);
}
TEST(ScreenInteractive, Signal_SIGABRT) {
TestSignal(SIGABRT);
}
TEST(ScreenInteractive, Signal_SIGFPE) {
TestSignal(SIGFPE);
}
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.