From b7b6a487558c97d477ba14feaa7207ed2a3f8831 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 3 Aug 2025 11:49:14 +0200 Subject: [PATCH] Update --- .bazelrc | 2 + BUILD.bazel | 12 +- CMakeLists.txt | 7 - bazel/ftxui.bzl | 10 - cmake/ftxui_set_options.cmake | 1 - cmake/ftxui_test.cmake | 1 - examples/CMakeLists.txt | 4 - examples/component/homescreen.cpp | 33 ++- examples/index.mjs | 7 +- include/ftxui/component/receiver.hpp | 9 + .../ftxui/component/screen_interactive.hpp | 4 - src/ftxui/component/receiver.cppm | 6 + src/ftxui/component/receiver_test.cpp | 81 ------- src/ftxui/component/screen_interactive.cpp | 213 ++++++++++-------- src/ftxui/core/task.hpp | 6 +- 15 files changed, 163 insertions(+), 233 deletions(-) delete mode 100644 src/ftxui/component/receiver_test.cpp diff --git a/.bazelrc b/.bazelrc index bd86ad56a..240fd4c83 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,5 @@ +common --enable_bzlmod + build --features=layering_check build --enable_bzlmod diff --git a/BUILD.bazel b/BUILD.bazel index 5dfb8c13f..a5419d25d 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -13,7 +13,6 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load(":bazel/ftxui.bzl", "ftxui_cc_library") load(":bazel/ftxui.bzl", "generate_examples") load(":bazel/ftxui.bzl", "windows_copts") -load(":bazel/ftxui.bzl", "pthread_linkopts") # A meta target depending on all of the ftxui submodules. # Note that component depends on dom and screen, so ftxui is just an alias for @@ -164,6 +163,15 @@ ftxui_cc_library( "src/ftxui/component/util.cpp", "src/ftxui/component/window.cpp", + # Core + "src/ftxui/core/task.cpp", + "src/ftxui/core/task.hpp", + "src/ftxui/core/task_queue.cpp", + "src/ftxui/core/task_queue.hpp", + "src/ftxui/core/task_runner.cpp", + "src/ftxui/core/task_runner.hpp", + + # Private header from ftxui:dom. "src/ftxui/dom/node_decorator.hpp", @@ -184,7 +192,6 @@ ftxui_cc_library( "include/ftxui/component/screen_interactive.hpp", "include/ftxui/component/task.hpp", ], - linkopts = pthread_linkopts(), deps = [ ":dom", ":screen", @@ -207,7 +214,6 @@ cc_test( "src/ftxui/component/menu_test.cpp", "src/ftxui/component/modal_test.cpp", "src/ftxui/component/radiobox_test.cpp", - "src/ftxui/component/receiver_test.cpp", "src/ftxui/component/resizable_split_test.cpp", "src/ftxui/component/slider_test.cpp", "src/ftxui/component/terminal_input_parser_test.cpp", diff --git a/CMakeLists.txt b/CMakeLists.txt index 7424a40a4..d7d6eb3ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,13 +159,6 @@ add_library(component target_link_libraries(dom PUBLIC screen) target_link_libraries(component PUBLIC dom) -if (NOT EMSCRIPTEN) - find_package(Threads) - target_link_libraries(component - PUBLIC Threads::Threads - ) -endif() - include(cmake/ftxui_set_options.cmake) ftxui_set_options(screen) ftxui_set_options(dom) diff --git a/bazel/ftxui.bzl b/bazel/ftxui.bzl index e0de2e815..2be26a5e3 100644 --- a/bazel/ftxui.bzl +++ b/bazel/ftxui.bzl @@ -43,16 +43,6 @@ def windows_copts(): "//conditions:default": [], }) -def pthread_linkopts(): - return select({ - # With MSVC, threading is already built-in (you don't need -pthread. - "@rules_cc//cc/compiler:msvc-cl": [], - "@rules_cc//cc/compiler:clang-cl": [], - "@rules_cc//cc/compiler:clang": ["-pthread"], - "@rules_cc//cc/compiler:gcc": ["-pthread"], - "//conditions:default": ["-pthread"], - }) - def ftxui_cc_library( name, srcs = [], diff --git a/cmake/ftxui_set_options.cmake b/cmake/ftxui_set_options.cmake index 185739e49..38a80ee9d 100644 --- a/cmake/ftxui_set_options.cmake +++ b/cmake/ftxui_set_options.cmake @@ -101,6 +101,5 @@ endfunction() if (EMSCRIPTEN) string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ASYNCIFY") string(APPEND CMAKE_EXE_LINKER_FLAGS " -s PROXY_TO_PTHREAD") endif() diff --git a/cmake/ftxui_test.cmake b/cmake/ftxui_test.cmake index f92a222b2..1666e3ecf 100644 --- a/cmake/ftxui_test.cmake +++ b/cmake/ftxui_test.cmake @@ -19,7 +19,6 @@ add_executable(ftxui-tests src/ftxui/component/menu_test.cpp src/ftxui/component/modal_test.cpp src/ftxui/component/radiobox_test.cpp - src/ftxui/component/receiver_test.cpp src/ftxui/component/resizable_split_test.cpp src/ftxui/component/screen_interactive_test.cpp src/ftxui/component/slider_test.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 953efa98a..0a49fe92b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -15,15 +15,11 @@ add_subdirectory(component) add_subdirectory(dom) if (EMSCRIPTEN) - string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ALLOW_MEMORY_GROWTH=1") - target_link_options(component PUBLIC "SHELL: -s ALLOW_MEMORY_GROWTH=1") - get_property(EXAMPLES GLOBAL PROPERTY FTXUI::EXAMPLES) foreach(file "index.html" "index.mjs" "index.css" - "sw.js" "run_webassembly.py") configure_file(${file} ${file}) endforeach(file) diff --git a/examples/component/homescreen.cpp b/examples/component/homescreen.cpp index 7a5e710c5..16edec506 100644 --- a/examples/component/homescreen.cpp +++ b/examples/component/homescreen.cpp @@ -6,6 +6,7 @@ #include // for atomic #include // for operator""s, chrono_literals #include // for sin +#include #include // for ref, reference_wrapper, function #include // for allocator, shared_ptr, __shared_ptr_access #include // for string, basic_string, char_traits, operator+, to_string @@ -269,7 +270,7 @@ int main() { auto spinner_tab_renderer = Renderer([&] { Elements entries; for (int i = 0; i < 22; ++i) { - entries.push_back(spinner(i, shift / 2) | bold | + entries.push_back(spinner(i, shift / 5) | bold | size(WIDTH, GREATER_THAN, 2) | border); } return hflow(std::move(entries)); @@ -512,24 +513,20 @@ int main() { }); }); - std::atomic refresh_ui_continue = true; - std::thread refresh_ui([&] { - while (refresh_ui_continue) { - using namespace std::chrono_literals; - std::this_thread::sleep_for(0.05s); - // The |shift| variable belong to the main thread. `screen.Post(task)` - // will execute the update on the thread where |screen| lives (e.g. the - // main thread). Using `screen.Post(task)` is threadsafe. - screen.Post([&] { shift++; }); - // After updating the state, request a new frame to be drawn. This is done - // by simulating a new "custom" event to be handled. - screen.Post(Event::Custom); - } - }); + Loop loop(&screen, main_renderer); + while(!loop.HasQuitted()) { + // Update the state of the application. + shift++; - screen.Loop(main_renderer); - refresh_ui_continue = false; - refresh_ui.join(); + // Request a new frame to be drawn. + screen.RequestAnimationFrame(); + + // Execute events, and draw the next frame. + loop.RunOnce(); + + // Sleep for a short duration to control the frame rate (60 FPS). + std::this_thread::sleep_for(std::chrono::milliseconds(1000/60)); + } return 0; } diff --git a/examples/index.mjs b/examples/index.mjs index 803659047..63d273269 100644 --- a/examples/index.mjs +++ b/examples/index.mjs @@ -7,7 +7,7 @@ if ("serviceWorker" in navigator && !window.crossOriginIsolated) { const url_sw = new URL("./sw.js", location.href); const registration = await navigator.serviceWorker.register(url_sw); window.location.reload(); // Reload to ensure the COOP/COEP headers are set. -} +} const example_list = "@EXAMPLES@".split(";"); const url_search_params = new URLSearchParams(window.location.search); @@ -55,7 +55,7 @@ const stdout = code => { const stderr = code => { if (code == 0 || code == 10) { console.error(String.fromCodePoint(...stderr_buffer)); - stderr_buffer = []; + stderr_buffer.length = 0; } else { stderr_buffer.push(code) } @@ -89,9 +89,6 @@ window.Module = { const resize_observer = new ResizeObserver(resize_handler); resize_observer.observe(term_element); resize_handler(); - - // Disable scrollbar - //term.write('\x1b[?47h') }, }; diff --git a/include/ftxui/component/receiver.hpp b/include/ftxui/component/receiver.hpp index 55189cf9f..d9fed4dcf 100644 --- a/include/ftxui/component/receiver.hpp +++ b/include/ftxui/component/receiver.hpp @@ -14,6 +14,8 @@ namespace ftxui { +// Deprecated +// // Usage: // // Initialization: @@ -39,17 +41,24 @@ namespace ftxui { // Receiver::Receive() returns true when there are no more senders. // clang-format off +// Deprecated: template class SenderImpl; +// Deprecated: template class ReceiverImpl; +// Deprecated: +// Deprecated: template using Sender = std::unique_ptr>; +// Deprecated: template using Receiver = std::unique_ptr>; +// Deprecated: template Receiver MakeReceiver(); // clang-format on // ---- Implementation part ---- template +// Deprecated: class SenderImpl { public: SenderImpl(const SenderImpl&) = delete; diff --git a/include/ftxui/component/screen_interactive.hpp b/include/ftxui/component/screen_interactive.hpp index 039f036d9..c9ba93e7b 100644 --- a/include/ftxui/component/screen_interactive.hpp +++ b/include/ftxui/component/screen_interactive.hpp @@ -5,7 +5,6 @@ #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP #include // for atomic -#include // for Receiver, Sender #include // for function #include // for shared_ptr #include // for string @@ -123,9 +122,6 @@ class ScreenInteractive : public Screen { bool track_mouse_ = true; - Sender task_sender_; - Receiver task_receiver_; - std::string set_cursor_position; std::string reset_cursor_position; diff --git a/src/ftxui/component/receiver.cppm b/src/ftxui/component/receiver.cppm index ddf4177b5..aee92ff19 100644 --- a/src/ftxui/component/receiver.cppm +++ b/src/ftxui/component/receiver.cppm @@ -12,9 +12,15 @@ export module ftxui.component.receiver; * @brief The FTXUI ftxui:: namespace */ export namespace ftxui { + // Deprecated: using ftxui::SenderImpl; + // Deprecated: using ftxui::ReceiverImpl; + // Deprecated: using ftxui::Sender; + // Deprecated: using ftxui::Receiver; + // Deprecated: using ftxui::MakeReceiver; + // Deprecated: } diff --git a/src/ftxui/component/receiver_test.cpp b/src/ftxui/component/receiver_test.cpp deleted file mode 100644 index cb2cde076..000000000 --- a/src/ftxui/component/receiver_test.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2020 Arthur Sonzogni. All rights reserved. -// Use of this source code is governed by the MIT license that can be found in -// the LICENSE file. -#include // for thread -#include // for move - -#include "ftxui/component/receiver.hpp" -#include "gtest/gtest.h" // for AssertionResult, Message, Test, TestPartResult, EXPECT_EQ, EXPECT_TRUE, EXPECT_FALSE, TEST - -// NOLINTBEGIN -namespace ftxui { - -TEST(Receiver, Basic) { - auto receiver = MakeReceiver(); - auto sender = receiver->MakeSender(); - - sender->Send('a'); - sender->Send('b'); - sender->Send('c'); - sender.reset(); - - char a, b, c, d; - EXPECT_TRUE(receiver->Receive(&a)); - EXPECT_TRUE(receiver->Receive(&b)); - EXPECT_TRUE(receiver->Receive(&c)); - EXPECT_FALSE(receiver->Receive(&d)); - - EXPECT_EQ(a, 'a'); - EXPECT_EQ(b, 'b'); - EXPECT_EQ(c, 'c'); -} - -TEST(Receiver, BasicWithThread) { - auto r1 = MakeReceiver(); - auto r2 = MakeReceiver(); - auto r3 = MakeReceiver(); - - auto s1 = r1->MakeSender(); - auto s2 = r2->MakeSender(); - auto s3 = r3->MakeSender(); - - auto s1_bis = r1->MakeSender(); - - auto stream = [](Receiver receiver, Sender sender) { - char c; - while (receiver->Receive(&c)) - sender->Send(c); - }; - - // Convert data from a different thread. - auto t12 = std::thread(stream, std::move(r1), std::move(s2)); - auto t23 = std::thread(stream, std::move(r2), std::move(s3)); - - // Send some data. - s1->Send('1'); - s1_bis->Send('2'); - s1->Send('3'); - s1_bis->Send('4'); - - // Close the stream. - s1.reset(); - s1_bis.reset(); - - char c; - EXPECT_TRUE(r3->Receive(&c)); - EXPECT_EQ(c, '1'); - EXPECT_TRUE(r3->Receive(&c)); - EXPECT_EQ(c, '2'); - EXPECT_TRUE(r3->Receive(&c)); - EXPECT_EQ(c, '3'); - EXPECT_TRUE(r3->Receive(&c)); - EXPECT_EQ(c, '4'); - EXPECT_FALSE(r3->Receive(&c)); - - // Thread will end at the end of the stream. - t12.join(); - t23.join(); -} - -} // namespace ftxui -// NOLINTEND diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 979d37727..2cce071e2 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -4,6 +4,7 @@ #include "ftxui/component/screen_interactive.hpp" #include // for copy, max, min #include // for array +#include #include #include // for operator-, milliseconds, operator>=, duration, common_type<>::type, time_point #include // for signal, SIGTSTP, SIGABRT, SIGWINCH, raise, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, __sighandler_t, size_t @@ -17,7 +18,6 @@ #include #include // for stack #include -#include #include // for thread, sleep_for #include // for _Swallow_assign, ignore #include // for decay_t @@ -37,6 +37,7 @@ #include "ftxui/screen/pixel.hpp" // for Pixel #include "ftxui/screen/terminal.hpp" // for Dimensions, Size #include "ftxui/screen/util.hpp" // for util::clamp +#include "ftxui/util/autoreset.hpp" // for AutoReset #if defined(_WIN32) #define DEFINE_CONSOLEV2_PROPERTIES @@ -49,9 +50,11 @@ #error Must be compiled in UNICODE mode #endif #else +#include #include // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set, timeval #include // for tcsetattr, termios, tcgetattr, TCSANOW, cc_t, ECHO, ICANON, VMIN, VTIME #include // for STDIN_FILENO, read +#include #endif // Quick exit is missing in standard CLang headers @@ -98,75 +101,9 @@ constexpr int timeout_milliseconds = 20; timeout_milliseconds * 1000; #if defined(_WIN32) -void EventListener(std::atomic* quit, Sender out) { - auto console = GetStdHandle(STD_INPUT_HANDLE); - auto parser = - TerminalInputParser([&](Event event) { out->Send(std::move(event)); }); - while (!*quit) { - // Throttle ReadConsoleInput by waiting 250ms, this wait function will - // return if there is input in the console. - auto wait_result = WaitForSingleObject(console, timeout_milliseconds); - if (wait_result == WAIT_TIMEOUT) { - parser.Timeout(timeout_milliseconds); - continue; - } - - DWORD number_of_events = 0; - if (!GetNumberOfConsoleInputEvents(console, &number_of_events)) - continue; - if (number_of_events <= 0) - continue; - - std::vector records{number_of_events}; - DWORD number_of_events_read = 0; - ReadConsoleInput(console, records.data(), (DWORD)records.size(), - &number_of_events_read); - records.resize(number_of_events_read); - - for (const auto& r : records) { - switch (r.EventType) { - case KEY_EVENT: { - auto key_event = r.Event.KeyEvent; - // ignore UP key events - if (key_event.bKeyDown == FALSE) - continue; - std::wstring wstring; - wstring += key_event.uChar.UnicodeChar; - for (auto it : to_string(wstring)) { - parser.Add(it); - } - } break; - case WINDOW_BUFFER_SIZE_EVENT: - out->Send(Event::Special({0})); - break; - case MENU_EVENT: - case FOCUS_EVENT: - case MOUSE_EVENT: - // TODO(mauve): Implement later. - break; - } - } - } -} - #elif defined(__EMSCRIPTEN__) #include -// Read char from the terminal. -void EventListener(std::atomic* quit, Sender out) { - auto parser = - TerminalInputParser([&](Event event) { out->Send(std::move(event)); }); - - char c; - while (!*quit) { - while (read(STDIN_FILENO, &c, 1), c) - parser.Add(c); - - emscripten_sleep(1); - parser.Timeout(1); - } -} - extern "C" { EMSCRIPTEN_KEEPALIVE void ftxui_on_resize(int columns, int rows) { @@ -180,8 +117,8 @@ void ftxui_on_resize(int columns, int rows) { #else // POSIX (Linux & Mac) -int CheckStdinReady(int usec_timeout) { - timeval tv = {0, usec_timeout}; // NOLINT +int CheckStdinReady() { + timeval tv = {0, 0}; // NOLINT fd_set fds; FD_ZERO(&fds); // NOLINT FD_SET(STDIN_FILENO, &fds); // NOLINT @@ -189,25 +126,6 @@ int CheckStdinReady(int usec_timeout) { return FD_ISSET(STDIN_FILENO, &fds); // NOLINT } - -// Read char from the terminal. -//void EventListener(std::atomic* quit, Sender out) { - //auto parser = - //TerminalInputParser([&](Event event) { out->Send(std::move(event)); }); - - //while (!*quit) { - //auto pending = ReadPendingChars(); - //if (pending.empty()) { - //parser.Timeout(timeout_milliseconds); - //continue; - //} - - //for (auto c : pending) { - //parser.Add(c); - //} - //} -//} - #endif std::stack on_exit_functions; // NOLINT @@ -665,7 +583,15 @@ void ScreenInteractive::Install() { SetConsoleMode(stdin_handle, in_mode); SetConsoleMode(stdout_handle, out_mode); -#else +#else // POSIX (Linux & Mac) +//#if defined(__EMSCRIPTEN__) + //// Reading stdin isn't blocking. + //int flags = fcntl(0, F_GETFL, 0); + //fcntl(0, F_SETFL, flags | O_NONBLOCK); + + //// Restore the terminal configuration on exit. + //on_exit_functions.emplace([flags] { fcntl(0, F_SETFL, flags); }); +//#endif for (const int signal : {SIGWINCH, SIGTSTP}) { InstallSignalHandler(signal); } @@ -751,16 +677,31 @@ void ScreenInteractive::Uninstall() { // private // NOLINTNEXTLINE void ScreenInteractive::RunOnceBlocking(Component component) { + // Set FPS to 60 at most. + const auto time_per_frame = std::chrono::microseconds(16666); // 1s / 60fps + + auto time = std::chrono::steady_clock::now(); size_t executed_task = internal_->task_runner.ExecutedTasks(); + + // Wait for at least one task to execute. while(executed_task == internal_->task_runner.ExecutedTasks() && !HasQuitted()) { RunOnce(component); + + const auto now = std::chrono::steady_clock::now(); + const auto delta = now - time; + time = now; + + if (delta < time_per_frame) { + const auto sleep_duration = time_per_frame - delta; + std::this_thread::sleep_for(sleep_duration); + } } } // private void ScreenInteractive::RunOnce(Component component) { - component_ = component; + AutoReset set_component(&component_, component); ExecuteSignalHandlers(); FetchTerminalEvents(); @@ -773,7 +714,7 @@ void ScreenInteractive::RunOnce(Component component) { } ExecuteSignalHandlers(); - Draw(std::move(component)); + Draw(component); if (selection_data_previous_ != selection_data_) { selection_data_previous_ = selection_data_; @@ -782,8 +723,6 @@ void ScreenInteractive::RunOnce(Component component) { Post(Event::Custom); } } - - component_.reset(); } // private @@ -793,9 +732,10 @@ void ScreenInteractive::HandleTask(Component component, Task& task) { [&](auto&& arg) { using T = std::decay_t; - // clang-format off + // clang-format off // Handle Event. if constexpr (std::is_same_v) { + if (arg.is_cursor_position()) { cursor_x_ = arg.cursor_x(); cursor_y_ = arg.cursor_y(); @@ -1080,7 +1020,87 @@ void ScreenInteractive::Signal(int signal) { } void ScreenInteractive::FetchTerminalEvents() { - if (!CheckStdinReady(timeout_microseconds)) { +#if defined(_WIN32) + auto get_input_records = [&] { + // Check if there is input in the console. + auto console = GetStdHandle(STD_INPUT_HANDLE); + DWORD number_of_events = 0; + if (!GetNumberOfConsoleInputEvents(console, &number_of_events)) { + return; + } + if (number_of_events <= 0) { + // No input, return. + return; + } + // Read the input events. + std::vector records(number_of_events); + DWORD number_of_events_read = 0; + if (!ReadConsoleInput(console, records.data(), (DWORD)records.size(), + &number_of_events_read)) { + return; + } + records.resize(number_of_events_read); + return records; + }; + + auto records = get_input_records(); + if (records.size() == 0) { + const auto timeout = + std::chrono::steady_clock::now() - internal_->last_char_time; + const size_t timeout_microseconds = + std::chrono::duration_cast(timeout).count(); + internal_->terminal_input_parser.Timeout(timeout_microseconds); + return; + } + internal_->last_char_time = std::chrono::steady_clock::now(); + + // Convert the input events to FTXUI events. + // For each event, we call the terminal input parser to convert it to + // Event. + for (const auto& r : records) { + switch (r.EventType) { + case KEY_EVENT: { + auto key_event = r.Event.KeyEvent; + // ignore UP key events + if (key_event.bKeyDown == FALSE) + continue; + std::wstring wstring; + wstring += key_event.uChar.UnicodeChar; + for (auto it : to_string(wstring)) { + internal_->terminal_input_parser.Add(it); + } + } break; + case WINDOW_BUFFER_SIZE_EVENT: + Post(Event::Special({0})); + break; + case MENU_EVENT: + case FOCUS_EVENT: + case MOUSE_EVENT: + // TODO(mauve): Implement later. + break; + } + } +#elif defined(__EMSCRIPTEN__) + // Read chars from the terminal. + // We configured it to be non blocking. + std::array out{}; + size_t l = read(STDIN_FILENO, out.data(), out.size()); + if (l == 0) { + const auto timeout = + std::chrono::steady_clock::now() - internal_->last_char_time; + const size_t timeout_microseconds = + std::chrono::duration_cast(timeout).count(); + internal_->terminal_input_parser.Timeout(timeout_microseconds); + return; + } + internal_->last_char_time = std::chrono::steady_clock::now(); + + // Convert the chars to events. + for(size_t i = 0; i < l; ++i) { + internal_->terminal_input_parser.Add(out[i]); + } +#else // POSIX (Linux & Mac) + if (!CheckStdinReady()) { const auto timeout = std::chrono::steady_clock::now() - internal_->last_char_time; const size_t timeout_ms = @@ -1091,13 +1111,14 @@ void ScreenInteractive::FetchTerminalEvents() { internal_->last_char_time = std::chrono::steady_clock::now(); // Read chars from the terminal. - std::array out; + std::array out{}; size_t l = read(fileno(stdin), out.data(), out.size()); // Convert the chars to events. for(size_t i = 0; i < l; ++i) { internal_->terminal_input_parser.Add(out[i]); } +#endif } void ScreenInteractive::PostAnimationTask() { diff --git a/src/ftxui/core/task.hpp b/src/ftxui/core/task.hpp index dd801d7a6..28ddcc74b 100644 --- a/src/ftxui/core/task.hpp +++ b/src/ftxui/core/task.hpp @@ -17,11 +17,11 @@ using Task = std::function; /// specific time, or as soon as possible. struct PendingTask { // Immediate task: - PendingTask(Task task) : task(std::move(task)) {} // NOLINT + PendingTask(Task t) : task(std::move(t)) {} // NOLINT // Delayed task with a duration - PendingTask(Task task, std::chrono::steady_clock::duration duration) - : task(std::move(task)), + PendingTask(Task t, std::chrono::steady_clock::duration duration) + : task(std::move(t)), time(std::chrono::steady_clock::now() + duration) {} /// The task to be executed.