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.