mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-18 17:18:08 +08:00
Prefer std::string over std::wstring. (#179)
In the past, FTXUI switched from std::string to std::wstring to support fullwidth characters. The reasons was that fullwidth characters can be stored inside a single wchar_t. Then FTXUI added support for combining characters. A single glygh doesn't even fit a wchar_t. Instead, a glyph can be arbitrary large. The usage of wstring doesn't really fit the new model and have several drawbacks: 1. It doesn't simplify the implementation of FTXUI, because of combining characters. 2. It reduces drawing performance by 2x. 3. It increase Screen's memory allocation by 2x. This patch converts FTXUI to use std::string internally. It now exposes std::string based API. The std::wstring API remains, but is now deprecated. Tests and examples haven't been update to show the breakage is limited. They will be updated in a second set of patches. Bug: https://github.com/ArthurSonzogni/FTXUI/issues/153 Co-authored-by: Tushar Maheshwari <tushar27192@gmail.com>
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
#include <algorithm> // for max
|
||||
#include <iostream> // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream
|
||||
#include <memory> // for allocator
|
||||
#include <sstream> // IWYU pragma: keep
|
||||
#include <iostream> // for operator<<, stringstream, basic_ostream, flush, cout, ostream
|
||||
#include <memory> // for allocator
|
||||
#include <sstream> // 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 = "┼";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user