From 3b4ab618a3475e5b393f845f13bad233feb2fa5b Mon Sep 17 00:00:00 2001 From: Arthur Sonzogni Date: Sun, 8 Aug 2021 23:25:20 +0200 Subject: [PATCH] Prefer std::string over std::wstring. (#179) In the past, FTXUI switched from std::string to std::wstring to support fullwidth characters. The reasons was that fullwidth characters can be stored inside a single wchar_t. Then FTXUI added support for combining characters. A single glygh doesn't even fit a wchar_t. Instead, a glyph can be arbitrary large. The usage of wstring doesn't really fit the new model and have several drawbacks: 1. It doesn't simplify the implementation of FTXUI, because of combining characters. 2. It reduces drawing performance by 2x. 3. It increase Screen's memory allocation by 2x. This patch converts FTXUI to use std::string internally. It now exposes std::string based API. The std::wstring API remains, but is now deprecated. Tests and examples haven't been update to show the breakage is limited. They will be updated in a second set of patches. Bug: https://github.com/ArthurSonzogni/FTXUI/issues/153 Co-authored-by: Tushar Maheshwari --- CMakeLists.txt | 3 +- cmake/ftxui_test.cmake | 1 + examples/component/button.cpp | 3 +- examples/component/composition.cpp | 3 +- examples/component/gallery.cpp | 6 +- examples/component/homescreen.cpp | 6 +- examples/component/input.cpp | 10 +- examples/component/menu2.cpp | 3 +- examples/component/menu_multiple.cpp | 9 +- examples/component/modal_dialog.cpp | 7 +- examples/component/print_key_press.cpp | 48 +-- examples/component/renderer.cpp | 3 +- examples/component/resizable_split.cpp | 3 +- examples/component/slider_rgb.cpp | 7 +- examples/component/toggle.cpp | 3 +- examples/dom/border.cpp | 11 +- examples/dom/color_gallery.cpp | 3 +- examples/dom/color_info_palette256.cpp | 23 +- examples/dom/color_truecolor_HSV.cpp | 15 +- examples/dom/color_truecolor_RGB.cpp | 15 +- examples/dom/dbox.cpp | 11 +- examples/dom/gauge.cpp | 17 +- examples/dom/hflow.cpp | 11 +- examples/dom/html_like.cpp | 3 +- examples/dom/package_manager.cpp | 29 +- examples/dom/paragraph.cpp | 13 +- examples/dom/separator.cpp | 11 +- examples/dom/size.cpp | 17 +- examples/dom/spinner.cpp | 23 +- examples/dom/style_blink.cpp | 11 +- examples/dom/style_bold.cpp | 11 +- examples/dom/style_color.cpp | 7 +- examples/dom/style_dim.cpp | 11 +- examples/dom/style_gallery.cpp | 13 +- examples/dom/style_inverted.cpp | 11 +- examples/dom/style_underlined.cpp | 11 +- examples/dom/vbox_hbox.cpp | 13 +- include/ftxui/component/component.hpp | 13 +- include/ftxui/component/component_options.hpp | 16 +- include/ftxui/component/deprecated.hpp | 17 + include/ftxui/component/event.hpp | 6 +- include/ftxui/dom/deprecated.hpp | 16 + include/ftxui/dom/elements.hpp | 8 +- include/ftxui/screen/color.hpp | 2 +- include/ftxui/screen/screen.hpp | 7 +- include/ftxui/screen/string.hpp | 7 +- include/ftxui/util/ref.hpp | 58 ++- src/ftxui/component/button.cpp | 2 +- src/ftxui/component/catch_event.cpp | 2 +- src/ftxui/component/checkbox.cpp | 10 +- src/ftxui/component/component.cpp | 3 +- src/ftxui/component/container.cpp | 6 +- src/ftxui/component/event.cpp | 9 +- src/ftxui/component/input.cpp | 88 ++++- src/ftxui/component/input_test.cpp | 10 +- src/ftxui/component/menu.cpp | 41 +- src/ftxui/component/radiobox.cpp | 51 ++- src/ftxui/component/renderer.cpp | 4 +- src/ftxui/component/resizable_split.cpp | 16 +- .../component/screen_interactive_test.cpp | 13 +- src/ftxui/component/slider.cpp | 18 +- .../component/terminal_input_parser_test.cpp | 2 +- src/ftxui/component/toggle.cpp | 34 +- src/ftxui/dom/benchmark_test.cpp | 4 +- src/ftxui/dom/border.cpp | 18 +- src/ftxui/dom/color.cpp | 8 +- src/ftxui/dom/flex.cpp | 6 +- src/ftxui/dom/gauge.cpp | 12 +- src/ftxui/dom/graph.cpp | 15 +- src/ftxui/dom/hbox.cpp | 4 +- src/ftxui/dom/hbox_test.cpp | 9 +- src/ftxui/dom/paragraph.cpp | 24 +- src/ftxui/dom/separator.cpp | 8 +- src/ftxui/dom/spinner.cpp | 352 +++++++++--------- src/ftxui/dom/text.cpp | 103 +++-- src/ftxui/dom/text_test.cpp | 13 +- src/ftxui/dom/util.cpp | 4 +- src/ftxui/dom/vbox.cpp | 4 +- src/ftxui/dom/vbox_test.cpp | 9 +- src/ftxui/screen/color.cpp | 35 +- src/ftxui/screen/screen.cpp | 90 +++-- src/ftxui/screen/string.cpp | 286 +++++++++++++- src/ftxui/screen/string_test.cpp | 47 +++ src/ftxui/screen/wcwidth.cpp | 315 +--------------- 84 files changed, 1234 insertions(+), 996 deletions(-) create mode 100644 include/ftxui/component/deprecated.hpp create mode 100644 include/ftxui/dom/deprecated.hpp create mode 100644 src/ftxui/screen/string_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d64ccb0..67a3bd8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ include(cmake/ftxui_git_version.cmake) project(ftxui LANGUAGES CXX - VERSION 0.7.${git_version} + VERSION 0.8.${git_version} ) option(FTXUI_BUILD_DOCS "Set to ON to build tests" ON) @@ -31,7 +31,6 @@ add_library(screen STATIC src/ftxui/screen/screen.cpp src/ftxui/screen/string.cpp src/ftxui/screen/terminal.cpp - src/ftxui/screen/wcwidth.cpp include/ftxui/screen/box.hpp include/ftxui/screen/color.hpp include/ftxui/screen/color_info.hpp diff --git a/cmake/ftxui_test.cmake b/cmake/ftxui_test.cmake index 8c73ff0c..33fc0d89 100644 --- a/cmake/ftxui_test.cmake +++ b/cmake/ftxui_test.cmake @@ -23,6 +23,7 @@ add_executable(tests src/ftxui/dom/hbox_test.cpp src/ftxui/dom/text_test.cpp src/ftxui/dom/vbox_test.cpp + src/ftxui/screen/string_test.cpp ) target_link_libraries(tests diff --git a/examples/component/button.cpp b/examples/component/button.cpp index f8bc4f3d..64805fe1 100644 --- a/examples/component/button.cpp +++ b/examples/component/button.cpp @@ -6,7 +6,8 @@ #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for ButtonOption #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for separator, gauge, Element, operator|, vbox, border using namespace ftxui; diff --git a/examples/component/composition.cpp b/examples/component/composition.cpp index 543bba33..6284329c 100644 --- a/examples/component/composition.cpp +++ b/examples/component/composition.cpp @@ -6,7 +6,8 @@ #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for ButtonOption #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, separator, Element, operator|, vbox, border +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for separator, Element, operator|, vbox, border using namespace ftxui; diff --git a/examples/component/gallery.cpp b/examples/component/gallery.cpp index 99f5af4c..c36d99f1 100644 --- a/examples/component/gallery.cpp +++ b/examples/component/gallery.cpp @@ -4,10 +4,12 @@ #include // for vector #include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Slider, Checkbox, Vertical, Renderer, Button, Input, Menu, Radiobox, Toggle +#include "ftxui/component/component.hpp" // for Slider, Checkbox, Vertical, Renderer, Button, Menu, Radiobox, Toggle #include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/deprecated.hpp" // for Input #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for separator, Element, operator|, size, xflex, text, WIDTH, hbox, vbox, EQUAL, border, GREATER_THAN +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for separator, operator|, Element, size, xflex, WIDTH, hbox, vbox, EQUAL, border, GREATER_THAN using namespace ftxui; diff --git a/examples/component/homescreen.cpp b/examples/component/homescreen.cpp index 3e41a426..4c863ee5 100644 --- a/examples/component/homescreen.cpp +++ b/examples/component/homescreen.cpp @@ -9,12 +9,14 @@ #include // for vector #include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, Tab, Toggle +#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Menu, Radiobox, Tab, Toggle #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for InputOption +#include "ftxui/component/deprecated.hpp" // for Input #include "ftxui/component/event.hpp" // for Event, Event::Custom #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, graph, separator, EQUAL, WIDTH, hcenter, bold, border, window, HEIGHT, Elements, hflow, flex_grow, frame, gauge, LESS_THAN, spinner, dim, GREATER_THAN +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, graph, separator, EQUAL, WIDTH, hcenter, bold, border, window, HEIGHT, Elements, hflow, flex_grow, frame, gauge, LESS_THAN, spinner, dim, GREATER_THAN #include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::Black, Color::Blue, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default using namespace ftxui; diff --git a/examples/component/input.cpp b/examples/component/input.cpp index 5d8e03cf..0ddf089c 100644 --- a/examples/component/input.cpp +++ b/examples/component/input.cpp @@ -1,12 +1,14 @@ #include // for allocator, __shared_ptr_access #include // for char_traits, operator+, wstring, basic_string -#include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Input, Renderer, Vertical -#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/captured_mouse.hpp" // for ftxui +#include "ftxui/component/component.hpp" // for Renderer, Vertical +#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for InputOption +#include "ftxui/component/deprecated.hpp" // for Input #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, hbox, separator, Element, operator|, vbox, border +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for hbox, separator, Element, operator|, vbox, border int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/component/menu2.cpp b/examples/component/menu2.cpp index 28c51a07..498b3e9e 100644 --- a/examples/component/menu2.cpp +++ b/examples/component/menu2.cpp @@ -8,7 +8,8 @@ #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for MenuOption #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, separator, bold, hcenter, vbox, hbox, gauge, Element, operator|, border +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for separator, bold, hcenter, vbox, hbox, gauge, Element, operator|, border #include "ftxui/screen/string.hpp" // for to_wstring int main(int argc, const char* argv[]) { diff --git a/examples/component/menu_multiple.cpp b/examples/component/menu_multiple.cpp index d1cc66f5..187b0d68 100644 --- a/examples/component/menu_multiple.cpp +++ b/examples/component/menu_multiple.cpp @@ -1,13 +1,14 @@ #include // for EXIT_SUCCESS -#include // for __shared_ptr_access -#include // for wstring, allocator, operator+, basic_string, char_traits -#include // for vector, __alloc_traits<>::value_type +#include // for allocator, __shared_ptr_access +#include // for wstring, operator+, basic_string, char_traits +#include // for vector, __alloc_traits<>::value_type #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Menu, Renderer, Horizontal, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, Element, operator|, window, flex, vbox +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for Element, operator|, window, flex, vbox #include "ftxui/screen/string.hpp" // for to_wstring using namespace ftxui; diff --git a/examples/component/modal_dialog.cpp b/examples/component/modal_dialog.cpp index 7c24a8b1..968dbe00 100644 --- a/examples/component/modal_dialog.cpp +++ b/examples/component/modal_dialog.cpp @@ -1,12 +1,13 @@ -#include // for allocator, __shared_ptr_access, shared_ptr -#include // for wstring, operator+, basic_string, char_traits +#include // for allocator, shared_ptr, __shared_ptr_access +#include // for wstring, basic_string, char_traits, operator+ #include // for vector #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Button, Renderer, Horizontal, Tab #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for Element, operator|, filler, text, hbox, separator, center, vbox, bold, border, clear_under, dbox, size, GREATER_THAN, HEIGHT +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for operator|, Element, filler, hbox, separator, center, vbox, bold, border, clear_under, dbox, size, GREATER_THAN, HEIGHT int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/component/print_key_press.cpp b/examples/component/print_key_press.cpp index bd825b50..8ded61f4 100644 --- a/examples/component/print_key_press.cpp +++ b/examples/component/print_key_press.cpp @@ -4,8 +4,8 @@ #include // for size_t #include // for max -#include // for shared_ptr -#include // for allocator, char_traits, operator+, wstring, basic_string, to_wstring, string +#include // for allocator, shared_ptr +#include // for char_traits, operator+, string, basic_string, to_string #include // for move #include // for vector @@ -18,56 +18,56 @@ using namespace ftxui; -std::wstring Stringify(Event event) { - std::wstring out; +std::string Stringify(Event event) { + std::string out; for (auto& it : event.input()) - out += L" " + std::to_wstring((unsigned int)it); + out += " " + std::to_string((unsigned int)it); - out = L"(" + out + L" ) -> "; + out = "(" + out + " ) -> "; if (event.is_character()) { - out += std::wstring(L"character(") + event.character() + L")"; + out += "character(" + event.character() + ")"; } else if (event.is_mouse()) { - out += L"mouse"; + out += "mouse"; switch (event.mouse().button) { case Mouse::Left: - out += L"_left"; + out += "_left"; break; case Mouse::Middle: - out += L"_middle"; + out += "_middle"; break; case Mouse::Right: - out += L"_right"; + out += "_right"; break; case Mouse::None: - out += L"_none"; + out += "_none"; break; case Mouse::WheelUp: - out += L"_wheel_up"; + out += "_wheel_up"; break; case Mouse::WheelDown: - out += L"_wheel_down"; + out += "_wheel_down"; break; } switch (event.mouse().motion) { case Mouse::Pressed: - out += L"_pressed"; + out += "_pressed"; break; case Mouse::Released: - out += L"_released"; + out += "_released"; break; } if (event.mouse().control) - out += L"_control"; + out += "_control"; if (event.mouse().shift) - out += L"_shift"; + out += "_shift"; if (event.mouse().meta) - out += L"_meta"; + out += "_meta"; - out += L"(" + // - std::to_wstring(event.mouse().x) + L"," + - std::to_wstring(event.mouse().y) + L")"; + out += "(" + // + std::to_string(event.mouse().x) + "," + + std::to_string(event.mouse().y) + ")"; } else { - out += L"(special)"; + out += "(special)"; } return out; } @@ -81,7 +81,7 @@ int main(int argc, const char* argv[]) { Elements children; for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) children.push_back(text(Stringify(keys[i]))); - return window(text(L"keys"), vbox(std::move(children))); + return window(text("keys"), vbox(std::move(children))); }); component = CatchEvent(component, [&](Event event) { diff --git a/examples/component/renderer.cpp b/examples/component/renderer.cpp index b80ea624..04d6d768 100644 --- a/examples/component/renderer.cpp +++ b/examples/component/renderer.cpp @@ -4,7 +4,8 @@ #include "ftxui/component/component.hpp" // for Renderer, Button, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for operator|, Element, text, bold, border, center, color +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for operator|, Element, bold, border, center, color #include "ftxui/screen/color.hpp" // for Color, Color::Red int main(int argc, const char* argv[]) { diff --git a/examples/component/resizable_split.cpp b/examples/component/resizable_split.cpp index cd925f8e..e7422942 100644 --- a/examples/component/resizable_split.cpp +++ b/examples/component/resizable_split.cpp @@ -4,7 +4,8 @@ #include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for Element, operator|, text, center, border +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for Element, operator|, center, border using namespace ftxui; diff --git a/examples/component/slider_rgb.cpp b/examples/component/slider_rgb.cpp index 3eb10e6b..e670001d 100644 --- a/examples/component/slider_rgb.cpp +++ b/examples/component/slider_rgb.cpp @@ -1,11 +1,12 @@ -#include // for allocator, __shared_ptr_access, shared_ptr -#include // for operator+, to_wstring, char_traits +#include // for allocator, shared_ptr, __shared_ptr_access +#include // for char_traits, operator+, to_wstring #include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/component.hpp" // for Slider, Renderer, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive -#include "ftxui/dom/elements.hpp" // for separator, Element, operator|, size, text, vbox, xflex, bgcolor, hbox, GREATER_THAN, WIDTH, border, HEIGHT, LESS_THAN +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for separator, operator|, Element, size, vbox, xflex, bgcolor, hbox, GREATER_THAN, WIDTH, border, HEIGHT, LESS_THAN #include "ftxui/screen/color.hpp" // for Color using namespace ftxui; diff --git a/examples/component/toggle.cpp b/examples/component/toggle.cpp index b56f2115..5683e9d2 100644 --- a/examples/component/toggle.cpp +++ b/examples/component/toggle.cpp @@ -6,7 +6,8 @@ #include "ftxui/component/component.hpp" // for Toggle, Renderer, Vertical #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive -#include "ftxui/dom/elements.hpp" // for text, hbox, vbox, Element +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for hbox, vbox, Element using namespace ftxui; diff --git a/examples/dom/border.cpp b/examples/dom/border.cpp index bd127012..8cd5119f 100644 --- a/examples/dom/border.cpp +++ b/examples/dom/border.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, vbox, border, Element, hbox +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/color_gallery.cpp b/examples/dom/color_gallery.cpp index 15c6fc05..d9d013a7 100644 --- a/examples/dom/color_gallery.cpp +++ b/examples/dom/color_gallery.cpp @@ -7,7 +7,8 @@ using namespace ftxui; #include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D -#include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, border +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, border #include "ftxui/dom/node.hpp" // for Render #include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight, Color::Palette256, ftxui diff --git a/examples/dom/color_info_palette256.cpp b/examples/dom/color_info_palette256.cpp index 0e172f47..aa32120a 100644 --- a/examples/dom/color_info_palette256.cpp +++ b/examples/dom/color_info_palette256.cpp @@ -1,17 +1,18 @@ -#include -#include -#include -#include -#include -#include +#include // for bgcolor, hbox, operator|, Elements, vbox, Element +#include // for ColorInfo +#include // for Dimension, Screen +#include // for allocator, string +#include // for move +#include // for vector -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" -#include "ftxui/screen/color.hpp" -#include "ftxui/screen/string.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color, Color::Palette256 +#include "ftxui/screen/string.hpp" // for to_wstring using namespace ftxui; -#include "./color_info_sorted_2d.ipp" // ColorInfoSorted2D. +#include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D int main(int argc, const char* argv[]) { std::vector> info_columns = ColorInfoSorted2D(); diff --git a/examples/dom/color_truecolor_HSV.cpp b/examples/dom/color_truecolor_HSV.cpp index 0aa63171..e299bb6a 100644 --- a/examples/dom/color_truecolor_HSV.cpp +++ b/examples/dom/color_truecolor_HSV.cpp @@ -1,11 +1,12 @@ -#include -#include -#include -#include +#include // for operator|, Elements, bgcolor, color, hbox, vbox, Element +#include // for Dimension, Screen +#include // for allocator +#include // for move -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" -#include "ftxui/screen/color.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/color_truecolor_RGB.cpp b/examples/dom/color_truecolor_RGB.cpp index 1fd632ae..21ccf65c 100644 --- a/examples/dom/color_truecolor_RGB.cpp +++ b/examples/dom/color_truecolor_RGB.cpp @@ -1,11 +1,12 @@ -#include -#include -#include -#include +#include // for hbox, bgcolor, operator|, vbox, Elements, window, Element +#include // for Dimension, Screen +#include // for allocator +#include // for move -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" -#include "ftxui/screen/color.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/dbox.cpp b/examples/dom/dbox.cpp index 851e3ce4..fa901f01 100644 --- a/examples/dom/dbox.cpp +++ b/examples/dom/dbox.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, border, Element, vbox, center, dbox +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/gauge.cpp b/examples/dom/gauge.cpp index ae882e83..5daeb207 100644 --- a/examples/dom/gauge.cpp +++ b/examples/dom/gauge.cpp @@ -1,12 +1,13 @@ -#include -#include -#include -#include -#include -#include +#include // for operator""s, chrono_literals +#include // for gauge, operator|, flex, hbox, Element +#include // for Screen +#include // for cout, endl, ostream +#include // for allocator, operator+, char_traits, operator<<, to_wstring, basic_string, string, wstring +#include // for sleep_for -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/hflow.cpp b/examples/dom/hflow.cpp index 02b9a71a..e137075d 100644 --- a/examples/dom/hflow.cpp +++ b/examples/dom/hflow.cpp @@ -1,12 +1,13 @@ #include // for size_t -#include // for operator|, size, Element, text, hcenter, Decorator, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN +#include // for operator|, size, Element, hcenter, Decorator, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN #include // for Dimension, Screen #include // for to_wstring -#include // for shared_ptr -#include // for allocator, operator+, char_traits, wstring +#include // for allocator, shared_ptr +#include // for operator+, char_traits, wstring -#include "ftxui/dom/node.hpp" // for Render -#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/html_like.cpp b/examples/dom/html_like.cpp index 3cb099ec..4bfd48b8 100644 --- a/examples/dom/html_like.cpp +++ b/examples/dom/html_like.cpp @@ -5,7 +5,8 @@ #include // for operator<<, string #include // for sleep_for -#include "ftxui/dom/elements.hpp" // for paragraph, text, operator|, Element, border, color, hflow, spinner, vbox, bold, dim, underlined +#include "ftxui/dom/deprecated.hpp" // for paragraph, text +#include "ftxui/dom/elements.hpp" // for operator|, Element, border, color, hflow, spinner, vbox, bold, dim, underlined #include "ftxui/dom/node.hpp" // for Render #include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/color.hpp" // for Color, Color::Red diff --git a/examples/dom/package_manager.cpp b/examples/dom/package_manager.cpp index d2c0d749..7ff8be3a 100644 --- a/examples/dom/package_manager.cpp +++ b/examples/dom/package_manager.cpp @@ -1,18 +1,19 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include // for operator""s, chrono_literals +#include // for operator|, Element, hbox, bold, color, filler, separator, vbox, window, gauge, size, dim, EQUAL, WIDTH +#include // for Screen, Dimension +#include // for to_wstring +#include // for cout, endl, ostream +#include // for list, operator!=, _List_iterator, _List_iterator<>::_Self +#include // for allocator, shared_ptr, allocator_traits<>::value_type +#include // for wstring, operator<<, string +#include // for sleep_for +#include // for move +#include // for vector -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" -#include "ftxui/screen/color.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color, Color::Green, Color::Red, Color::RedLight int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/paragraph.cpp b/examples/dom/paragraph.cpp index 9a1a614a..e0ed815d 100644 --- a/examples/dom/paragraph.cpp +++ b/examples/dom/paragraph.cpp @@ -1,10 +1,11 @@ -#include -#include -#include -#include +#include // for getchar +#include // for operator|, hflow, border, Element, hbox, flex, vbox +#include // for Dimension, Screen +#include // for allocator, wstring -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for paragraph +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/separator.cpp b/examples/dom/separator.cpp index 0f258a34..e0afefb1 100644 --- a/examples/dom/separator.cpp +++ b/examples/dom/separator.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for center, separator, operator|, flex, Element, vbox, hbox, border +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/size.cpp b/examples/dom/size.cpp index bc736d42..0a044cb9 100644 --- a/examples/dom/size.cpp +++ b/examples/dom/size.cpp @@ -1,12 +1,13 @@ -#include -#include -#include -#include -#include -#include +#include // for operator|, Element, hcenter, hbox, size, window, Elements, bold, dim, EQUAL, WIDTH +#include // for Screen, Dimension +#include // for to_wstring +#include // for allocator, shared_ptr +#include // for wstring +#include // for move -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/spinner.cpp b/examples/dom/spinner.cpp index e5c3a262..99788e88 100644 --- a/examples/dom/spinner.cpp +++ b/examples/dom/spinner.cpp @@ -1,15 +1,16 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include // for operator""s, chrono_literals +#include // for Element, operator|, separator, filler, hbox, size, spinner, vbox, bold, border, EQUAL, WIDTH +#include // for Screen, Dimension +#include // for to_wstring +#include // for cout, endl, ostream +#include // for operator<<, string +#include // for sleep_for +#include // for move +#include // for vector -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_blink.cpp b/examples/dom/style_blink.cpp index 64645bf6..191a22a8 100644 --- a/examples/dom/style_blink.cpp +++ b/examples/dom/style_blink.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, blink, hbox, Element +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_bold.cpp b/examples/dom/style_bold.cpp index df0dd6e3..e8c7de6e 100644 --- a/examples/dom/style_bold.cpp +++ b/examples/dom/style_bold.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, bold, hbox, Element +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_color.cpp b/examples/dom/style_color.cpp index 47d89287..2d9ba1e0 100644 --- a/examples/dom/style_color.cpp +++ b/examples/dom/style_color.cpp @@ -1,9 +1,10 @@ #include // for Dimension, Screen #include // for allocator -#include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, filler, hbox -#include "ftxui/dom/node.hpp" // for Render -#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for bgcolor, color, vbox, filler, hbox +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight int main(int argc, const char* argv[]) { diff --git a/examples/dom/style_dim.cpp b/examples/dom/style_dim.cpp index 61b73d70..dce4c60e 100644 --- a/examples/dom/style_dim.cpp +++ b/examples/dom/style_dim.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, dim, hbox, Element +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_gallery.cpp b/examples/dom/style_gallery.cpp index 4439aa63..4f010dea 100644 --- a/examples/dom/style_gallery.cpp +++ b/examples/dom/style_gallery.cpp @@ -1,10 +1,11 @@ -#include -#include -#include +#include // for operator|, Element, bgcolor, color, blink, bold, dim, inverted, underlined, hbox +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" -#include "ftxui/screen/color.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/color.hpp" // for Color, Color::Blue int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_inverted.cpp b/examples/dom/style_inverted.cpp index 3712deba..94f7ff55 100644 --- a/examples/dom/style_inverted.cpp +++ b/examples/dom/style_inverted.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, inverted, hbox, Element +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/style_underlined.cpp b/examples/dom/style_underlined.cpp index 52a8d7ad..0019e4b1 100644 --- a/examples/dom/style_underlined.cpp +++ b/examples/dom/style_underlined.cpp @@ -1,9 +1,10 @@ -#include -#include -#include +#include // for operator|, underlined, hbox, Element +#include // for Dimension, Screen +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/examples/dom/vbox_hbox.cpp b/examples/dom/vbox_hbox.cpp index 65b55a85..20b47f75 100644 --- a/examples/dom/vbox_hbox.cpp +++ b/examples/dom/vbox_hbox.cpp @@ -1,10 +1,11 @@ -#include -#include -#include -#include +#include // for getchar +#include // for filler, hbox, vbox +#include // for Screen, Dimension +#include // for allocator -#include "ftxui/dom/node.hpp" -#include "ftxui/screen/box.hpp" +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui int main(int argc, const char* argv[]) { using namespace ftxui; diff --git a/include/ftxui/component/component.hpp b/include/ftxui/component/component.hpp index 3b7f3ff5..beab06fe 100644 --- a/include/ftxui/component/component.hpp +++ b/include/ftxui/component/component.hpp @@ -9,7 +9,7 @@ #include "ftxui/component/component_base.hpp" // for Component, Components #include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, InputOption, MenuOption, RadioboxOption, ToggleOption #include "ftxui/dom/elements.hpp" // for Element -#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef, StringRef +#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef, ConstStringListRef, StringRef namespace ftxui { struct ButtonOption; @@ -34,17 +34,17 @@ Component Checkbox(ConstStringRef label, Component Input(StringRef content, ConstStringRef placeholder, Ref option = {}); -Component Menu(const std::vector* entries, +Component Menu(ConstStringListRef entries, int* selected_, Ref = {}); -Component Radiobox(const std::vector* entries, +Component Radiobox(ConstStringListRef entries, int* selected_, Ref option = {}); -Component Toggle(const std::vector* entries, +Component Toggle(ConstStringListRef entries, int* selected, Ref option = {}); template // T = {int, float, long} -Component Slider(StringRef label, T* value, T min, T max, T increment); +Component Slider(ConstStringRef label, T* value, T min, T max, T increment); Component ResizableSplitLeft(Component main, Component back, int* main_size); Component ResizableSplitRight(Component main, Component back, int* main_size); Component ResizableSplitTop(Component main, Component back, int* main_size); @@ -65,6 +65,9 @@ Component Tab(Components children, int* selector); } // namespace ftxui +// Include component using the old deprecated wstring. +#include "ftxui/component/deprecated.hpp" + #endif /* end of include guard: FTXUI_COMPONENT_HPP */ // Copyright 2021 Arthur Sonzogni. All rights reserved. diff --git a/include/ftxui/component/component_options.hpp b/include/ftxui/component/component_options.hpp index 34dc2953..0d9ab303 100644 --- a/include/ftxui/component/component_options.hpp +++ b/include/ftxui/component/component_options.hpp @@ -33,10 +33,10 @@ struct ButtonOption { /// @brief Option for the Checkbox component. /// @ingroup component struct CheckboxOption { - std::wstring style_checked = L"▣ "; ///< Prefix for a "checked" state. - std::wstring style_unchecked = L"☐ "; ///< Prefix for a "unchecked" state. - Decorator style_focused = inverted; ///< Decorator used when focused. - Decorator style_unfocused = nothing; ///< Decorator used when unfocused. + std::string style_checked = "▣ "; ///< Prefix for a "checked" state. + std::string style_unchecked = "☐ "; ///< Prefix for a "unchecked" state. + Decorator style_focused = inverted; ///< Decorator used when focused. + Decorator style_unfocused = nothing; ///< Decorator used when unfocused. /// Called when the user change the state. std::function on_change = []() {}; @@ -59,10 +59,10 @@ struct InputOption { /// @brief Option for the Radiobox component. /// @ingroup component struct RadioboxOption { - std::wstring style_checked = L"◉ "; ///< Prefix for a "checked" state. - std::wstring style_unchecked = L"○ "; ///< Prefix for a "unchecked" state. - Decorator style_focused = inverted; ///< Decorator used when focused. - Decorator style_unfocused = nothing; ///< Decorator used when unfocused. + std::string style_checked = "◉ "; ///< Prefix for a "checked" state. + std::string style_unchecked = "○ "; ///< Prefix for a "unchecked" state. + Decorator style_focused = inverted; ///< Decorator used when focused. + Decorator style_unfocused = nothing; ///< Decorator used when unfocused. /// Called when the selected entry changes. std::function on_change = []() {}; diff --git a/include/ftxui/component/deprecated.hpp b/include/ftxui/component/deprecated.hpp new file mode 100644 index 00000000..7a3178bd --- /dev/null +++ b/include/ftxui/component/deprecated.hpp @@ -0,0 +1,17 @@ +#ifndef FTXUI_COMPONENT_DEPRECATED_HPP +#define FTXUI_COMPONENT_DEPRECATED_HPP + +#include "ftxui/component/component.hpp" + +namespace ftxui { + +Component Input(WideStringRef content, + ConstStringRef placeholder, + Ref option = {}); +} // namespace ftxui + +#endif /* FTXUI_COMPONENT_DEPRECATED_HPP */ + +// 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. diff --git a/include/ftxui/component/event.hpp b/include/ftxui/component/event.hpp index 3096a86a..ef6190a2 100644 --- a/include/ftxui/component/event.hpp +++ b/include/ftxui/component/event.hpp @@ -24,10 +24,9 @@ class ComponentBase; /// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html struct Event { // --- Constructor section --------------------------------------------------- + static Event Character(std::string); static Event Character(char); static Event Character(wchar_t); - - static Event Character(std::string); static Event Special(std::string); static Event Mouse(std::string, Mouse mouse); static Event CursorReporting(std::string, int x, int y); @@ -58,7 +57,7 @@ struct Event { //--- Method section --------------------------------------------------------- bool is_character() const { return type_ == Type::Character; } - wchar_t character() const { return character_; } + std::string character() const { return input_; } bool is_mouse() const { return type_ == Type::Mouse; } struct Mouse& mouse() { @@ -92,7 +91,6 @@ struct Event { }; union { - wchar_t character_ = U'?'; struct Mouse mouse_; struct Cursor cursor_; }; diff --git a/include/ftxui/dom/deprecated.hpp b/include/ftxui/dom/deprecated.hpp new file mode 100644 index 00000000..7f537cd7 --- /dev/null +++ b/include/ftxui/dom/deprecated.hpp @@ -0,0 +1,16 @@ +#ifndef FTXUI_DOM_DEPRECRATED_HPP +#define FTXUI_DOM_DEPRECRATED_HPP + +#include "ftxui/dom/elements.hpp" + +namespace ftxui { +Element text(std::wstring text); +Element vtext(std::wstring text); +Elements paragraph(std::wstring text); +} // namespace ftxui + +#endif /* end of include guard: FTXUI_DOM_DEPRECRATED_HPP */ + +// 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. diff --git a/include/ftxui/dom/elements.hpp b/include/ftxui/dom/elements.hpp index b9be11b0..4a2dd9e5 100644 --- a/include/ftxui/dom/elements.hpp +++ b/include/ftxui/dom/elements.hpp @@ -26,8 +26,8 @@ Elements operator|(Elements, Decorator); Decorator operator|(Decorator, Decorator); // --- Widget --- -Element text(std::wstring text); -Element vtext(std::wstring text); +Element text(std::string text); +Element vtext(std::string text); Element separator(void); Element separator(Pixel); Element gauge(float ratio); @@ -35,7 +35,7 @@ Element border(Element); Decorator borderWith(Pixel); Element window(Element title, Element content); Element spinner(int charset_index, size_t image_index); -Elements paragraph(std::wstring text); // Use inside hflow(). Split by space. +Elements paragraph(std::string text); // Use inside hflow(). Split by space. Element graph(GraphFunction); // -- Decorator --- @@ -112,6 +112,8 @@ Dimensions Fit(Element&); // Make container able to take any number of children as input. #include "ftxui/dom/take_any_args.hpp" +// Include old definitions using wstring. +#include "ftxui/dom/deprecated.hpp" #endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */ // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/include/ftxui/screen/color.hpp b/include/ftxui/screen/color.hpp index e8edbcb8..521c7cd1 100644 --- a/include/ftxui/screen/color.hpp +++ b/include/ftxui/screen/color.hpp @@ -303,7 +303,7 @@ class Color { bool operator==(const Color& rhs) const; bool operator!=(const Color& rhs) const; - std::wstring Print(bool is_background_color) const; + std::string Print(bool is_background_color) const; private: enum class ColorType : uint8_t { diff --git a/include/ftxui/screen/screen.hpp b/include/ftxui/screen/screen.hpp index 37f2096f..5120472a 100644 --- a/include/ftxui/screen/screen.hpp +++ b/include/ftxui/screen/screen.hpp @@ -2,7 +2,7 @@ #define FTXUI_SCREEN_SCREEN #include -#include // for allocator, wstring, string, basic_string +#include // for string, allocator, basic_string #include // for vector #include "ftxui/screen/box.hpp" // for Box @@ -16,8 +16,7 @@ namespace ftxui { struct Pixel { // The graphemes stored into the pixel. To support combining characters, // like: a⃦, this can potentially contains multiple codepoitns. - // Required: character.size() >= 1; - std::wstring character = L" "; + std::string character = " "; // Colors: Color background_color = Color::Default; @@ -55,7 +54,7 @@ class Screen { static Screen Create(Dimensions width, Dimensions height); // Node write into the screen using Screen::at. - wchar_t& at(int x, int y); + std::string& at(int x, int y); Pixel& PixelAt(int x, int y); // Convert the screen into a printable string in the terminal. diff --git a/include/ftxui/screen/string.hpp b/include/ftxui/screen/string.hpp index 8e1f0a46..cc78dabc 100644 --- a/include/ftxui/screen/string.hpp +++ b/include/ftxui/screen/string.hpp @@ -2,6 +2,7 @@ #define FTXUI_SCREEN_STRING_HPP #include +#include namespace ftxui { std::string to_string(const std::wstring& s); @@ -12,12 +13,10 @@ std::wstring to_wstring(T s) { return to_wstring(std::to_string(s)); } -int wchar_width(char32_t); int wchar_width(wchar_t); -int wchar_width_cjk(char32_t); -int wchar_width_cjk(wchar_t); int wstring_width(const std::wstring&); -int wstring_width_cjk(const std::wstring&); +int string_width(const std::string&); +std::vector Utf8ToGlyphs(const std::string& input); } // namespace ftxui diff --git a/include/ftxui/util/ref.hpp b/include/ftxui/util/ref.hpp index 73b76d19..2eb7eb5f 100644 --- a/include/ftxui/util/ref.hpp +++ b/include/ftxui/util/ref.hpp @@ -42,11 +42,27 @@ class Ref { /// class convert multiple mutable string toward a shared representation. class StringRef { public: - StringRef(std::wstring* ref) : address_(ref) {} - StringRef(std::wstring ref) : owned_(std::move(ref)) {} - StringRef(const wchar_t* ref) : StringRef(std::wstring(ref)) {} - StringRef(const char* ref) : StringRef(to_wstring(std::string(ref))) {} - StringRef(std::string ref) : StringRef(to_wstring(std::move(ref))) {} + StringRef(std::string* ref) : address_(ref) {} + StringRef(std::string ref) : owned_(std::move(ref)) {} + StringRef(const wchar_t* ref) : StringRef(to_string(std::wstring(ref))) {} + StringRef(const char* ref) : StringRef(std::string(ref)) {} + std::string& operator*() { return address_ ? *address_ : owned_; } + std::string* operator->() { return address_ ? address_ : &owned_; } + + private: + std::string owned_; + std::string* address_ = nullptr; +}; + +/// @brief An adapter. Own or reference a constant string. For convenience, this +/// class convert multiple mutable string toward a shared representation. +class WideStringRef { + public: + WideStringRef(std::wstring* ref) : address_(ref) {} + WideStringRef(std::wstring ref) : owned_(std::move(ref)) {} + WideStringRef(const wchar_t* ref) : WideStringRef(std::wstring(ref)) {} + WideStringRef(const char* ref) + : WideStringRef(to_wstring(std::string(ref))) {} std::wstring& operator*() { return address_ ? *address_ : owned_; } std::wstring* operator->() { return address_ ? address_ : &owned_; } @@ -59,19 +75,35 @@ class StringRef { /// class convert multiple immutable string toward a shared representation. class ConstStringRef { public: - ConstStringRef(const std::wstring* ref) : address_(ref) {} - ConstStringRef(std::wstring ref) : owned_(std::move(ref)) {} + ConstStringRef(const std::string* ref) : address_(ref) {} + ConstStringRef(const std::wstring* ref) : ConstStringRef(to_string(*ref)) {} + ConstStringRef(std::string ref) : owned_(std::move(ref)) {} + ConstStringRef(std::wstring ref) : ConstStringRef(to_string(ref)) {} ConstStringRef(const wchar_t* ref) : ConstStringRef(std::wstring(ref)) {} ConstStringRef(const char* ref) : ConstStringRef(to_wstring(std::string(ref))) {} - ConstStringRef(std::string ref) - : ConstStringRef(to_wstring(std::move(ref))) {} - const std::wstring& operator*() { return address_ ? *address_ : owned_; } - const std::wstring* operator->() { return address_ ? address_ : &owned_; } + const std::string& operator*() { return address_ ? *address_ : owned_; } + const std::string* operator->() { return address_ ? address_ : &owned_; } private: - const std::wstring owned_; - const std::wstring* address_ = nullptr; + const std::string owned_; + const std::string* address_ = nullptr; +}; + +/// @brief An adapter. Reference a list of strings. +class ConstStringListRef { + public: + ConstStringListRef(const std::vector* ref) : ref_(ref) {} + ConstStringListRef(const std::vector* ref) : ref_wide_(ref) {} + + size_t size() const { return ref_ ? ref_->size() : ref_wide_->size(); } + std::string operator[](size_t i) const { + return ref_ ? (*ref_)[i] : to_string((*ref_wide_)[i]); + } + + private: + const std::vector* ref_ = nullptr; + const std::vector* ref_wide_ = nullptr; }; } // namespace ftxui diff --git a/src/ftxui/component/button.cpp b/src/ftxui/component/button.cpp index b540e2d7..5697f71a 100644 --- a/src/ftxui/component/button.cpp +++ b/src/ftxui/component/button.cpp @@ -75,7 +75,7 @@ class ButtonBase : public ComponentBase { /// /// ```cpp /// auto screen = ScreenInteractive::FitComponent(); -/// std::wstring label = L"Click to quit"; +/// std::string label = "Click to quit"; /// Component button = Button(&label, screen.ExitLoopClosure()); /// screen.Loop(button) /// ``` diff --git a/src/ftxui/component/catch_event.cpp b/src/ftxui/component/catch_event.cpp index 59ba1aa7..aec519d3 100644 --- a/src/ftxui/component/catch_event.cpp +++ b/src/ftxui/component/catch_event.cpp @@ -37,7 +37,7 @@ class CatchEventBase : public ComponentBase { /// ```cpp /// auto screen = ScreenInteractive::TerminalOutput(); /// auto renderer = Renderer([] { -/// return text(L"My interface"); +/// return text("My interface"); /// }); /// screen.Loop(renderer); /// ``` diff --git a/src/ftxui/component/checkbox.cpp b/src/ftxui/component/checkbox.cpp index 70e5d2e7..19f5edcd 100644 --- a/src/ftxui/component/checkbox.cpp +++ b/src/ftxui/component/checkbox.cpp @@ -22,10 +22,10 @@ class CheckboxBase : public ComponentBase { #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft terminal do not use fonts able to render properly the default // radiobox glyph. - if (option_->style_checked == L"▣ ") - option_->style_checked = L"[X]"; - if (option_->style_unchecked == L"☐ ") - option_->style_unchecked = L"[ ]"; + if (option_->style_checked == "▣ ") + option_->style_checked = "[X]"; + if (option_->style_unchecked == "☐ ") + option_->style_unchecked = "[ ]"; #endif } @@ -91,7 +91,7 @@ class CheckboxBase : public ComponentBase { /// /// ```cpp /// auto screen = ScreenInteractive::FitComponent(); -/// std::wstring label = L"Make a sandwidth"; +/// std::string label = "Make a sandwidth"; /// bool checked = false; /// Component checkbox = Checkbox(&label, &checked); /// screen.Loop(checkbox) diff --git a/src/ftxui/component/component.cpp b/src/ftxui/component/component.cpp index 9d892596..db8a22d7 100644 --- a/src/ftxui/component/component.cpp +++ b/src/ftxui/component/component.cpp @@ -3,6 +3,7 @@ #include // for assert #include // for begin, end #include // for move +#include // for vector, __alloc_traits<>::value_type #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface #include "ftxui/component/component.hpp" @@ -82,7 +83,7 @@ Element ComponentBase::Render() { if (children_.size() == 1) return children_.front()->Render(); - return text(L"Not implemented component"); + return text("Not implemented component"); } /// @brief Called in response to an event. diff --git a/src/ftxui/component/container.cpp b/src/ftxui/component/container.cpp index 3c2008cc..499b948d 100644 --- a/src/ftxui/component/container.cpp +++ b/src/ftxui/component/container.cpp @@ -93,7 +93,7 @@ class VerticalContainer : public ContainerBase { for (auto& it : children_) elements.push_back(it->Render()); if (elements.size() == 0) - return text(L"Empty container"); + return text("Empty container"); return vbox(std::move(elements)); } @@ -122,7 +122,7 @@ class HorizontalContainer : public ContainerBase { for (auto& it : children_) elements.push_back(it->Render()); if (elements.size() == 0) - return text(L"Empty container"); + return text("Empty container"); return hbox(std::move(elements)); } @@ -150,7 +150,7 @@ class TabContainer : public ContainerBase { Component active_child = ActiveChild(); if (active_child) return active_child->Render(); - return text(L"Empty container"); + return text("Empty container"); } bool OnMouseEvent(Event event) override { diff --git a/src/ftxui/component/event.cpp b/src/ftxui/component/event.cpp index c90228e5..ecb8c0fa 100644 --- a/src/ftxui/component/event.cpp +++ b/src/ftxui/component/event.cpp @@ -9,7 +9,6 @@ namespace ftxui { // static Event Event::Character(std::string input) { Event event; - event.character_ = to_wstring(input)[0]; event.input_ = std::move(input); event.type_ = Type::Character; return event; @@ -17,16 +16,12 @@ Event Event::Character(std::string input) { // static Event Event::Character(char c) { - return Character(wchar_t(c)); + return Event::Character(std::string{c}); } // static Event Event::Character(wchar_t c) { - Event event; - event.input_ = {(char)c}; - event.type_ = Type::Character; - event.character_ = c; - return event; + return Event::Character(to_string(std::wstring{c})); } // static diff --git a/src/ftxui/component/input.cpp b/src/ftxui/component/input.cpp index 7eded8b5..8191bf1f 100644 --- a/src/ftxui/component/input.cpp +++ b/src/ftxui/component/input.cpp @@ -8,21 +8,24 @@ #include "ftxui/component/component.hpp" // for Make, Input #include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_options.hpp" // for InputOption +#include "ftxui/component/deprecated.hpp" // for Input #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Custom, Event::Delete, Event::End, Event::Home, Event::Return #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed #include "ftxui/component/screen_interactive.hpp" // for Component -#include "ftxui/dom/elements.hpp" // for operator|, Element, text, reflect, dim, flex, focus, inverted, hbox, size, frame, select, underlined, Decorator, EQUAL, HEIGHT +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for operator|, Element, reflect, text, dim, flex, focus, inverted, hbox, size, frame, select, underlined, Decorator, EQUAL, HEIGHT #include "ftxui/screen/box.hpp" // for Box -#include "ftxui/util/ref.hpp" // for StringRef, Ref, ConstStringRef +#include "ftxui/screen/string.hpp" // for to_wstring, to_string +#include "ftxui/util/ref.hpp" // for WideStringRef, Ref, ConstStringRef, StringRef namespace ftxui { // An input box. The user can type text into it. -class InputBase : public ComponentBase { +class WideInputBase : public ComponentBase { public: - InputBase(StringRef content, - ConstStringRef placeholder, - Ref option) + WideInputBase(WideStringRef content, + ConstStringRef placeholder, + Ref option) : content_(content), placeholder_(placeholder), option_(option) {} int& cursor_position() { return *(option_->cursor_position); } @@ -132,7 +135,7 @@ class InputBase : public ComponentBase { // Content if (event.is_character()) { - content_->insert(cursor_position(), 1, event.character()); + content_->insert(cursor_position(), 1, to_wstring(event.character())[0]); cursor_position()++; option_->on_change(); return true; @@ -165,7 +168,7 @@ class InputBase : public ComponentBase { bool Focusable() const final { return true; } - StringRef content_; + WideStringRef content_; ConstStringRef placeholder_; Box input_box_; @@ -173,6 +176,43 @@ class InputBase : public ComponentBase { Ref option_; }; +// An input box. The user can type text into it. +// For convenience, the std::string version of Input simply wrap a +// WideInputBase. +// TODO(arthursonzogni): Provide an implementation handling std::string natively +// and adds better support for combining characters. +class InputBase : public ComponentBase { + public: + InputBase(StringRef content, + ConstStringRef placeholder, + Ref option) + : content_(std::move(content)), + wrapped_content_(to_wstring(*content_)), + wrapped_input_(&wrapped_content_, + std::move(placeholder), + std::move(option)) {} + + Element Render() override { + wrapped_content_ = to_wstring(*content_); + return wrapped_input_.Render(); + } + + bool OnEvent(Event event) override { + wrapped_content_ = to_wstring(*content_); + if (wrapped_input_.OnEvent(event)) { + content_ = to_string(wrapped_content_); + return true; + } + return false; + } + + bool Focusable() const final { return true; } + + StringRef content_; + std::wstring wrapped_content_; + WideInputBase wrapped_input_; +}; + /// @brief An input box for editing text. /// @param content The editable content. /// @param placeholder The text displayed when content is still empty. @@ -184,8 +224,8 @@ class InputBase : public ComponentBase { /// /// ```cpp /// auto screen = ScreenInteractive::FitComponent(); -/// std::wstring content= L""; -/// std::wstring placeholder = L"placeholder"; +/// std::string content= ""; +/// std::string placeholder = "placeholder"; /// Component input = Input(&content, &placeholder); /// screen.Loop(input); /// ``` @@ -201,6 +241,34 @@ Component Input(StringRef content, return Make(content, placeholder, std::move(option)); } +/// @brief . An input box for editing text. +/// @param content The editable content. +/// @param placeholder The text displayed when content is still empty. +/// @param option Additional optional parameters. +/// @ingroup component +/// @see InputBase +/// +/// ### Example +/// +/// ```cpp +/// auto screen = ScreenInteractive::FitComponent(); +/// std::string content= ""; +/// std::string placeholder = "placeholder"; +/// Component input = Input(&content, &placeholder); +/// screen.Loop(input); +/// ``` +/// +/// ### Output +/// +/// ```bash +/// placeholder +/// ``` +Component Input(WideStringRef content, + ConstStringRef placeholder, + Ref option) { + return Make(content, placeholder, std::move(option)); +} + } // namespace ftxui // Copyright 2020 Arthur Sonzogni. All rights reserved. diff --git a/src/ftxui/component/input_test.cpp b/src/ftxui/component/input_test.cpp index 94a26e20..da1f49ca 100644 --- a/src/ftxui/component/input_test.cpp +++ b/src/ftxui/component/input_test.cpp @@ -4,9 +4,9 @@ #include // for wstring #include "ftxui/component/captured_mouse.hpp" // for ftxui -#include "ftxui/component/component.hpp" // for Input #include "ftxui/component/component_base.hpp" // for ComponentBase, Component #include "ftxui/component/component_options.hpp" // for InputOption +#include "ftxui/component/deprecated.hpp" // for Input #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Delete, Event::End, Event::Home #include "ftxui/dom/elements.hpp" // for Fit #include "ftxui/dom/node.hpp" // for Render @@ -42,8 +42,8 @@ TEST(InputTest, Type) { auto document = input->Render(); auto screen = Screen::Create(Dimension::Fit(document)); Render(screen, document); - EXPECT_EQ(screen.PixelAt(0, 0).character, L"a"); - EXPECT_EQ(screen.PixelAt(1, 0).character, L"b"); + EXPECT_EQ(screen.PixelAt(0, 0).character, "a"); + EXPECT_EQ(screen.PixelAt(1, 0).character, "b"); } TEST(InputTest, TypePassword) { @@ -64,8 +64,8 @@ TEST(InputTest, TypePassword) { auto document = input->Render(); auto screen = Screen::Create(Dimension::Fit(document)); Render(screen, document); - EXPECT_EQ(screen.PixelAt(0, 0).character, L"•"); - EXPECT_EQ(screen.PixelAt(1, 0).character, L"•"); + EXPECT_EQ(screen.PixelAt(0, 0).character, "•"); + EXPECT_EQ(screen.PixelAt(1, 0).character, "•"); } TEST(InputTest, Arrow) { diff --git a/src/ftxui/component/menu.cpp b/src/ftxui/component/menu.cpp index 3342b224..8694aa03 100644 --- a/src/ftxui/component/menu.cpp +++ b/src/ftxui/component/menu.cpp @@ -2,7 +2,7 @@ #include // for max, min #include // for function #include // for shared_ptr, allocator_traits<>::value_type -#include // for operator+, wstring +#include // for operator+, string #include // for move #include // for vector, __alloc_traits<>::value_type @@ -23,16 +23,14 @@ namespace ftxui { /// @ingroup component class MenuBase : public ComponentBase { public: - MenuBase(const std::vector* entries, - int* selected, - Ref option) + MenuBase(ConstStringListRef entries, int* selected, Ref option) : entries_(entries), selected_(selected), option_(option) {} Element Render() { Elements elements; bool is_menu_focused = Focused(); - boxes_.resize(entries_->size()); - for (size_t i = 0; i < entries_->size(); ++i) { + boxes_.resize(entries_.size()); + for (size_t i = 0; i < entries_.size(); ++i) { bool is_focused = (focused_entry() == int(i)) && is_menu_focused; bool is_selected = (*selected_ == int(i)); @@ -43,9 +41,9 @@ class MenuBase : public ComponentBase { auto focus_management = !is_selected ? nothing : is_menu_focused ? focus : select; - auto icon = is_selected ? L"> " : L" "; - elements.push_back(text(icon + entries_->at(i)) | style | - focus_management | reflect(boxes_[i])); + auto icon = is_selected ? "> " : " "; + elements.push_back(text(icon + entries_[i]) | style | focus_management | + reflect(boxes_[i])); } return vbox(std::move(elements)); } @@ -64,12 +62,12 @@ class MenuBase : public ComponentBase { (*selected_)--; if (event == Event::ArrowDown || event == Event::Character('j')) (*selected_)++; - if (event == Event::Tab && entries_->size()) - *selected_ = (*selected_ + 1) % entries_->size(); - if (event == Event::TabReverse && entries_->size()) - *selected_ = (*selected_ + entries_->size() - 1) % entries_->size(); + if (event == Event::Tab && entries_.size()) + *selected_ = (*selected_ + 1) % entries_.size(); + if (event == Event::TabReverse && entries_.size()) + *selected_ = (*selected_ + entries_.size() - 1) % entries_.size(); - *selected_ = std::max(0, std::min(int(entries_->size()) - 1, *selected_)); + *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_)); if (*selected_ != old_selected) { focused_entry() = *selected_; @@ -106,12 +104,11 @@ class MenuBase : public ComponentBase { return false; } - bool Focusable() const final { return entries_->size(); } - + bool Focusable() const final { return entries_.size(); } int& focused_entry() { return option_->focused_entry(); } protected: - const std::vector* const entries_; + ConstStringListRef entries_; int* selected_ = 0; Ref option_; @@ -129,10 +126,10 @@ class MenuBase : public ComponentBase { /// /// ```cpp /// auto screen = ScreenInteractive::TerminalOutput(); -/// std::vector entries = { -/// L"entry 1", -/// L"entry 2", -/// L"entry 3", +/// std::vector entries = { +/// "entry 1", +/// "entry 2", +/// "entry 3", /// }; /// int selected = 0; /// auto menu = Menu(&entries, &selected); @@ -146,7 +143,7 @@ class MenuBase : public ComponentBase { /// entry 2 /// entry 3 /// ``` -Component Menu(const std::vector* entries, +Component Menu(ConstStringListRef entries, int* selected, Ref option) { return Make(entries, selected, std::move(option)); diff --git a/src/ftxui/component/radiobox.cpp b/src/ftxui/component/radiobox.cpp index 5666ba38..24a713d0 100644 --- a/src/ftxui/component/radiobox.cpp +++ b/src/ftxui/component/radiobox.cpp @@ -2,7 +2,7 @@ #include // for max, min #include // for function #include // for shared_ptr, allocator_traits<>::value_type -#include // for wstring +#include // for string #include // for move #include // for vector @@ -25,26 +25,26 @@ namespace { /// @ingroup component class RadioboxBase : public ComponentBase { public: - RadioboxBase(const std::vector* entries, + RadioboxBase(ConstStringListRef entries, int* selected, Ref option) : entries_(entries), selected_(selected), option_(std::move(option)) { #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) // Microsoft terminal do not use fonts able to render properly the default // radiobox glyph. - if (option_->style_checked == L"◉ ") - option_->style_checked = L"(*)"; - if (option_->style_unchecked == L"○ ") - option_->style_unchecked = L"( )"; + if (option_->style_checked == "◉ ") + option_->style_checked = "(*)"; + if (option_->style_unchecked == "○ ") + option_->style_unchecked = "( )"; #endif } private: Element Render() override { - std::vector elements; + Elements elements; bool is_focused = Focused(); - boxes_.resize(entries_->size()); - for (size_t i = 0; i < entries_->size(); ++i) { + boxes_.resize(entries_.size()); + for (size_t i = 0; i < entries_.size(); ++i) { auto style = (focused_entry() == int(i) && is_focused) ? option_->style_focused : option_->style_unfocused; @@ -52,10 +52,10 @@ class RadioboxBase : public ComponentBase { : is_focused ? focus : select; - const std::wstring& symbol = *selected_ == int(i) - ? option_->style_checked - : option_->style_unchecked; - elements.push_back(hbox(text(symbol), text(entries_->at(i)) | style) | + const std::string& symbol = *selected_ == int(i) + ? option_->style_checked + : option_->style_unchecked; + elements.push_back(hbox(text(symbol), text(entries_[i]) | style) | focus_management | reflect(boxes_[i])); } return vbox(std::move(elements)); @@ -75,12 +75,12 @@ class RadioboxBase : public ComponentBase { new_focused--; if (event == Event::ArrowDown || event == Event::Character('j')) new_focused++; - if (event == Event::Tab && entries_->size()) - new_focused = (new_focused + 1) % entries_->size(); - if (event == Event::TabReverse && entries_->size()) - new_focused = (new_focused + entries_->size() - 1) % entries_->size(); + if (event == Event::Tab && entries_.size()) + new_focused = (new_focused + 1) % entries_.size(); + if (event == Event::TabReverse && entries_.size()) + new_focused = (new_focused + entries_.size() - 1) % entries_.size(); - new_focused = std::max(0, std::min(int(entries_->size()) - 1, new_focused)); + new_focused = std::max(0, std::min(int(entries_.size()) - 1, new_focused)); if (focused_entry() != new_focused) { focused_entry() = new_focused; @@ -119,11 +119,10 @@ class RadioboxBase : public ComponentBase { return false; } - bool Focusable() const final { return entries_->size(); } - + bool Focusable() const final { return entries_.size(); } int& focused_entry() { return option_->focused_entry(); } - const std::vector* const entries_; + ConstStringListRef entries_; int* const selected_; int cursor_position = 0; @@ -144,10 +143,10 @@ class RadioboxBase : public ComponentBase { /// /// ```cpp /// auto screen = ScreenInteractive::TerminalOutput(); -/// std::vector entries = { -/// L"entry 1", -/// L"entry 2", -/// L"entry 3", +/// std::vector entries = { +/// "entry 1", +/// "entry 2", +/// "entry 3", /// }; /// int selected = 0; /// auto menu = Radiobox(&entries, &selected); @@ -161,7 +160,7 @@ class RadioboxBase : public ComponentBase { /// ○ entry 2 /// ○ entry 3 /// ``` -Component Radiobox(const std::vector* entries, +Component Radiobox(ConstStringListRef entries, int* selected, Ref option) { return Make(entries, selected, std::move(option)); diff --git a/src/ftxui/component/renderer.cpp b/src/ftxui/component/renderer.cpp index 5c568f8f..f1d0c18c 100644 --- a/src/ftxui/component/renderer.cpp +++ b/src/ftxui/component/renderer.cpp @@ -21,7 +21,7 @@ namespace ftxui { /// ```cpp /// auto screen = ScreenInteractive::TerminalOutput(); /// auto renderer = Renderer([] { -/// return text(L"My interface"); +/// return text("My interface"); /// }); /// screen.Loop(renderer); /// ``` @@ -46,7 +46,7 @@ Component Renderer(std::function render) { /// /// ```cpp /// auto screen = ScreenInteractive::TerminalOutput(); -/// std::wstring label = "Click to quit"; +/// std::string label = "Click to quit"; /// auto button = Button(&label, screen.ExitLoopClosure()); /// auto renderer = Renderer(button, [&] { /// return hbox({ diff --git a/src/ftxui/component/resizable_split.cpp b/src/ftxui/component/resizable_split.cpp index 3ee7d148..863d7d25 100644 --- a/src/ftxui/component/resizable_split.cpp +++ b/src/ftxui/component/resizable_split.cpp @@ -250,8 +250,8 @@ class ResizableSplitBottomBase : public ComponentBase { /// ```cpp /// auto screen = ScreenInteractive::Fullscreen(); /// int left_size = 10; -/// auto left = Renderer([] { return text(L"Left") | center;}); -/// auto right = Renderer([] { return text(L"right") | center;}); +/// auto left = Renderer([] { return text("Left") | center;}); +/// auto right = Renderer([] { return text("right") | center;}); /// auto split = ResizableSplitLeft(left, right, &left_size); /// screen.Loop(split); /// ``` @@ -280,8 +280,8 @@ Component ResizableSplitLeft(Component main, Component back, int* main_size) { /// ```cpp /// auto screen = ScreenInteractive::Fullscreen(); /// int right_size = 10; -/// auto left = Renderer([] { return text(L"Left") | center;}); -/// auto right = Renderer([] { return text(L"right") | center;}); +/// auto left = Renderer([] { return text("Left") | center;}); +/// auto right = Renderer([] { return text("right") | center;}); /// auto split = ResizableSplitRight(right, left, &right_size); /// screen.Loop(split); /// ``` @@ -310,8 +310,8 @@ Component ResizableSplitRight(Component main, Component back, int* main_size) { /// ```cpp /// auto screen = ScreenInteractive::Fullscreen(); /// int top_size = 1; -/// auto top = Renderer([] { return text(L"Top") | center;}); -/// auto bottom = Renderer([] { return text(L"Bottom") | center;}); +/// auto top = Renderer([] { return text("Top") | center;}); +/// auto bottom = Renderer([] { return text("Bottom") | center;}); /// auto split = ResizableSplitTop(top, bottom, &top_size); /// screen.Loop(split); /// ``` @@ -340,8 +340,8 @@ Component ResizableSplitTop(Component main, Component back, int* main_size) { /// ```cpp /// auto screen = ScreenInteractive::Fullscreen(); /// int bottom_size = 1; -/// auto top = Renderer([] { return text(L"Top") | center;}); -/// auto bottom = Renderer([] { return text(L"Bottom") | center;}); +/// auto top = Renderer([] { return text("Top") | center;}); +/// auto bottom = Renderer([] { return text("Bottom") | center;}); /// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size); /// screen.Loop(split); /// ``` diff --git a/src/ftxui/component/screen_interactive_test.cpp b/src/ftxui/component/screen_interactive_test.cpp index 77fbafee..808c5afd 100644 --- a/src/ftxui/component/screen_interactive_test.cpp +++ b/src/ftxui/component/screen_interactive_test.cpp @@ -1,11 +1,12 @@ -#include // for Message -#include // for TestPartResult -#include +#include // for Message +#include // for SuiteApiResolver, TestFactoryImpl, TestPartResult +#include // for raise, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM -#include "ftxui/component/component.hpp" +#include "ftxui/component/component.hpp" // for Renderer #include "ftxui/component/screen_interactive.hpp" -#include "ftxui/dom/elements.hpp" -#include "gtest/gtest_pred_impl.h" // for AssertionResult, Test, EXPECT_EQ +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for Element +#include "gtest/gtest_pred_impl.h" // for Test, TEST, EXPECT_EQ using namespace ftxui; diff --git a/src/ftxui/component/slider.cpp b/src/ftxui/component/slider.cpp index 2a4f3348..5b59bf86 100644 --- a/src/ftxui/component/slider.cpp +++ b/src/ftxui/component/slider.cpp @@ -17,7 +17,7 @@ namespace ftxui { template class SliderBase : public ComponentBase { public: - SliderBase(StringRef label, T* value, T min, T max, T increment) + SliderBase(ConstStringRef label, T* value, T min, T max, T increment) : label_(label), value_(value), min_(min), @@ -31,9 +31,9 @@ class SliderBase : public ComponentBase { return hbox({ text(*label_) | dim | vcenter, hbox({ - text(L"["), + text("["), gauge(percent) | underlined | xflex | reflect(gauge_box_), - text(L"]"), + text("]"), }) | xflex, }) | gauge_color | xflex | reflect(box_); @@ -87,7 +87,7 @@ class SliderBase : public ComponentBase { bool Focusable() const final { return true; } private: - StringRef label_; + ConstStringRef label_; T* value_; T min_; T max_; @@ -110,7 +110,7 @@ class SliderBase : public ComponentBase { /// ```cpp /// auto screen = ScreenInteractive::TerminalOutput(); /// int value = 50; -/// auto slider = Slider(L"Value:", &value, 0, 100, 1); +/// auto slider = Slider("Value:", &value, 0, 100, 1); /// screen.Loop(slider); /// ``` /// @@ -120,23 +120,23 @@ class SliderBase : public ComponentBase { /// Value:[██████████████████████████ ] /// ``` template -Component Slider(StringRef label, T* value, T min, T max, T increment) { +Component Slider(ConstStringRef label, T* value, T min, T max, T increment) { return Make>(std::move(label), value, min, max, increment); } -template Component Slider(StringRef label, +template Component Slider(ConstStringRef label, int* value, int min, int max, int increment); -template Component Slider(StringRef label, +template Component Slider(ConstStringRef label, float* value, float min, float max, float increment); -template Component Slider(StringRef label, +template Component Slider(ConstStringRef label, long* value, long min, long max, diff --git a/src/ftxui/component/terminal_input_parser_test.cpp b/src/ftxui/component/terminal_input_parser_test.cpp index 61e4bc33..6b9340c1 100644 --- a/src/ftxui/component/terminal_input_parser_test.cpp +++ b/src/ftxui/component/terminal_input_parser_test.cpp @@ -29,7 +29,7 @@ TEST(Event, Character) { for (char c : basic_char) { EXPECT_TRUE(event_receiver->Receive(&received)); EXPECT_TRUE(received.is_character()); - EXPECT_EQ(c, received.character()); + EXPECT_EQ(c, received.character()[0]); } EXPECT_FALSE(event_receiver->Receive(&received)); } diff --git a/src/ftxui/component/toggle.cpp b/src/ftxui/component/toggle.cpp index 1368c8e0..eae1bf7c 100644 --- a/src/ftxui/component/toggle.cpp +++ b/src/ftxui/component/toggle.cpp @@ -2,19 +2,18 @@ #include // for max, min #include // for function #include // for shared_ptr, allocator_traits<>::value_type -#include // for wstring #include // for move #include // for vector -#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse -#include "ftxui/component/component.hpp" // for Make, Component, Toggle -#include "ftxui/component/component_base.hpp" // for ComponentBase +#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse +#include "ftxui/component/component.hpp" // for Make, Toggle +#include "ftxui/component/component_base.hpp" // for Component, ComponentBase #include "ftxui/component/component_options.hpp" // for ToggleOption #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed #include "ftxui/dom/elements.hpp" // for operator|, Element, Elements, hbox, reflect, separator, text, focus, nothing, select #include "ftxui/screen/box.hpp" // for Box -#include "ftxui/util/ref.hpp" // for Ref +#include "ftxui/util/ref.hpp" // for ConstStringListRef, Ref namespace ftxui { @@ -24,7 +23,7 @@ namespace { /// @ingroup component class ToggleBase : public ComponentBase { public: - ToggleBase(const std::vector* entries, + ToggleBase(ConstStringListRef entries, int* selected, Ref option) : entries_(entries), selected_(selected), option_(std::move(option)) {} @@ -33,8 +32,8 @@ class ToggleBase : public ComponentBase { Element Render() override { Elements children; bool is_toggle_focused = Focused(); - boxes_.resize(entries_->size()); - for (size_t i = 0; i < entries_->size(); ++i) { + boxes_.resize(entries_.size()); + for (size_t i = 0; i < entries_.size(); ++i) { // Separator. if (i != 0) children.push_back(separator()); @@ -49,7 +48,7 @@ class ToggleBase : public ComponentBase { auto focus_management = !is_selected ? nothing : is_toggle_focused ? focus : select; - children.push_back(text(entries_->at(i)) | style | focus_management | + children.push_back(text(entries_[i]) | style | focus_management | reflect(boxes_[i])); } return hbox(std::move(children)); @@ -64,12 +63,12 @@ class ToggleBase : public ComponentBase { (*selected_)--; if (event == Event::ArrowRight || event == Event::Character('l')) (*selected_)++; - if (event == Event::Tab && entries_->size()) - *selected_ = (*selected_ + 1) % entries_->size(); - if (event == Event::TabReverse && entries_->size()) - *selected_ = (*selected_ + entries_->size() - 1) % entries_->size(); + if (event == Event::Tab && entries_.size()) + *selected_ = (*selected_ + 1) % entries_.size(); + if (event == Event::TabReverse && entries_.size()) + *selected_ = (*selected_ + entries_.size() - 1) % entries_.size(); - *selected_ = std::max(0, std::min(int(entries_->size()) - 1, *selected_)); + *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_)); if (old_selected != *selected_) { focused_entry() = *selected_; @@ -107,11 +106,10 @@ class ToggleBase : public ComponentBase { return false; } - bool Focusable() const final { return entries_->size(); } - + bool Focusable() const final { return entries_.size(); } int& focused_entry() { return option_->focused_entry(); } - const std::vector* const entries_; + ConstStringListRef entries_; int* selected_ = 0; std::vector boxes_; @@ -125,7 +123,7 @@ class ToggleBase : public ComponentBase { /// @param selected Reference the selected entry. /// @param option Additional optional parameters. /// @ingroup component -Component Toggle(const std::vector* entries, +Component Toggle(ConstStringListRef entries, int* selected, Ref option) { return Make(entries, selected, std::move(option)); diff --git a/src/ftxui/dom/benchmark_test.cpp b/src/ftxui/dom/benchmark_test.cpp index 5808e66d..20536a92 100644 --- a/src/ftxui/dom/benchmark_test.cpp +++ b/src/ftxui/dom/benchmark_test.cpp @@ -10,7 +10,7 @@ using namespace ftxui; static void BencharkBasic(benchmark::State& state) { while (state.KeepRunning()) { auto document = vbox({ - text(L"Test"), + text("Test"), separator(), hbox({ gauge(0.9), @@ -20,7 +20,7 @@ static void BencharkBasic(benchmark::State& state) { gauge(0.1), separator(), }), - text(L"Test"), + text("Test"), }) | border; auto root = gauge(1.0); diff --git a/src/ftxui/dom/border.cpp b/src/ftxui/dom/border.cpp index dcbe6953..13b6d47c 100644 --- a/src/ftxui/dom/border.cpp +++ b/src/ftxui/dom/border.cpp @@ -1,6 +1,7 @@ #include // for max #include // for begin, end -#include // for make_shared, __shared_ptr_access +#include // for allocator, make_shared, __shared_ptr_access +#include // for basic_string, string #include // for move #include // for vector, __alloc_traits<>::value_type @@ -12,10 +13,11 @@ namespace ftxui { -static wchar_t simple_border_charset[] = L"╭╮╰╯─│┬┴┤├"; +static std::string simple_border_charset[] = {"╭", "╮", "╰", "╯", "─", + "│", "┬", "┴", "┤", "├"}; // For reference, here is the charset for normal border: -// L"┌┐└┘─│┬┴┤├"; +// {"┌", "┐", "└", "┘", "─", "│", "┬", "┴", "┤", "├"}; // TODO(arthursonzogni): Consider adding options to choose the kind of borders // to use. @@ -29,7 +31,7 @@ class Border : public Node { : Node(std::move(children)), charset_pixel(10, pixel) {} std::vector charset_pixel; - std::vector charset; + std::vector charset; void ComputeRequirement() override { Node::ComputeRequirement(); @@ -120,10 +122,10 @@ class Border : public Node { /// /// ```cpp /// // Use 'border' as a function... -/// Element document = border(text(L"The element")); +/// Element document = border(text("The element")); /// /// // ...Or as a 'pipe'. -/// Element document = text(L"The element") | border; +/// Element document = text("The element") | border; /// ``` /// /// ### Output @@ -146,8 +148,8 @@ Element border(Element child) { /// ### Example /// /// ```cpp -/// Element document = window(text(L"Title"), -/// text(L"content") +/// Element document = window(text("Title"), +/// text("content") /// ); /// ``` /// diff --git a/src/ftxui/dom/color.cpp b/src/ftxui/dom/color.cpp index af1fbdd5..67f32c46 100644 --- a/src/ftxui/dom/color.cpp +++ b/src/ftxui/dom/color.cpp @@ -52,7 +52,7 @@ class FgColor : public NodeDecorator { /// ### Example /// /// ```cpp -/// Element document = color(Color::Green, text(L"Success")), +/// Element document = color(Color::Green, text("Success")), /// ``` Element color(Color color, Element child) { return std::make_shared(std::move(child), color); @@ -67,7 +67,7 @@ Element color(Color color, Element child) { /// ### Example /// /// ```cpp -/// Element document = bgcolor(Color::Green, text(L"Success")), +/// Element document = bgcolor(Color::Green, text("Success")), /// ``` Element bgcolor(Color color, Element child) { return std::make_shared(std::move(child), color); @@ -81,7 +81,7 @@ Element bgcolor(Color color, Element child) { /// ### Example /// /// ```cpp -/// Element document = text(L"red") | color(Color::Red); +/// Element document = text("red") | color(Color::Red); /// ``` Decorator color(Color c) { return [c](Element child) { return color(c, std::move(child)); }; @@ -95,7 +95,7 @@ Decorator color(Color c) { /// ### Example /// /// ```cpp -/// Element document = text(L"red") | bgcolor(Color::Red); +/// Element document = text("red") | bgcolor(Color::Red); /// ``` Decorator bgcolor(Color color) { return [color](Element child) { return bgcolor(color, std::move(child)); }; diff --git a/src/ftxui/dom/flex.cpp b/src/ftxui/dom/flex.cpp index 54e05f5c..23d66c23 100644 --- a/src/ftxui/dom/flex.cpp +++ b/src/ftxui/dom/flex.cpp @@ -103,9 +103,9 @@ Element filler() { /// /// ~~~cpp /// hbox({ -/// text(L"left") | border , -/// text(L"middle") | border | flex, -/// text(L"right") | border, +/// text("left") | border , +/// text("middle") | border | flex, +/// text("right") | border, /// }); /// ~~~ /// diff --git a/src/ftxui/dom/gauge.cpp b/src/ftxui/dom/gauge.cpp index b494f6b0..d6e75211 100644 --- a/src/ftxui/dom/gauge.cpp +++ b/src/ftxui/dom/gauge.cpp @@ -1,4 +1,5 @@ -#include // for make_shared +#include // for allocator, make_shared +#include // for string #include "ftxui/dom/elements.hpp" // for Element, gauge #include "ftxui/dom/node.hpp" // for Node @@ -8,12 +9,13 @@ namespace ftxui { +static std::string charset[] = #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) -// Microsoft's terminals often use fonts not handling the 8 unicode characters -// for representing the whole gauge. Fallback with less. -static wchar_t charset[] = L" ▌▌▌███"; + // Microsoft's terminals often use fonts not handling the 8 unicode + // characters for representing the whole gauge. Fallback with less. + {" ", " ", " ", " ", "▌", "▌", "▌", "█", "█", "█"}; #else -static wchar_t charset[] = L" ▏▎▍▌▋▊▉█"; + {" ", " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"}; #endif class Gauge : public Node { diff --git a/src/ftxui/dom/graph.cpp b/src/ftxui/dom/graph.cpp index 64a463c2..9bd5222f 100644 --- a/src/ftxui/dom/graph.cpp +++ b/src/ftxui/dom/graph.cpp @@ -1,5 +1,6 @@ #include // for function -#include // for make_shared +#include // for allocator, make_shared +#include // for string #include // for vector #include "ftxui/dom/elements.hpp" // for GraphFunction, Element, graph @@ -10,12 +11,13 @@ namespace ftxui { -// Microsoft's terminals often use fonts not handling the 8 unicode characters -// for representing the whole gauge. Fallback with less. +static std::string charset[] = #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) -const wchar_t charset[] = L" █ █████"; + // Microsoft's terminals often use fonts not handling the 8 unicode + // characters for representing the whole graph. Fallback with less. + {" ", " ", "█", " ", "█", "█", "█", "█", "█"}; #else -const wchar_t charset[] = L" ▗▐▖▄▟▌▙█"; + {" ", "▗", "▐", "▖", "▄", "▟", "▌", "▙", "█"}; #endif class Graph : public Node { @@ -43,8 +45,7 @@ class Graph : public Node { int yy = 2 * y; int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6; int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2; - wchar_t pix = charset[i_1 + i_2]; - screen.at(x, y) = pix; + screen.at(x, y) = charset[i_1 + i_2]; } } } diff --git a/src/ftxui/dom/hbox.cpp b/src/ftxui/dom/hbox.cpp index 08e82bf4..092e38f3 100644 --- a/src/ftxui/dom/hbox.cpp +++ b/src/ftxui/dom/hbox.cpp @@ -136,8 +136,8 @@ class HBox : public Node { /// /// ```cpp /// hbox({ -/// text(L"Left"), -/// text(L"Right"), +/// text("Left"), +/// text("Right"), /// }); /// ``` Element hbox(Elements children) { diff --git a/src/ftxui/dom/hbox_test.cpp b/src/ftxui/dom/hbox_test.cpp index fc5ca6c0..f9ea9da4 100644 --- a/src/ftxui/dom/hbox_test.cpp +++ b/src/ftxui/dom/hbox_test.cpp @@ -1,13 +1,14 @@ -#include // for Message -#include // for TestPartResult +#include // for Message +#include // for SuiteApiResolver, TestFactoryImpl, TestPartResult #include // for allocator, basic_string, string #include // for vector -#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for operator|, Element, flex_grow, flex_shrink, hbox #include "ftxui/dom/node.hpp" // for Render #include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/screen.hpp" // for Screen -#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ +#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST using namespace ftxui; using namespace ftxui; diff --git a/src/ftxui/dom/paragraph.cpp b/src/ftxui/dom/paragraph.cpp index a90c18d7..3e9299b2 100644 --- a/src/ftxui/dom/paragraph.cpp +++ b/src/ftxui/dom/paragraph.cpp @@ -1,7 +1,8 @@ -#include -#include +#include // for basic_istream, wstringstream +#include // for allocator, char_traits, getline, operator+, wstring, basic_string -#include "ftxui/dom/elements.hpp" +#include "ftxui/dom/deprecated.hpp" // for text, paragraph +#include "ftxui/dom/elements.hpp" // for Elements namespace ftxui { @@ -14,9 +15,22 @@ Elements paragraph(std::wstring the_text) { Elements output; std::wstringstream ss(the_text); std::wstring word; - while (std::getline(ss, word, L' ')) { + while (std::getline(ss, word, L' ')) output.push_back(text(word + L' ')); - } + return output; +} + +/// @brief Return a vector of ftxui::text for every word of the string. This is +/// useful combined with ftxui::hflow. +/// @param the_text The string to be splitted. +/// @ingroup dom +/// @see hflow. +Elements paragraph(std::string the_text) { + Elements output; + std::stringstream ss(the_text); + std::string word; + while (std::getline(ss, word, ' ')) + output.push_back(text(word + ' ')); return output; } diff --git a/src/ftxui/dom/separator.cpp b/src/ftxui/dom/separator.cpp index 88d066ef..fa3d894c 100644 --- a/src/ftxui/dom/separator.cpp +++ b/src/ftxui/dom/separator.cpp @@ -1,5 +1,5 @@ #include // for make_shared -#include // for wstring +#include // for string #include "ftxui/dom/elements.hpp" // for Element, separator #include "ftxui/dom/node.hpp" // for Node @@ -22,11 +22,11 @@ class Separator : public Node { bool is_column = (box_.x_max == box_.x_min); bool is_line = (box_.y_min == box_.y_max); - wchar_t c = U'+'; + std::string c = "+"; if (is_line && !is_column) - c = U'─'; + c = "─"; else - c = U'│'; + c = "│"; for (int y = box_.y_min; y <= box_.y_max; ++y) { for (int x = box_.x_min; x <= box_.x_max; ++x) { diff --git a/src/ftxui/dom/spinner.cpp b/src/ftxui/dom/spinner.cpp index 8d7a602e..eb80354a 100644 --- a/src/ftxui/dom/spinner.cpp +++ b/src/ftxui/dom/spinner.cpp @@ -1,6 +1,6 @@ #include // for size_t #include // for allocator, allocator_traits<>::value_type -#include // for basic_string, wstring +#include // for string #include // for move #include // for vector, __alloc_traits<>::value_type @@ -8,242 +8,242 @@ namespace ftxui { -static const std::vector>> elements = { +static const std::vector>> elements = { { - {L"Replaced by the gauge"}, + {"Replaced by the gauge"}, }, { - {L". "}, - {L".. "}, - {L"..."}, + {". "}, + {".. "}, + {"..."}, }, { - {L"|"}, - {L"/"}, - {L"-"}, - {L"\\"}, + {"|"}, + {"/"}, + {"-"}, + {"\\"}, }, { - {L"+"}, - {L"x"}, + {"+"}, + {"x"}, }, { - {L"| "}, - {L"|| "}, - {L"|||"}, + {"| "}, + {"|| "}, + {"|||"}, }, { - {L"←"}, - {L"↖"}, - {L"↑"}, - {L"↗"}, - {L"→"}, - {L"↘"}, - {L"↓"}, - {L"↙"}, + {"←"}, + {"↖"}, + {"↑"}, + {"↗"}, + {"→"}, + {"↘"}, + {"↓"}, + {"↙"}, }, { - {L"▁"}, - {L"▂"}, - {L"▃"}, - {L"▄"}, - {L"▅"}, - {L"▆"}, - {L"▇"}, - {L"█"}, - {L"▇"}, - {L"▆"}, - {L"▅"}, - {L"▄"}, - {L"▃"}, - {L"▁"}, + {"▁"}, + {"▂"}, + {"▃"}, + {"▄"}, + {"▅"}, + {"▆"}, + {"▇"}, + {"█"}, + {"▇"}, + {"▆"}, + {"▅"}, + {"▄"}, + {"▃"}, + {"▁"}, }, { - {L"▉"}, - {L"▊"}, - {L"▋"}, - {L"▌"}, - {L"▍"}, - {L"▎"}, - {L"▏"}, - {L"▎"}, - {L"▍"}, - {L"▌"}, - {L"▋"}, - {L"▊"}, + {"▉"}, + {"▊"}, + {"▋"}, + {"▌"}, + {"▍"}, + {"▎"}, + {"▏"}, + {"▎"}, + {"▍"}, + {"▌"}, + {"▋"}, + {"▊"}, }, { - {L"▖"}, - {L"▘"}, - {L"▝"}, - {L"▗"}, + {"▖"}, + {"▘"}, + {"▝"}, + {"▗"}, }, { - {L"◢"}, - {L"◣"}, - {L"◤"}, - {L"◥"}, + {"◢"}, + {"◣"}, + {"◤"}, + {"◥"}, }, { - {L"◰"}, - {L"◳"}, - {L"◲"}, - {L"◱"}, + {"◰"}, + {"◳"}, + {"◲"}, + {"◱"}, }, { - {L"◴"}, - {L"◷"}, - {L"◶"}, - {L"◵"}, + {"◴"}, + {"◷"}, + {"◶"}, + {"◵"}, }, { - {L"◐"}, - {L"◓"}, - {L"◑"}, - {L"◒"}, + {"◐"}, + {"◓"}, + {"◑"}, + {"◒"}, }, { - {L"◡"}, - {L"⊙"}, - {L"◠"}, + {"◡"}, + {"⊙"}, + {"◠"}, }, { - {L"⠁"}, - {L"⠂"}, - {L"⠄"}, - {L"⡀"}, - {L"⢀"}, - {L"⠠"}, - {L"⠐"}, - {L"⠈"}, + {"⠁"}, + {"⠂"}, + {"⠄"}, + {"⡀"}, + {"⢀"}, + {"⠠"}, + {"⠐"}, + {"⠈"}, }, { - {L"⠋"}, - {L"⠙"}, - {L"⠹"}, - {L"⠸"}, - {L"⠼"}, - {L"⠴"}, - {L"⠦"}, - {L"⠧"}, - {L"⠇"}, - {L"⠏"}, + {"⠋"}, + {"⠙"}, + {"⠹"}, + {"⠸"}, + {"⠼"}, + {"⠴"}, + {"⠦"}, + {"⠧"}, + {"⠇"}, + {"⠏"}, }, { - {L"(*----------)"}, {L"(-*---------)"}, {L"(--*--------)"}, - {L"(---*-------)"}, {L"(----*------)"}, {L"(-----*-----)"}, - {L"(------*----)"}, {L"(-------*---)"}, {L"(--------*--)"}, - {L"(---------*-)"}, {L"(----------*)"}, {L"(---------*-)"}, - {L"(--------*--)"}, {L"(-------*---)"}, {L"(------*----)"}, - {L"(-----*-----)"}, {L"(----*------)"}, {L"(---*-------)"}, - {L"(--*--------)"}, {L"(-*---------)"}, + {"(*----------)"}, {"(-*---------)"}, {"(--*--------)"}, + {"(---*-------)"}, {"(----*------)"}, {"(-----*-----)"}, + {"(------*----)"}, {"(-------*---)"}, {"(--------*--)"}, + {"(---------*-)"}, {"(----------*)"}, {"(---------*-)"}, + {"(--------*--)"}, {"(-------*---)"}, {"(------*----)"}, + {"(-----*-----)"}, {"(----*------)"}, {"(---*-------)"}, + {"(--*--------)"}, {"(-*---------)"}, }, { - {L"[ ]"}, - {L"[= ]"}, - {L"[== ]"}, - {L"[=== ]"}, - {L"[==== ]"}, - {L"[===== ]"}, - {L"[======]"}, - {L"[===== ]"}, - {L"[==== ]"}, - {L"[=== ]"}, - {L"[== ]"}, - {L"[= ]"}, + {"[ ]"}, + {"[= ]"}, + {"[== ]"}, + {"[=== ]"}, + {"[==== ]"}, + {"[===== ]"}, + {"[======]"}, + {"[===== ]"}, + {"[==== ]"}, + {"[=== ]"}, + {"[== ]"}, + {"[= ]"}, }, { - {L"[ ]"}, - {L"[= ]"}, - {L"[== ]"}, - {L"[=== ]"}, - {L"[==== ]"}, - {L"[===== ]"}, - {L"[======]"}, - {L"[ =====]"}, - {L"[ ====]"}, - {L"[ ===]"}, - {L"[ ==]"}, - {L"[ =]"}, + {"[ ]"}, + {"[= ]"}, + {"[== ]"}, + {"[=== ]"}, + {"[==== ]"}, + {"[===== ]"}, + {"[======]"}, + {"[ =====]"}, + {"[ ====]"}, + {"[ ===]"}, + {"[ ==]"}, + {"[ =]"}, }, { - {L"[== ]"}, - {L"[== ]"}, - {L"[== ]"}, - {L"[== ]"}, - {L"[== ]"}, - {L" [== ]"}, - {L"[ == ]"}, - {L"[ == ]"}, - {L"[ ==]"}, - {L"[ ==]"}, - {L"[ ==]"}, - {L"[ ==]"}, - {L"[ ==]"}, - {L"[ ==] "}, - {L"[ == ]"}, - {L"[ == ]"}, + {"[== ]"}, + {"[== ]"}, + {"[== ]"}, + {"[== ]"}, + {"[== ]"}, + {" [== ]"}, + {"[ == ]"}, + {"[ == ]"}, + {"[ ==]"}, + {"[ ==]"}, + {"[ ==]"}, + {"[ ==]"}, + {"[ ==]"}, + {"[ ==] "}, + {"[ == ]"}, + {"[ == ]"}, }, {{ - L" ─╮", - L" │", - L" ", + " ─╮", + " │", + " ", }, { - L" ╮", - L" │", - L" ╯", + " ╮", + " │", + " ╯", }, { - L" ", - L" │", - L" ─╯", + " ", + " │", + " ─╯", }, { - L" ", - L" ", - L"╰─╯", + " ", + " ", + "╰─╯", }, { - L" ", - L"│ ", - L"╰─ ", + " ", + "│ ", + "╰─ ", }, { - L"╭ ", - L"│ ", - L"╰ ", + "╭ ", + "│ ", + "╰ ", }, { - L"╭─ ", - L"│ ", - L" ", + "╭─ ", + "│ ", + " ", }, { - L"╭─╮", - L" ", - L" ", + "╭─╮", + " ", + " ", }}, {{ - L" /\\O ", - L" /\\/ ", - L" /\\ ", - L" / \\ ", - L"LOL LOL", + " /\\O ", + " /\\/ ", + " /\\ ", + " / \\ ", + "LOL LOL ", }, { - L" _O ", - L" //|_ ", - L" | ", - L" /| ", - L" LLOL ", + " _O ", + " //|_ ", + " | ", + " /| ", + " LLOL ", }, { - L" O ", - L" /_ ", - L" |\\ ", - L" / | ", - L" LOLLOL ", + " O ", + " /_ ", + " |\\ ", + " / | ", + " LOLLOL ", }}}; /// @brief Useful to represent the effect of time and/or events. This display an diff --git a/src/ftxui/dom/text.cpp b/src/ftxui/dom/text.cpp index 2803fd70..59d62b43 100644 --- a/src/ftxui/dom/text.cpp +++ b/src/ftxui/dom/text.cpp @@ -1,13 +1,14 @@ -#include // for max -#include // for make_shared -#include // for wstring +#include // for make_shared +#include // for string +#include // for vector +#include "ftxui/dom/deprecated.hpp" // for text, vtext #include "ftxui/dom/elements.hpp" // for Element, text, vtext #include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/screen/box.hpp" // for Box -#include "ftxui/screen/screen.hpp" // for Screen -#include "ftxui/screen/string.hpp" // for wchar_width, wstring_width +#include "ftxui/screen/screen.hpp" // for Pixel, Screen +#include "ftxui/screen/string.hpp" // for string_width, Utf8ToGlyphs, to_string namespace ftxui { @@ -15,10 +16,10 @@ using ftxui::Screen; class Text : public Node { public: - Text(std::wstring text) : text_(text) {} + Text(std::string text) : text_(text) {} void ComputeRequirement() override { - requirement_.min_x = wstring_width(text_); + requirement_.min_x = string_width(text_); requirement_.min_y = 1; } @@ -27,33 +28,26 @@ class Text : public Node { int y = box_.y_min; if (y > box_.y_max) return; - for (wchar_t c : text_) { - const int width = wchar_width(c); - if (width >= 1) { - if (x > box_.x_max) - return; - screen.PixelAt(x, y).character = c; - } else { - screen.PixelAt(x - 1, y).character += c; - } - x += std::max(width, 0); + for (const auto& cell : Utf8ToGlyphs(text_)) { + if (x > box_.x_max) + return; + screen.PixelAt(x, y).character = cell; + ++x; } } private: - std::wstring text_; + std::string text_; }; class VText : public Node { public: - VText(std::wstring text) : text_(text) { - for (auto& c : text_) - width_ = std::max(width_, wchar_width(c)); - } + VText(std::string text) + : text_(text), width_{std::min(string_width(text_), 1)} {} void ComputeRequirement() override { requirement_.min_x = width_; - requirement_.min_y = text_.size(); + requirement_.min_y = string_width(text_); } void Render(Screen& screen) override { @@ -61,20 +55,39 @@ class VText : public Node { int y = box_.y_min; if (x + width_ - 1 > box_.x_max) return; - for (wchar_t c : text_) { + for (const auto& it : Utf8ToGlyphs(text_)) { if (y > box_.y_max) return; - screen.at(x, y) = c; + screen.PixelAt(x, y).character = it; y += 1; } } private: - std::wstring text_; + std::string text_; int width_ = 1; }; -/// @brief Display a pieve of unicode text. +/// @brief Display a piece of UTF8 encoded unicode text. +/// @ingroup dom +/// @see ftxui::to_wstring +/// +/// ### Example +/// +/// ```cpp +/// Element document = text("Hello world!"); +/// ``` +/// +/// ### Output +/// +/// ```bash +/// Hello world! +/// ``` +Element text(std::string text) { + return std::make_shared(text); +} + +/// @brief Display a piece of UTF16 encoded unicode text. /// @ingroup dom /// @see ftxui::to_wstring /// @@ -90,10 +103,40 @@ class VText : public Node { /// Hello world! /// ``` Element text(std::wstring text) { - return std::make_shared(text); + return std::make_shared(to_string(text)); } -/// @brief Display a pieve of unicode text vertically. +/// @brief Display a piece of unicode text vertically. +/// @ingroup dom +/// @see ftxui::to_wstring +/// +/// ### Example +/// +/// ```cpp +/// Element document = vtext("Hello world!"); +/// ``` +/// +/// ### Output +/// +/// ```bash +/// H +/// e +/// l +/// l +/// o +/// +/// w +/// o +/// r +/// l +/// d +/// ! +/// ``` +Element vtext(std::string text) { + return std::make_shared(text); +} + +/// @brief Display a piece of UTF16 encoded unicode text vertically. /// @ingroup dom /// @see ftxui::to_wstring /// @@ -120,7 +163,7 @@ Element text(std::wstring text) { /// ! /// ``` Element vtext(std::wstring text) { - return std::make_shared(text); + return std::make_shared(to_string(text)); } } // namespace ftxui diff --git a/src/ftxui/dom/text_test.cpp b/src/ftxui/dom/text_test.cpp index ad1b4301..8102aac4 100644 --- a/src/ftxui/dom/text_test.cpp +++ b/src/ftxui/dom/text_test.cpp @@ -2,12 +2,13 @@ #include // for SuiteApiResolver, TestFactoryImpl, TestPartResult #include // for allocator, wstring -#include "ftxui/dom/elements.hpp" // for text, operator|, border, Element -#include "ftxui/dom/node.hpp" // for Render -#include "ftxui/screen/box.hpp" // for ftxui -#include "ftxui/screen/screen.hpp" // for Screen -#include "ftxui/screen/string.hpp" // for to_string -#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST +#include "ftxui/dom/deprecated.hpp" // for text +#include "ftxui/dom/elements.hpp" // for operator|, border, Element +#include "ftxui/dom/node.hpp" // for Render +#include "ftxui/screen/box.hpp" // for ftxui +#include "ftxui/screen/screen.hpp" // for Screen +#include "ftxui/screen/string.hpp" // for to_string +#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST using namespace ftxui; diff --git a/src/ftxui/dom/util.cpp b/src/ftxui/dom/util.cpp index 23a2c611..689f0793 100644 --- a/src/ftxui/dom/util.cpp +++ b/src/ftxui/dom/util.cpp @@ -56,10 +56,10 @@ Elements operator|(Elements elements, Decorator decorator) { /// /// Both of these are equivalent: /// ```cpp -/// bold(text(L"Hello")); +/// bold(text("Hello")); /// ``` /// ```cpp -/// text(L"Hello") | bold; +/// text("Hello") | bold; /// ``` Element operator|(Element element, Decorator decorator) { return decorator(std::move(element)); diff --git a/src/ftxui/dom/vbox.cpp b/src/ftxui/dom/vbox.cpp index 4021cdc8..1ed02d8a 100644 --- a/src/ftxui/dom/vbox.cpp +++ b/src/ftxui/dom/vbox.cpp @@ -137,8 +137,8 @@ class VBox : public Node { /// /// ```cpp /// vbox({ -/// text(L"Up"), -/// text(L"Down"), +/// text("Up"), +/// text("Down"), /// }); /// ``` Element vbox(Elements children) { diff --git a/src/ftxui/dom/vbox_test.cpp b/src/ftxui/dom/vbox_test.cpp index 19aa8b9c..c9e707c7 100644 --- a/src/ftxui/dom/vbox_test.cpp +++ b/src/ftxui/dom/vbox_test.cpp @@ -1,14 +1,15 @@ -#include // for Message -#include // for TestPartResult +#include // for Message +#include // for SuiteApiResolver, TestFactoryImpl, TestPartResult #include // for remove #include // for allocator, basic_string, string #include // for vector -#include "ftxui/dom/elements.hpp" // for vtext, operator|, Element, flex_grow +#include "ftxui/dom/deprecated.hpp" // for vtext +#include "ftxui/dom/elements.hpp" // for operator|, Element, flex_grow, flex_shrink, vbox #include "ftxui/dom/node.hpp" // for Render #include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/screen.hpp" // for Screen -#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ +#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST using namespace ftxui; using namespace ftxui; diff --git a/src/ftxui/screen/color.cpp b/src/ftxui/screen/color.cpp index 5dbb65de..ed92e132 100644 --- a/src/ftxui/screen/color.cpp +++ b/src/ftxui/screen/color.cpp @@ -1,19 +1,16 @@ #include "ftxui/screen/color.hpp" -#include "ftxui/screen/color_info.hpp" -#include "ftxui/screen/string.hpp" -#include "ftxui/screen/terminal.hpp" + +#include "ftxui/screen/color_info.hpp" // for GetColorInfo, ColorInfo +#include "ftxui/screen/terminal.hpp" // for Terminal, Terminal::Color, Terminal::Palette256, Terminal::TrueColor namespace ftxui { namespace { -const wchar_t* palette16code[16][2] = { - {L"30", L"40"}, {L"31", L"41"}, {L"32", L"42"}, {L"33", L"43"}, - {L"34", L"44"}, - - {L"35", L"45"}, {L"36", L"46"}, {L"37", L"47"}, - - {L"90", L"100"}, {L"91", L"101"}, {L"92", L"102"}, {L"93", L"103"}, - {L"94", L"104"}, {L"95", L"105"}, {L"96", L"106"}, {L"97", L"107"}, +const char* palette16code[16][2] = { + {"30", "40"}, {"31", "41"}, {"32", "42"}, {"33", "43"}, + {"34", "44"}, {"35", "45"}, {"36", "46"}, {"37", "47"}, + {"90", "100"}, {"91", "101"}, {"92", "102"}, {"93", "103"}, + {"94", "104"}, {"95", "105"}, {"96", "106"}, {"97", "107"}, }; } @@ -26,24 +23,24 @@ bool Color::operator!=(const Color& rhs) const { return !operator==(rhs); } -std::wstring Color::Print(bool is_background_color) const { +std::string Color::Print(bool is_background_color) const { switch (type_) { case ColorType::Palette1: - return is_background_color ? L"49" : L"39"; + return is_background_color ? "49" : "39"; case ColorType::Palette16: return palette16code[index_][is_background_color]; case ColorType::Palette256: - return (is_background_color ? L"48;5;" : L"38;5;") + to_wstring(index_); + return (is_background_color ? "48;5;" : "38;5;") + std::to_string(index_); case ColorType::TrueColor: - return (is_background_color ? L"48;2;" : L"38;2;") // - + to_wstring(red_) + L";" // - + to_wstring(green_) + L";" // - + to_wstring(blue_); // + return (is_background_color ? "48;2;" : "38;2;") // + + std::to_string(red_) + ";" // + + std::to_string(green_) + ";" // + + std::to_string(blue_); // } - return L""; + return ""; } /// @brief Build a transparent color. diff --git a/src/ftxui/screen/screen.cpp b/src/ftxui/screen/screen.cpp index 3a9ef50a..db682ba7 100644 --- a/src/ftxui/screen/screen.cpp +++ b/src/ftxui/screen/screen.cpp @@ -1,10 +1,9 @@ -#include // for max -#include // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream -#include // for allocator -#include // IWYU pragma: keep +#include // for operator<<, stringstream, basic_ostream, flush, cout, ostream +#include // for allocator +#include // IWYU pragma: keep #include "ftxui/screen/screen.hpp" -#include "ftxui/screen/string.hpp" // for to_string, wchar_width +#include "ftxui/screen/string.hpp" // for string_width #include "ftxui/screen/terminal.hpp" // for Dimensions, Size #if defined(_WIN32) @@ -18,24 +17,24 @@ namespace ftxui { namespace { -static const wchar_t* BOLD_SET = L"\x1B[1m"; -static const wchar_t* BOLD_RESET = L"\x1B[22m"; // Can't use 21 here. +static const char BOLD_SET[] = "\x1B[1m"; +static const char BOLD_RESET[] = "\x1B[22m"; // Can't use 21 here. -static const wchar_t* DIM_SET = L"\x1B[2m"; -static const wchar_t* DIM_RESET = L"\x1B[22m"; +static const char DIM_SET[] = "\x1B[2m"; +static const char DIM_RESET[] = "\x1B[22m"; -static const wchar_t* UNDERLINED_SET = L"\x1B[4m"; -static const wchar_t* UNDERLINED_RESET = L"\x1B[24m"; +static const char UNDERLINED_SET[] = "\x1B[4m"; +static const char UNDERLINED_RESET[] = "\x1B[24m"; -static const wchar_t* BLINK_SET = L"\x1B[5m"; -static const wchar_t* BLINK_RESET = L"\x1B[25m"; +static const char BLINK_SET[] = "\x1B[5m"; +static const char BLINK_RESET[] = "\x1B[25m"; -static const wchar_t* INVERTED_SET = L"\x1B[7m"; -static const wchar_t* INVERTED_RESET = L"\x1B[27m"; +static const char INVERTED_SET[] = "\x1B[7m"; +static const char INVERTED_RESET[] = "\x1B[27m"; -static const char* MOVE_LEFT = "\r"; -static const char* MOVE_UP = "\x1B[1A"; -static const char* CLEAR_LINE = "\x1B[2K"; +static const char MOVE_LEFT[] = "\r"; +static const char MOVE_UP[] = "\x1B[1A"; +static const char CLEAR_LINE[] = "\x1B[2K"; Pixel dev_null_pixel; @@ -62,7 +61,9 @@ void WindowsEmulateVT100Terminal() { } #endif -void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) { +void UpdatePixelStyle(std::stringstream& ss, + Pixel& previous, + const Pixel& next) { if (next.bold != previous.bold) ss << (next.bold ? BOLD_SET : BOLD_RESET); @@ -80,8 +81,8 @@ void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) { if (next.foreground_color != previous.foreground_color || next.background_color != previous.background_color) { - ss << L"\x1B[" + next.foreground_color.Print(false) + L"m"; - ss << L"\x1B[" + next.background_color.Print(true) + L"m"; + ss << "\x1B[" + next.foreground_color.Print(false) + "m"; + ss << "\x1B[" + next.background_color.Print(true) + "m"; } previous = next; @@ -135,7 +136,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; + std::stringstream ss; Pixel previous_pixel; Pixel final_pixel; @@ -143,24 +144,21 @@ std::string Screen::ToString() { for (int y = 0; y < dimy_; ++y) { if (y != 0) { UpdatePixelStyle(ss, previous_pixel, final_pixel); - ss << L"\r\n"; + ss << "\r\n"; } - for (int x = 0; x < dimx_;) { - auto& pixel = pixels_[y][x]; - UpdatePixelStyle(ss, previous_pixel, pixel); - - int x_inc = 0; - for (auto& c : pixel.character) { - ss << c; - x_inc += wchar_width(c); + bool previous_fullwidth = false; + for (const auto& pixel : pixels_[y]) { + if (!previous_fullwidth) { + UpdatePixelStyle(ss, previous_pixel, pixel); + ss << pixel.character; } - x += std::max(x_inc, 1); + previous_fullwidth = (string_width(pixel.character) == 2); } } UpdatePixelStyle(ss, previous_pixel, final_pixel); - return to_string(ss.str()); + return ss.str(); } void Screen::Print() { @@ -170,8 +168,8 @@ void Screen::Print() { /// @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. -wchar_t& Screen::at(int x, int y) { - return PixelAt(x, y).character[0]; +std::string& Screen::at(int x, int y) { + return PixelAt(x, y).character; } /// @brief Access a Pixel at a given position. @@ -229,21 +227,21 @@ void Screen::ApplyShader() { // Merge box characters togethers. for (int y = 1; y < dimy_; ++y) { for (int x = 1; x < dimx_; ++x) { - wchar_t& left = at(x - 1, y); - wchar_t& top = at(x, y - 1); - wchar_t& cur = at(x, y); + std::string& left = at(x - 1, y); + std::string& top = at(x, y - 1); + std::string& cur = at(x, y); // Left vs current - if (cur == U'│' && left == U'─') cur = U'┤'; - if (cur == U'─' && left == U'│') left = U'├'; - if (cur == U'├' && left == U'─') cur = U'┼'; - if (cur == U'─' && left == U'┤') left = U'┼'; + if (cur == "│" && left == "─") cur = "┤"; + if (cur == "─" && left == "│") left = "├"; + if (cur == "├" && left == "─") cur = "┼"; + if (cur == "─" && left == "┤") left = "┼"; // Top vs current - if (cur == U'─' && top == U'│') cur = U'┴'; - if (cur == U'│' && top == U'─') top = U'┬'; - if (cur == U'┬' && top == U'│') cur = U'┼'; - if (cur == U'│' && top == U'┴') top = U'┼'; + if (cur == "─" && top == "│") cur = "┴"; + if (cur == "│" && top == "─") top = "┬"; + if (cur == "┬" && top == "│") cur = "┼"; + if (cur == "│" && top == "┴") top = "┼"; } } } diff --git a/src/ftxui/screen/string.cpp b/src/ftxui/screen/string.cpp index 693ca021..9d72b11a 100644 --- a/src/ftxui/screen/string.cpp +++ b/src/ftxui/screen/string.cpp @@ -1,9 +1,291 @@ +// Most of this code is borrowed from: +// Markus Kuhn -- 2007-05-26 (Unicode 5.0) +// Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c +// Thanks you! +// +// Modified by Arthur Sonzogni for FTXUI. + #include "ftxui/screen/string.hpp" -#include // for codecvt_utf8_utf16 -#include // for wstring_convert +#include // for size_t +#include // for uint32_t, uint8_t +#include // for codecvt_utf8_utf16 +#include // for wstring_convert +#include // for string, basic_string, wstring, allocator + +namespace { + +struct Interval { + uint32_t first; + uint32_t last; +}; + +// Sorted list of non-overlapping intervals of non-spacing characters +// generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" +static const Interval g_combining_characters[] = { + {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489}, + {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, + {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603}, + {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670}, + {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, + {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, + {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902}, + {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, + {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, + {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, + {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C}, + {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, + {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, + {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, + {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, + {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, + {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, + {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, + {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC}, + {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, + {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, + {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, + {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, + {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, + {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, + {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, + {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, + {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F}, + {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, + {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, + {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, + {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922}, + {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B}, + {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, + {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, + {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF}, + {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063}, + {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F}, + {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, + {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, + {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, + {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, + {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169}, + {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, + {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F}, + {0xE0100, 0xE01EF}, +}; + +static const Interval g_full_width_characters[] = { + {0x1100, 0x115f}, {0x2329, 0x2329}, {0x232a, 0x232a}, {0x2e80, 0x303e}, + {0x3040, 0xa4cf}, {0xac00, 0xd7a3}, {0xf900, 0xfaff}, {0xfe10, 0xfe19}, + {0xfe30, 0xfe6f}, {0xff00, 0xff60}, {0xffe0, 0xffe6}, {0x20000, 0x2fffd}, + {0x30000, 0x3fffd}, +}; + +// Find a codepoint inside a sorted list of Interval. +int Bisearch(uint32_t ucs, const Interval* table, int max) { + if (ucs < table[0].first || ucs > table[max].last) + return 0; + + int min = 0; + while (max >= min) { + int mid = (min + max) / 2; + if (ucs > table[mid].last) + min = mid + 1; + else if (ucs < table[mid].first) + max = mid - 1; + else + return 1; + } + + return 0; +} + +bool IsCombining(uint32_t ucs) { + return Bisearch(ucs, g_combining_characters, + sizeof(g_combining_characters) / sizeof(Interval) - 1); +} + +bool IsFullWidth(uint32_t ucs) { + if (ucs < 0x0300) // Quick path: + return false; + + return Bisearch(ucs, g_full_width_characters, + sizeof(g_full_width_characters) / sizeof(Interval) - 1); +} + +bool IsControl(uint32_t ucs) { + if (ucs == 0) + return true; + if (ucs < 32) + return true; + if (ucs >= 0x7f && ucs < 0xa0) + return true; + return false; +} + +int codepoint_width(uint32_t ucs) { + if (IsControl(ucs)) + return -1; + + if (IsCombining(ucs)) + return 0; + + if (IsFullWidth(ucs)) + return 2; + + return 1; +} + +// From UTF8 encoded string |input|, eat in between 1 and 4 byte representing +// one codepoint. Put the codepoint into |ucs|. Start at |start| and update +// |end| to represent the beginning of the next byte to eat for consecutive +// executions. +bool EatCodePoint(const std::string& input, + size_t start, + size_t* end, + uint32_t* ucs) { + if (start >= input.size()) { + *end = start + 1; + return false; + } + uint8_t byte_1 = input[start]; + + // 1 byte string. + if ((byte_1 & 0b1000'0000) == 0b0000'0000) { + *ucs = byte_1 & 0b0111'1111; + *end = start + 1; + return true; + } + + // 2 byte string. + if ((byte_1 & 0b1110'0000) == 0b1100'0000 && start + 1 < input.size()) { + uint8_t byte_2 = input[start + 1]; + *ucs = 0; + *ucs += byte_1 & 0b0001'1111; + *ucs <<= 6; + *ucs += byte_2 & 0b0011'1111; + *end = start + 2; + return true; + } + + // 3 byte string. + if ((byte_1 & 0b1111'0000) == 0b1110'0000 && start + 2 < input.size()) { + uint8_t byte_2 = input[start + 1]; + uint8_t byte_3 = input[start + 2]; + *ucs = 0; + *ucs += byte_1 & 0b0000'1111; + *ucs <<= 6; + *ucs += byte_2 & 0b0011'1111; + *ucs <<= 6; + *ucs += byte_3 & 0b0011'1111; + *end = start + 3; + return true; + } + + // 4 byte string. + if ((byte_1 & 0b1111'1000) == 0b1111'0000 && start + 3 < input.size()) { + uint8_t byte_2 = input[start + 1]; + uint8_t byte_3 = input[start + 2]; + uint8_t byte_4 = input[start + 3]; + *ucs = 0; + *ucs += byte_1 & 0b0000'0111; + *ucs <<= 6; + *ucs += byte_2 & 0b0011'1111; + *ucs <<= 6; + *ucs += byte_3 & 0b0011'1111; + *ucs <<= 6; + *ucs += byte_4 & 0b0011'1111; + *end = start + 4; + return true; + } + + *end = start + 1; + return false; +} + +} // namespace namespace ftxui { +int wchar_width(wchar_t ucs) { + return codepoint_width(uint32_t(ucs)); +} + +int wstring_width(const std::wstring& text) { + int width = 0; + + for (const wchar_t& it : text) { + int w = wchar_width(it); + if (w < 0) + return -1; + width += w; + } + return width; +} + +int string_width(const std::string& input) { + int width = 0; + size_t start = 0; + while (start < input.size()) { + uint32_t codepoint = 0; + if (!EatCodePoint(input, start, &start, &codepoint)) + continue; + + if (IsControl(codepoint)) + continue; + + if (IsCombining(codepoint)) + continue; + + if (IsFullWidth(codepoint)) { + width += 2; + continue; + } + + width += 1; + } + return width; +} + +std::vector Utf8ToGlyphs(const std::string& input) { + std::vector out; + std::string current; + out.reserve(input.size()); + size_t start = 0; + size_t end = 0; + while (start < input.size()) { + uint32_t codepoint; + if (!EatCodePoint(input, start, &end, &codepoint)) { + start = end; + continue; + } + + std::string append = input.substr(start, end - start); + start = end; + + // Ignore control characters. + if (IsControl(codepoint)) + continue; + + // Combining characters are put with the previous glyph they are modifying. + if (IsCombining(codepoint)) { + if (out.size() != 0) + out.back() += append; + continue; + } + + // Fullwidth characters take two cells. The second is made of the empty + // string to reserve the space the first is taking. + if (IsFullWidth(codepoint)) { + out.push_back(append); + out.push_back(""); + continue; + } + + // Normal characters: + out.push_back(append); + } + return out; +} + #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4996) // codecvt_utf8_utf16 is deprecated diff --git a/src/ftxui/screen/string_test.cpp b/src/ftxui/screen/string_test.cpp new file mode 100644 index 00000000..502a2abd --- /dev/null +++ b/src/ftxui/screen/string_test.cpp @@ -0,0 +1,47 @@ +#include // for Message +#include // for TestPartResult, SuiteApiResolver, TestFactoryImpl +#include // for allocator, string + +#include "ftxui/screen/string.hpp" +#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, TEST + +using namespace ftxui; + +TEST(StringTest, StringWidth) { + // Basic: + EXPECT_EQ(0, string_width("")); + EXPECT_EQ(1, string_width("a")); + EXPECT_EQ(2, string_width("ab")); + // Fullwidth glyphs: + EXPECT_EQ(2, string_width("测")); + EXPECT_EQ(4, string_width("测试")); + // Combining characters: + EXPECT_EQ(1, string_width("ā")); + EXPECT_EQ(1, string_width("a⃒")); + EXPECT_EQ(1, string_width("a̗")); + // Control characters: + EXPECT_EQ(0, string_width("\1")); + EXPECT_EQ(2, string_width("a\1a")); +} + +TEST(StringTest, Utf8ToGlyphs) { + using T = std::vector; + // Basic: + EXPECT_EQ(Utf8ToGlyphs(""), T({})); + EXPECT_EQ(Utf8ToGlyphs("a"), T({"a"})); + EXPECT_EQ(Utf8ToGlyphs("ab"), T({"a", "b"})); + // Fullwidth glyphs: + EXPECT_EQ(Utf8ToGlyphs("测"), T({"测", ""})); + EXPECT_EQ(Utf8ToGlyphs("测试"), T({"测", "", "试", ""})); + // Combining characters: + EXPECT_EQ(Utf8ToGlyphs("ā"), T({"ā"})); + EXPECT_EQ(Utf8ToGlyphs("a⃒"), T({"a⃒"})); + EXPECT_EQ(Utf8ToGlyphs("a̗"), T({"a̗"})); + // Control characters: + EXPECT_EQ(Utf8ToGlyphs("\1"), T({})); + EXPECT_EQ(Utf8ToGlyphs("a\1a"), T({"a", "a"})); +} + +// 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. diff --git a/src/ftxui/screen/wcwidth.cpp b/src/ftxui/screen/wcwidth.cpp index a23ce3bf..6c0a379e 100644 --- a/src/ftxui/screen/wcwidth.cpp +++ b/src/ftxui/screen/wcwidth.cpp @@ -1,317 +1,4 @@ -/* - * This is an implementation of wcwidth() and wcswidth() (defined in - * IEEE Std 1002.1-2001) for Unicode. - * - * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html - * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html - * - * In fixed-width output devices, Latin characters all occupy a single - * "cell" position of equal width, whereas ideographic CJK characters - * occupy two such cells. Interoperability between terminal-line - * applications and (teletype-style) character terminals using the - * UTF-8 encoding requires agreement on which character should advance - * the cursor by how many cell positions. No established formal - * standards exist at present on which Unicode character shall occupy - * how many cell positions on character terminals. These routines are - * a first attempt of defining such behavior based on simple rules - * applied to data provided by the Unicode Consortium. - * - * For some graphical characters, the Unicode standard explicitly - * defines a character-cell width via the definition of the East Asian - * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. - * In all these cases, there is no ambiguity about which width a - * terminal shall use. For characters in the East Asian Ambiguous (A) - * class, the width choice depends purely on a preference of backward - * compatibility with either historic CJK or Western practice. - * Choosing single-width for these characters is easy to justify as - * the appropriate long-term solution, as the CJK practice of - * displaying these characters as double-width comes from historic - * implementation simplicity (8-bit encoded characters were displayed - * single-width and 16-bit ones double-width, even for Greek, - * Cyrillic, etc.) and not any typographic considerations. - * - * Much less clear is the choice of width for the Not East Asian - * (Neutral) class. Existing practice does not dictate a width for any - * of these characters. It would nevertheless make sense - * typographically to allocate two character cells to characters such - * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be - * represented adequately with a single-width glyph. The following - * routines at present merely assign a single-cell width to all - * neutral characters, in the interest of simplicity. This is not - * entirely satisfactory and should be reconsidered before - * establishing a formal standard in this area. At the moment, the - * decision which Not East Asian (Neutral) characters should be - * represented by double-width glyphs cannot yet be answered by - * applying a simple rule from the Unicode database content. Setting - * up a proper standard for the behavior of UTF-8 character terminals - * will require a careful analysis not only of each Unicode character, - * but also of each presentation form, something the author of these - * routines has avoided to do so far. - * - * http://www.unicode.org/unicode/reports/tr11/ - * - * Markus Kuhn -- 2007-05-26 (Unicode 5.0) - * - * Permission to use, copy, modify, and distribute this software - * for any purpose and without fee is hereby granted. The author - * disclaims all warranties with regard to this software. - * - * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ -#include - -#include "ftxui/screen/string.hpp" - -namespace ftxui { - -namespace { -struct interval { - char32_t first; - char32_t last; -}; - -/* auxiliary function for binary search in interval table */ -int bisearch(char32_t ucs, const struct interval* table, int max) { - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - - return 0; -} -} // namespace - -/* The following two functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - SOFT HYPHEN (U+00AD) has a column width of 1. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * Full-width (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that char32_t characters are encoded - * in ISO 10646. - */ - -int wchar_width(char32_t ucs) { - /* sorted list of non-overlapping intervals of non-spacing characters */ - /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ - static const struct interval combining[] = { - {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489}, - {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, - {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603}, - {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670}, - {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, - {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A}, - {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902}, - {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D}, - {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981}, - {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD}, - {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C}, - {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, - {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC}, - {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD}, - {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C}, - {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D}, - {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0}, - {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48}, - {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC}, - {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD}, - {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D}, - {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, - {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, - {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, - {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, - {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E}, - {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97}, - {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030}, - {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, - {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F}, - {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, - {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD}, - {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD}, - {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922}, - {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B}, - {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34}, - {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42}, - {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF}, - {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063}, - {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F}, - {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B}, - {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, - {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, - {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, - {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169}, - {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, - {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F}, - {0xE0100, 0xE01EF}}; - - /* test for 8-bit control characters */ - if (ucs == 0) - return 0; - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) - return -1; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1)) - return 0; - - /* if we arrive here, ucs is not a combining or C0/C1 control character */ - - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && - ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); -} - -/* - * The following functions are the same as mk_wcwidth() and - * mk_wcswidth(), except that spacing characters in the East Asian - * Ambiguous (A) category as defined in Unicode Technical Report #11 - * have a column width of 2. This variant might be useful for users of - * CJK legacy encodings who want to migrate to UCS without changing - * the traditional terminal character-width behaviour. It is not - * otherwise recommended for general use. - */ -int wchar_width_cjk(char32_t ucs) { - /* sorted list of non-overlapping intervals of East Asian Ambiguous - * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ - static const struct interval ambiguous[] = { - {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8}, - {0x00AA, 0x00AA}, {0x00AE, 0x00AE}, {0x00B0, 0x00B4}, - {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6}, - {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1}, - {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED}, - {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA}, - {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101}, - {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B}, - {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133}, - {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144}, - {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153}, - {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE}, - {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4}, - {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA}, - {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261}, - {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB}, - {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB}, - {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0391, 0x03A1}, - {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, {0x03C3, 0x03C9}, - {0x0401, 0x0401}, {0x0410, 0x044F}, {0x0451, 0x0451}, - {0x2010, 0x2010}, {0x2013, 0x2016}, {0x2018, 0x2019}, - {0x201C, 0x201D}, {0x2020, 0x2022}, {0x2024, 0x2027}, - {0x2030, 0x2030}, {0x2032, 0x2033}, {0x2035, 0x2035}, - {0x203B, 0x203B}, {0x203E, 0x203E}, {0x2074, 0x2074}, - {0x207F, 0x207F}, {0x2081, 0x2084}, {0x20AC, 0x20AC}, - {0x2103, 0x2103}, {0x2105, 0x2105}, {0x2109, 0x2109}, - {0x2113, 0x2113}, {0x2116, 0x2116}, {0x2121, 0x2122}, - {0x2126, 0x2126}, {0x212B, 0x212B}, {0x2153, 0x2154}, - {0x215B, 0x215E}, {0x2160, 0x216B}, {0x2170, 0x2179}, - {0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, - {0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200}, - {0x2202, 0x2203}, {0x2207, 0x2208}, {0x220B, 0x220B}, - {0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215}, - {0x221A, 0x221A}, {0x221D, 0x2220}, {0x2223, 0x2223}, - {0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E}, - {0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248}, - {0x224C, 0x224C}, {0x2252, 0x2252}, {0x2260, 0x2261}, - {0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F}, - {0x2282, 0x2283}, {0x2286, 0x2287}, {0x2295, 0x2295}, - {0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, - {0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B}, - {0x2550, 0x2573}, {0x2580, 0x258F}, {0x2592, 0x2595}, - {0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, - {0x25B6, 0x25B7}, {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, - {0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, - {0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606}, - {0x2609, 0x2609}, {0x260E, 0x260F}, {0x2614, 0x2615}, - {0x261C, 0x261C}, {0x261E, 0x261E}, {0x2640, 0x2640}, - {0x2642, 0x2642}, {0x2660, 0x2661}, {0x2663, 0x2665}, - {0x2667, 0x266A}, {0x266C, 0x266D}, {0x266F, 0x266F}, - {0x273D, 0x273D}, {0x2776, 0x277F}, {0xE000, 0xF8FF}, - {0xFFFD, 0xFFFD}, {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}}; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1)) - return 2; - - return wchar_width(ucs); -} - -int wchar_width(wchar_t ucs) { - return wchar_width(char32_t(ucs)); -} - -int wchar_width_cjk(wchar_t ucs) { - return wchar_width_cjk(char32_t(ucs)); -} - -int wstring_width(const std::wstring& text) { - int width = 0; - - for (const wchar_t& it : text) { - int w = wchar_width(it); - if (w < 0) - return -1; - width += w; - } - return width; -} - -int wstring_width_cjk(const std::wstring& text) { - int width = 0; - - for (const wchar_t& it : text) { - int w = wchar_width_cjk(it); - if (w < 0) - return -1; - width += w; - } - return width; -} - -} // namespace ftxui - -// Copyright 2020 Arthur Sonzogni. All rights reserved. +// 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.