From 373b016ca98eff05a0d893df8cbfc5487b726991 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Mon, 22 Mar 2021 00:26:52 +0100 Subject: [PATCH 01/10] Add webassembly support (#79) --- CMakeLists.txt | 7 + README.md | 1 + examples/CMakeLists.txt | 11 ++ examples/dom/border.cpp | 2 +- examples/dom/color_gallery.cpp | 2 +- examples/dom/color_info_palette256.cpp | 2 +- examples/dom/color_truecolor_HSV.cpp | 2 +- examples/dom/color_truecolor_RGB.cpp | 2 +- examples/dom/dbox.cpp | 2 +- examples/dom/gauge.cpp | 3 +- examples/dom/graph.cpp | 4 +- examples/dom/hflow.cpp | 2 +- examples/dom/html_like.cpp | 4 +- examples/dom/package_manager.cpp | 3 +- examples/dom/paragraph.cpp | 2 +- examples/dom/separator.cpp | 3 +- examples/dom/size.cpp | 2 +- examples/dom/spinner.cpp | 3 +- examples/dom/style_blink.cpp | 3 +- examples/dom/style_bold.cpp | 3 +- examples/dom/style_color.cpp | 3 +- examples/dom/style_dim.cpp | 3 +- examples/dom/style_gallery.cpp | 3 +- examples/dom/style_inverted.cpp | 3 +- examples/dom/style_underlined.cpp | 3 +- examples/dom/vbox_hbox.cpp | 3 +- examples/dom/window.cpp | 2 +- examples/index.html | 164 +++++++++++++++++++++ examples/run_webassembly.sh | 6 + include/ftxui/screen/screen.hpp | 1 + src/ftxui/component/screen_interactive.cpp | 30 +++- src/ftxui/dom/text_test.cpp | 14 +- src/ftxui/dom/vbox_test.cpp | 1 + src/ftxui/screen/screen.cpp | 9 +- src/ftxui/screen/terminal.cpp | 6 +- 35 files changed, 267 insertions(+), 47 deletions(-) create mode 100644 examples/index.html create mode 100755 examples/run_webassembly.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 57efcf4..b237613 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,13 @@ foreach(lib screen dom component) endforeach() +if (EMSCRIPTEN) + #string(APPEND CMAKE_CXX_FLAGS " -s ASSERTIONS=1") + string(APPEND CMAKE_CXX_FLAGS " -s ASYNCIFY") + string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS") + string(APPEND CMAKE_CXX_FLAGS " -s PROXY_TO_PTHREAD") +endif() + if(FTXUI_ENABLE_INSTALL) include(GNUInstallDirs) install(TARGETS screen dom component diff --git a/README.md b/README.md index 194172c..d7f32da 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ A simple C++ library for terminal based user interface. - [Starter example project](https://github.com/ArthurSonzogni/ftxui-starter) - [Documentation](https://arthursonzogni.com/FTXUI/doc/) +- [Examples (WebAssembly)](https://arthursonzogni.com/FTXUI/examples/) - [Build using CMake](https://arthursonzogni.com/FTXUI/doc/#build-using-cmake) - [Build using nxxm](https://arthursonzogni.com/FTXUI/doc/#build-using-cmake) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ff779c0..41e3207 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,14 @@ add_subdirectory(component) add_subdirectory(dom) add_subdirectory(util) + +if (EMSCRIPTEN) + foreach(file + "index.html" + "run_webassembly.sh") + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${file} + ${CMAKE_CURRENT_BINARY_DIR}/${file} + ) + endforeach(file) +endif() diff --git a/examples/dom/border.cpp b/examples/dom/border.cpp index 7a49f3e..57fa7b3 100644 --- a/examples/dom/border.cpp +++ b/examples/dom/border.cpp @@ -28,7 +28,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString() << std::endl; + screen.Print(); } // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/examples/dom/color_gallery.cpp b/examples/dom/color_gallery.cpp index db1c25b..0775ad1 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -126,7 +126,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/color_info_palette256.cpp b/examples/dom/color_info_palette256.cpp index 56820f3..68a1d18 100644 --- a/examples/dom/color_info_palette256.cpp +++ b/examples/dom/color_info_palette256.cpp @@ -30,7 +30,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/color_truecolor_HSV.cpp b/examples/dom/color_truecolor_HSV.cpp index 887f27c..ad902bb 100644 --- a/examples/dom/color_truecolor_HSV.cpp +++ b/examples/dom/color_truecolor_HSV.cpp @@ -26,7 +26,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/color_truecolor_RGB.cpp b/examples/dom/color_truecolor_RGB.cpp index ed1495b..d35788e 100644 --- a/examples/dom/color_truecolor_RGB.cpp +++ b/examples/dom/color_truecolor_RGB.cpp @@ -45,7 +45,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/dbox.cpp b/examples/dom/dbox.cpp index 67561ef..2fc712c 100644 --- a/examples/dom/dbox.cpp +++ b/examples/dom/dbox.cpp @@ -17,7 +17,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/gauge.cpp b/examples/dom/gauge.cpp index 2d7ecd3..eb2a96d 100644 --- a/examples/dom/gauge.cpp +++ b/examples/dom/gauge.cpp @@ -19,7 +19,8 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen(100, 1); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.01s); diff --git a/examples/dom/graph.cpp b/examples/dom/graph.cpp index dbf7f1e..78c8f46 100644 --- a/examples/dom/graph.cpp +++ b/examples/dom/graph.cpp @@ -60,8 +60,8 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; - + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.03s); diff --git a/examples/dom/hflow.cpp b/examples/dom/hflow.cpp index ef6beb2..aa140a6 100644 --- a/examples/dom/hflow.cpp +++ b/examples/dom/hflow.cpp @@ -39,7 +39,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString() << std::endl; + screen.Print(); return 0; } diff --git a/examples/dom/html_like.cpp b/examples/dom/html_like.cpp index 6485cf1..be565e8 100644 --- a/examples/dom/html_like.cpp +++ b/examples/dom/html_like.cpp @@ -41,8 +41,8 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full()); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; - + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.01s); diff --git a/examples/dom/package_manager.cpp b/examples/dom/package_manager.cpp index 3875945..11cbd5f 100644 --- a/examples/dom/package_manager.cpp +++ b/examples/dom/package_manager.cpp @@ -123,7 +123,8 @@ int main(int argc, const char* argv[]) { auto document = render(); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); // Simulate time. diff --git a/examples/dom/paragraph.cpp b/examples/dom/paragraph.cpp index 7ed3d14..adb1f38 100644 --- a/examples/dom/paragraph.cpp +++ b/examples/dom/paragraph.cpp @@ -25,7 +25,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Full()); Render(screen, document); - std::cout << screen.ToString(); + screen.Print(); getchar(); return 0; diff --git a/examples/dom/separator.cpp b/examples/dom/separator.cpp index e575868..f3bf1a3 100644 --- a/examples/dom/separator.cpp +++ b/examples/dom/separator.cpp @@ -18,8 +18,7 @@ int main(int argc, const char* argv[]) { border; auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString() << std::endl; + screen.Print(); return 0; } diff --git a/examples/dom/size.cpp b/examples/dom/size.cpp index 392c62e..dfeea1d 100644 --- a/examples/dom/size.cpp +++ b/examples/dom/size.cpp @@ -18,7 +18,7 @@ int main(int argc, const char* argv[]) { auto document = hbox(std::move(content)); auto screen = Screen::Create(Dimension::Fit(document)); Render(screen, document); - std::cout << screen.ToString() << std::endl; + screen.Print(); return 0; } diff --git a/examples/dom/spinner.cpp b/examples/dom/spinner.cpp index 52cfe87..7fff889 100644 --- a/examples/dom/spinner.cpp +++ b/examples/dom/spinner.cpp @@ -28,7 +28,8 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - std::cout << reset_position << screen.ToString() << std::flush; + std::cout << reset_position; + screen.Print(); reset_position = screen.ResetPosition(); std::this_thread::sleep_for(0.1s); diff --git a/examples/dom/style_blink.cpp b/examples/dom/style_blink.cpp index 0445add..114a0d4 100644 --- a/examples/dom/style_blink.cpp +++ b/examples/dom/style_blink.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_bold.cpp b/examples/dom/style_bold.cpp index 89cb641..e395d78 100644 --- a/examples/dom/style_bold.cpp +++ b/examples/dom/style_bold.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_color.cpp b/examples/dom/style_color.cpp index 5c4ec50..f50fddb 100644 --- a/examples/dom/style_color.cpp +++ b/examples/dom/style_color.cpp @@ -51,8 +51,7 @@ int main(int argc, const char* argv[]) { auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_dim.cpp b/examples/dom/style_dim.cpp index 53823a2..1c4d446 100644 --- a/examples/dom/style_dim.cpp +++ b/examples/dom/style_dim.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_gallery.cpp b/examples/dom/style_gallery.cpp index a180789..0ce864f 100644 --- a/examples/dom/style_gallery.cpp +++ b/examples/dom/style_gallery.cpp @@ -19,8 +19,7 @@ int main(int argc, const char* argv[]) { // clang-format on auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_inverted.cpp b/examples/dom/style_inverted.cpp index ad930ab..9a19181 100644 --- a/examples/dom/style_inverted.cpp +++ b/examples/dom/style_inverted.cpp @@ -11,8 +11,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/style_underlined.cpp b/examples/dom/style_underlined.cpp index 41c5fd4..dedf04a 100644 --- a/examples/dom/style_underlined.cpp +++ b/examples/dom/style_underlined.cpp @@ -12,8 +12,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); return 0; } diff --git a/examples/dom/vbox_hbox.cpp b/examples/dom/vbox_hbox.cpp index 93bb984..92d23cd 100644 --- a/examples/dom/vbox_hbox.cpp +++ b/examples/dom/vbox_hbox.cpp @@ -26,8 +26,7 @@ int main(int argc, const char* argv[]) { }); auto screen = Screen::Create(Dimension::Full()); Render(screen, document); - - std::cout << screen.ToString(); + screen.Print(); getchar(); return 0; diff --git a/examples/dom/window.cpp b/examples/dom/window.cpp index 18726da..df84561 100644 --- a/examples/dom/window.cpp +++ b/examples/dom/window.cpp @@ -16,7 +16,7 @@ int main(void) { auto screen = Screen::Create(Dimension::Fixed(80), Dimension::Fixed(10)); Render(screen, document); - std::cout << screen.ToString() << '\n'; + screen.Print(); } // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 0000000..fde820a --- /dev/null +++ b/examples/index.html @@ -0,0 +1,164 @@ + + + + FTXUI examples WebAssembly + + + + + +
+

FTXUI WebAssembly Example

+

+ FTXUI is a single + C++ library for terminal user interface. +

+

+ On this page, you can try all the examples contained in: ./example/ + Those are compiled using WebAssembly. +

+ +
+
+ + + + + + diff --git a/examples/run_webassembly.sh b/examples/run_webassembly.sh new file mode 100755 index 0000000..488c23c --- /dev/null +++ b/examples/run_webassembly.sh @@ -0,0 +1,6 @@ +#! /bin/bash +python3 -m http.server 8888 & +P1=$! +trap 'kill 0' SIGINT; P1 +python3 -m webbrowser http://localhost:8888 +wait $P1 diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index 7caba26..0c75202 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -56,6 +56,7 @@ class Screen { // Convert the screen into a printable string in the terminal. std::string ToString(); + void Print(); // Get screen dimensions. int dimx() { return dimx_; } diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 130ce34..b4f3753 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -38,6 +38,11 @@ namespace ftxui { namespace { +void Flush() { + // Emscripten doesn't implement flush. We interpret zero as flush. + std::cout << std::flush << (char)0; +} + constexpr int timeout_milliseconds = 20; constexpr int timeout_microseconds = timeout_milliseconds * 1000; #if defined(_WIN32) @@ -90,8 +95,25 @@ void EventListener(std::atomic* quit, } } -#else +#elif defined(__EMSCRIPTEN__) +#include +// Read char from the terminal. +void EventListener(std::atomic* quit, Sender out) { + (void)timeout_microseconds; + auto parser = TerminalInputParser(std::move(out)); + + char c; + while (!*quit) { + while(read(STDIN_FILENO, &c, 1), c) + parser.Add(c); + + emscripten_sleep(1); + parser.Timeout(1); + } +} + +#else #include int CheckStdinReady(int usec_timeout) { @@ -260,12 +282,13 @@ void ScreenInteractive::Loop(Component* component) { // Hide the cursor and show it at exit. std::cout << HIDE_CURSOR; std::cout << DISABLE_LINE_WRAP; - std::cout << std::flush; + Flush(); on_exit_functions.push([&] { std::cout << reset_cursor_position; std::cout << SHOW_CURSOR; std::cout << ENABLE_LINE_WRAP; std::cout << std::endl; + Flush(); }); auto event_listener = @@ -276,7 +299,8 @@ void ScreenInteractive::Loop(Component* component) { if (!event_receiver_->HasPending()) { std::cout << reset_cursor_position << ResetPosition(); Draw(component); - std::cout << ToString() << set_cursor_position << std::flush; + std::cout << ToString() << set_cursor_position; + Flush(); Clear(); } Event event; diff --git a/src/ftxui/dom/text_test.cpp b/src/ftxui/dom/text_test.cpp index d4f6e0e..34fe2a5 100644 --- a/src/ftxui/dom/text_test.cpp +++ b/src/ftxui/dom/text_test.cpp @@ -42,7 +42,7 @@ TEST(TextTest, ScreenBigger2) { Screen screen(6, 2); Render(screen, element); - EXPECT_EQ("test \n ", screen.ToString()); + EXPECT_EQ("test \r\n ", screen.ToString()); } // See https://github.com/ArthurSonzogni/FTXUI/issues/2#issuecomment-504871456 @@ -51,8 +51,8 @@ TEST(TextTest, CJK) { Screen screen(6, 3); Render(screen, element); EXPECT_EQ( - "┌────┐\n" - "│测试│\n" + "┌────┐\r\n" + "│测试│\r\n" "└────┘", screen.ToString()); } @@ -63,8 +63,8 @@ TEST(TextTest, CJK_2) { Screen screen(5, 3); Render(screen, element); EXPECT_EQ( - "┌───┐\n" - "│测试\n" + "┌───┐\r\n" + "│测试\r\n" "└───┘", screen.ToString()); } @@ -75,8 +75,8 @@ TEST(TextTest, CJK_3) { Screen screen(4, 3); Render(screen, element); EXPECT_EQ( - "┌──┐\n" - "│测│\n" + "┌──┐\r\n" + "│测│\r\n" "└──┘", screen.ToString()); } diff --git a/src/ftxui/dom/vbox_test.cpp b/src/ftxui/dom/vbox_test.cpp index cffa74a..917afd9 100644 --- a/src/ftxui/dom/vbox_test.cpp +++ b/src/ftxui/dom/vbox_test.cpp @@ -6,6 +6,7 @@ using namespace ftxui; using namespace ftxui; std::string rotate(std::string str) { + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); return str; } diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index f98cc50..d83e424 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "ftxui/dom/node.hpp" #include "ftxui/screen/string.hpp" @@ -149,6 +150,7 @@ Screen::Screen(int dimx, int dimy) } /// Produce a std::string that can be used to print the Screen on the terminal. +/// Don't forget to flush stdout. Alternatively, you can use Screen::Print(); std::string Screen::ToString() { std::wstringstream ss; @@ -158,7 +160,7 @@ std::string Screen::ToString() { for (int y = 0; y < dimy_; ++y) { if (y != 0) { UpdatePixelStyle(ss, previous_pixel, final_pixel); - ss << '\n'; + ss << L"\r\n"; } for (int x = 0; x < dimx_;) { auto& pixel = pixels_[y][x]; @@ -181,6 +183,10 @@ std::string Screen::ToString() { return to_string(ss.str()); } +void Screen::Print() { + std::cout << ToString() << std::flush << (char)0; +} + /// @brief Access a character a given position. /// @param x The character position along the x-axis. /// @param y The character position along the y-axis. @@ -254,6 +260,7 @@ void Screen::ApplyShader() { } } } + // clang-format on } // namespace ftxui diff --git a/src/ftxui/screen/terminal.cpp b/src/ftxui/screen/terminal.cpp index fae1de8..e86c82d 100644 --- a/src/ftxui/screen/terminal.cpp +++ b/src/ftxui/screen/terminal.cpp @@ -19,7 +19,7 @@ namespace ftxui { Terminal::Dimensions Terminal::Size() { #if defined(__EMSCRIPTEN__) - return Dimensions{80, 43}; + return Dimensions{140, 43}; #elif defined(_WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; int columns, rows; @@ -48,6 +48,10 @@ bool Contains(const std::string& s, const char* key) { static bool cached = false; Terminal::Color cached_supported_color; Terminal::Color ComputeColorSupport() { +#if defined(__EMSCRIPTEN__) + return Terminal::Color::TrueColor; +#endif + std::string COLORTERM = Safe(std::getenv("COLORTERM")); if (Contains(COLORTERM, "24bit") || Contains(COLORTERM, "truecolor")) return Terminal::Color::TrueColor; From 430c805dfdd83345fdeb17ffeb8a94f7f3ba62ab Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Mon, 22 Mar 2021 00:28:19 +0100 Subject: [PATCH 02/10] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7f32da..7342511 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,11 @@ A simple C++ library for terminal based user interface. ## Operating systems - [![linux-gcc][badge.linux-gcc]][link.linux-gcc] -- [![linux-clang][badge.linux-clang]][link.linux-clang] -- [![linux-emscripten][badge.linux-emscripten]][link.linux-emscripten] +[![linux-clang][badge.linux-clang]][link.linux-clang] +[![linux-emscripten][badge.linux-emscripten]][link.linux-emscripten] + - [![windows-msvc][badge.windows-msvc]][link.windows-msvc] + - [![mac-clang][badge.mac-clang]][link.mac-clang] [badge.linux-gcc]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-gcc.yaml/badge.svg?branch=master From a4c6daae53bd7b77933afa8ac1a33c985a8c9f30 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Mon, 22 Mar 2021 00:28:56 +0100 Subject: [PATCH 03/10] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 7342511..76bc123 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,7 @@ A simple C++ library for terminal based user interface. - [![linux-gcc][badge.linux-gcc]][link.linux-gcc] [![linux-clang][badge.linux-clang]][link.linux-clang] [![linux-emscripten][badge.linux-emscripten]][link.linux-emscripten] - - [![windows-msvc][badge.windows-msvc]][link.windows-msvc] - - [![mac-clang][badge.mac-clang]][link.mac-clang] [badge.linux-gcc]: https://github.com/ArthurSonzogni/FTXUI/actions/workflows/linux-gcc.yaml/badge.svg?branch=master From a6c692edcfa82746134abcbcc5344e8651cdfe32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=9A=E6=9C=A8=E9=89=89?= <740291272@qq.com> Date: Mon, 22 Mar 2021 17:31:35 +0800 Subject: [PATCH 04/10] Fix MSVC Warning D9025 (#80) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b237613..ba4671d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ foreach(lib screen dom component) # Add as many warning as possible: if (WIN32) if (MSVC) - target_compile_options(${lib} PRIVATE "/W4") + target_compile_options(${lib} PRIVATE "/W3") target_compile_options(${lib} PRIVATE "/WX") target_compile_options(${lib} PRIVATE "/wd4244") target_compile_options(${lib} PRIVATE "/wd4267") From 160b1c8bbc79f03145cee766f3339d92b77ce326 Mon Sep 17 00:00:00 2001 From: d Date: Sun, 28 Mar 2021 02:01:04 +0200 Subject: [PATCH 05/10] Added Home, End, PageUp, PageDown events. Added handling for Home and End for input component --- include/ftxui/component/event.hpp | 7 +++++++ src/ftxui/component/event.cpp | 5 +++++ src/ftxui/component/input.cpp | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 14e826a..b006f49 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -44,6 +44,12 @@ struct Event { static const Event TabReverse; static const Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; + static const Event Home; + static const Event End; + + static const Event PageUp; + static const Event PageDown; + // --- Custom --- static Event Custom; @@ -53,6 +59,7 @@ struct Event { const std::string& input() const { return input_; } bool operator==(const Event& other) const { return input_ == other.input_; } + bool operator!=(const Event& other) const { return !operator==(other); } //--- State section ---------------------------------------------------------- private: diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index 29fc9c1..b8c6d7a 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -62,6 +62,11 @@ const Event Event::F9 = Event::Special("\x1B[20~"); const Event Event::F10 = Event::Special("\x1B[21~"); const Event Event::F11 = Event::Special("\x1B[21~"); // Doesn't exist const Event Event::F12 = Event::Special("\x1B[24~"); +const Event Event::Home = Event::Special({27, 91, 72}); +const Event Event::End = Event::Special({27, 91, 70}); +const Event Event::PageUp = Event::Special({27, 91, 53, 126}); +const Event Event::PageDown = Event::Special({27, 91, 54, 126}); + Event Event::Custom = Event::Special({0}); } // namespace ftxui diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 7a76055..0223c94 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -85,6 +85,16 @@ bool Input::OnEvent(Event event) { return true; } + if (event == Event::Home) { + cursor_position = 0; + return true; + } + + if (event == Event::End) { + cursor_position = (int)content.size(); + return true; + } + // Content if (event.is_character()) { content.insert(cursor_position, 1, event.character()); From 386a0f9eacbb69228ddf3efddc6c54d109582849 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Sun, 28 Mar 2021 18:14:43 +0200 Subject: [PATCH 06/10] Add tests for the input component. --- CMakeLists.txt | 3 +- src/ftxui/component/input_test.cpp | 158 +++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/ftxui/component/input_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ba4671d..0831fbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,9 +215,10 @@ if (FTXUI_BUILD_TESTS AND ${CMAKE_VERSION} VERSION_GREATER "3.11.4") add_executable(tests src/ftxui/component/container_test.cpp - src/ftxui/component/terminal_input_parser_test.cpp + src/ftxui/component/input_test.cpp src/ftxui/component/radiobox_test.cpp src/ftxui/component/receiver_test.cpp + src/ftxui/component/terminal_input_parser_test.cpp src/ftxui/component/toggle_test.cpp src/ftxui/dom/gauge_test.cpp src/ftxui/dom/hbox_test.cpp diff --git a/src/ftxui/component/input_test.cpp b/src/ftxui/component/input_test.cpp new file mode 100644 index 0000000..4bfc6b9 --- /dev/null +++ b/src/ftxui/component/input_test.cpp @@ -0,0 +1,158 @@ +#include "ftxui/component/input.hpp" + +#include "gtest/gtest.h" + +using namespace ftxui; + +TEST(InputTest, Init) { + Input input; + + EXPECT_EQ(input.content, L""); + EXPECT_EQ(input.placeholder, L""); + EXPECT_EQ(input.cursor_position, 0); +} + +TEST(InputTest, Type) { + Input input; + + input.OnEvent(Event::Character('a')); + EXPECT_EQ(input.content, L"a"); + EXPECT_EQ(input.cursor_position, 1u); + + input.OnEvent(Event::Character('b')); + EXPECT_EQ(input.content, L"ab"); + EXPECT_EQ(input.cursor_position, 2u); +} + +TEST(InputTest, Arrow) { + Input input; + + input.OnEvent(Event::Character('a')); + input.OnEvent(Event::Character('b')); + input.OnEvent(Event::Character('c')); + + EXPECT_EQ(input.cursor_position, 3u); + + input.OnEvent(Event::ArrowLeft); + EXPECT_EQ(input.cursor_position, 2u); + + input.OnEvent(Event::ArrowLeft); + EXPECT_EQ(input.cursor_position, 1u); + + input.OnEvent(Event::ArrowLeft); + EXPECT_EQ(input.cursor_position, 0u); + + input.OnEvent(Event::ArrowLeft); + EXPECT_EQ(input.cursor_position, 0u); + + input.OnEvent(Event::ArrowRight); + EXPECT_EQ(input.cursor_position, 1u); + + input.OnEvent(Event::ArrowRight); + EXPECT_EQ(input.cursor_position, 2u); + + input.OnEvent(Event::ArrowRight); + EXPECT_EQ(input.cursor_position, 3u); + + input.OnEvent(Event::ArrowRight); + EXPECT_EQ(input.cursor_position, 3u); +} + +TEST(InputTest, Insert) { + Input input; + + input.OnEvent(Event::Character('a')); + input.OnEvent(Event::Character('b')); + input.OnEvent(Event::Character('c')); + EXPECT_EQ(input.content, L"abc"); + + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::Character('-')); + EXPECT_EQ(input.content, L"a-bc"); + + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::Character('-')); + EXPECT_EQ(input.content, L"a--bc"); + + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::Character('-')); + EXPECT_EQ(input.content, L"-a--bc"); +} + +TEST(InputTest, Home) { + Input input; + + input.OnEvent(Event::Character('a')); + input.OnEvent(Event::Character('b')); + input.OnEvent(Event::Character('c')); + EXPECT_EQ(input.content, L"abc"); + + EXPECT_EQ(input.cursor_position, 3u); + input.OnEvent(Event::Home); + EXPECT_EQ(input.cursor_position, 0u); + + input.OnEvent(Event::Character('-')); + EXPECT_EQ(input.content, L"-abc"); +} + +TEST(InputTest, End) { + Input input; + + input.OnEvent(Event::Character('a')); + input.OnEvent(Event::Character('b')); + input.OnEvent(Event::Character('c')); + + input.OnEvent(Event::ArrowLeft); + input.OnEvent(Event::ArrowLeft); + + EXPECT_EQ(input.cursor_position, 1u); + input.OnEvent(Event::End); + EXPECT_EQ(input.cursor_position, 3u); +} + +TEST(InputTest, Delete) { + Input input; + + input.OnEvent(Event::Character('a')); + input.OnEvent(Event::Character('b')); + input.OnEvent(Event::Character('c')); + input.OnEvent(Event::ArrowLeft); + + EXPECT_EQ(input.content, L"abc"); + EXPECT_EQ(input.cursor_position, 2u); + + input.OnEvent(Event::Delete); + EXPECT_EQ(input.content, L"ab"); + EXPECT_EQ(input.cursor_position, 2u); + + input.OnEvent(Event::Delete); + EXPECT_EQ(input.content, L"ab"); + EXPECT_EQ(input.cursor_position, 2u); +} + +TEST(InputTest, Backspace) { + Input input; + + input.OnEvent(Event::Character('a')); + input.OnEvent(Event::Character('b')); + input.OnEvent(Event::Character('c')); + input.OnEvent(Event::ArrowLeft); + + EXPECT_EQ(input.content, L"abc"); + EXPECT_EQ(input.cursor_position, 2u); + + input.OnEvent(Event::Backspace); + EXPECT_EQ(input.content, L"ac"); + EXPECT_EQ(input.cursor_position, 1u); + + input.OnEvent(Event::Backspace); + EXPECT_EQ(input.content, L"c"); + EXPECT_EQ(input.cursor_position, 0u); + + input.OnEvent(Event::Backspace); + EXPECT_EQ(input.content, L"c"); + EXPECT_EQ(input.cursor_position, 0u); +} From e54d4643f5585fe5303f48d3e055f10f87abe7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=9A=E6=9C=A8=E9=89=89?= <740291272@qq.com> Date: Sat, 10 Apr 2021 23:37:32 +0800 Subject: [PATCH 07/10] Update terminal.cpp --- src/ftxui/screen/terminal.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ftxui/screen/terminal.cpp b/src/ftxui/screen/terminal.cpp index e86c82d..fea187e 100644 --- a/src/ftxui/screen/terminal.cpp +++ b/src/ftxui/screen/terminal.cpp @@ -6,7 +6,11 @@ #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX #define NOMINMAX +#endif + #include #else #include From c8c0857ce8dcc8b632ed9f6908eff77829f45e56 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Fri, 23 Apr 2021 14:09:12 +0200 Subject: [PATCH 08/10] Add todoman in "Project using FTXUI" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76bc123..2f480fe 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ Feel free to add your projects here: - [Pigeon ROS TUI](https://github.com/PigeonSensei/Pigeon_ros_tui) - [hastur](https://github.com/robinlinden/hastur) - [CryptoCalculator](https://github.com/brevis/CryptoCalculator) -- +- [todoman](https://github.com/aaleino/todoman) ## Hosted on: * [github](https://github.com/ArthurSonzogni/ftxui) From 4bc299aa3fcd03197f8050db5a5e7e589cea8fe8 Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sun, 25 Apr 2021 13:56:26 +0200 Subject: [PATCH 09/10] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2f480fe..f1bdfbc 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ A simple C++ library for terminal based user interface. * Support for [UTF8](https://en.wikipedia.org/wiki/UTF-8) and [fullwidth chars](https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms) (→ 测试) * No dependencies. * Cross platform (mostly). Linux (main target), Windows (experimental), Mac. + * Keyboard navigation. + * Mouse support (very soon) ## Operating systems - [![linux-gcc][badge.linux-gcc]][link.linux-gcc] From 176848e3f62321eb260d59b1204fc7d6352396ea Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sun, 25 Apr 2021 17:08:54 +0200 Subject: [PATCH 10/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1bdfbc..93f01de 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ A simple C++ library for terminal based user interface. * No dependencies. * Cross platform (mostly). Linux (main target), Windows (experimental), Mac. * Keyboard navigation. - * Mouse support (very soon) + * Mouse support (very soon, [feedback](https://github.com/ArthurSonzogni/FTXUI/issues/7#issuecomment-826339732) needed) ## Operating systems - [![linux-gcc][badge.linux-gcc]][link.linux-gcc]