mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-26 12:37:06 +08:00
Remove codecvt dependency. (#516)
This resolves: https://github.com/ArthurSonzogni/FTXUI/issues/514
This commit is contained in:
parent
55b9706cfd
commit
05f29ff3b3
@ -26,8 +26,8 @@ TEST(AnimationTest, StartAndEnd) {
|
|||||||
animation::easing::BounceInOut,
|
animation::easing::BounceInOut,
|
||||||
};
|
};
|
||||||
for (auto& it : functions) {
|
for (auto& it : functions) {
|
||||||
EXPECT_NEAR(0.f, it(0.f), 1.0e-4);
|
EXPECT_NEAR(0.F, it(0.F), 1.0e-4);
|
||||||
EXPECT_NEAR(1.f, it(1.f), 1.0e-4);
|
EXPECT_NEAR(1.F, it(1.F), 1.0e-4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE
|
||||||
Loop::Loop(ScreenInteractive* screen, Component component)
|
Loop::Loop(ScreenInteractive* screen, Component component)
|
||||||
: screen_(screen), component_(component) {
|
: screen_(screen), component_(std::move(component)) {
|
||||||
screen_->PreMain();
|
screen_->PreMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ CapturedMouse ScreenInteractive::CaptureMouse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenInteractive::Loop(Component component) { // NOLINT
|
void ScreenInteractive::Loop(Component component) { // NOLINT
|
||||||
class Loop loop(this, component);
|
class Loop loop(this, std::move(component));
|
||||||
loop.Run();
|
loop.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,12 +559,13 @@ void ScreenInteractive::RunOnceBlocking(Component component) {
|
|||||||
RunOnce(component);
|
RunOnce(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE
|
||||||
void ScreenInteractive::RunOnce(Component component) {
|
void ScreenInteractive::RunOnce(Component component) {
|
||||||
Task task;
|
Task task;
|
||||||
while (task_receiver_->ReceiveNonBlocking(&task)) {
|
while (task_receiver_->ReceiveNonBlocking(&task)) {
|
||||||
HandleTask(component, task);
|
HandleTask(component, task);
|
||||||
}
|
}
|
||||||
Draw(component);
|
Draw(std::move(component));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenInteractive::HandleTask(Component component, Task& task) {
|
void ScreenInteractive::HandleTask(Component component, Task& task) {
|
||||||
@ -620,8 +621,9 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
|
|||||||
|
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
void ScreenInteractive::Draw(Component component) {
|
void ScreenInteractive::Draw(Component component) {
|
||||||
if (frame_valid_)
|
if (frame_valid_) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
auto document = component->Render();
|
auto document = component->Render();
|
||||||
int dimx = 0;
|
int dimx = 0;
|
||||||
int dimy = 0;
|
int dimy = 0;
|
||||||
|
@ -158,7 +158,7 @@ class FocusCursor : public Focus {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void Render(Screen& screen) override {
|
void Render(Screen& screen) override {
|
||||||
Select::Render(screen);
|
Select::Render(screen); // NOLINT
|
||||||
screen.SetCursor(Screen::Cursor{
|
screen.SetCursor(Screen::Cursor{
|
||||||
box_.x_min,
|
box_.x_min,
|
||||||
box_.y_min,
|
box_.y_min,
|
||||||
|
@ -1,29 +1,16 @@
|
|||||||
// Most of this code is borrowed from:
|
// Content of this file was created thanks to:
|
||||||
// Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
// - https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/WordBreakProperty.txt
|
||||||
// Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
// - Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||||
|
// http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||||
// Thanks you!
|
// Thanks you!
|
||||||
//
|
|
||||||
// Modified by Arthur Sonzogni for FTXUI.
|
|
||||||
|
|
||||||
#include "ftxui/screen/string.hpp"
|
#include "ftxui/screen/string.hpp"
|
||||||
|
|
||||||
#include <array> // for array
|
#include <array> // for array
|
||||||
#include <codecvt> // for codecvt_utf8_utf16
|
|
||||||
#include <cstdint> // for uint32_t, uint8_t
|
#include <cstdint> // for uint32_t, uint8_t
|
||||||
#include <locale> // for wstring_convert
|
|
||||||
#include <string> // for string, basic_string, wstring
|
#include <string> // for string, basic_string, wstring
|
||||||
#include <tuple> // for std::ignore
|
#include <tuple> // for std::ignore
|
||||||
|
|
||||||
// `codecvt_utf8_utf16 is deprecated in C++17. However there are no replacement.
|
|
||||||
// Microsoft provides one, but that's not standardized. Hence the two code path.
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stringapiset.h>
|
|
||||||
#else
|
|
||||||
#include <codecvt> // for codecvt_utf8_utf16
|
|
||||||
#include <locale> // for wstring_convert
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Interval {
|
struct Interval {
|
||||||
@ -1587,56 +1574,56 @@ bool EatCodePoint(const std::string& input,
|
|||||||
*end = start + 1;
|
*end = start + 1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t byte_1 = input[start];
|
uint8_t C0 = input[start];
|
||||||
|
|
||||||
// 1 byte string.
|
// 1 byte string.
|
||||||
if ((byte_1 & 0b1000'0000) == 0b0000'0000) { // NOLINT
|
if ((C0 & 0b1000'0000) == 0b0000'0000) { // NOLINT
|
||||||
*ucs = byte_1 & 0b0111'1111; // NOLINT
|
*ucs = C0 & 0b0111'1111; // NOLINT
|
||||||
*end = start + 1;
|
*end = start + 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 byte string.
|
// 2 byte string.
|
||||||
if ((byte_1 & 0b1110'0000) == 0b1100'0000 && // NOLINT
|
if ((C0 & 0b1110'0000) == 0b1100'0000 && // NOLINT
|
||||||
start + 1 < input.size()) {
|
start + 1 < input.size()) {
|
||||||
uint8_t byte_2 = input[start + 1];
|
uint8_t C1 = input[start + 1];
|
||||||
*ucs = 0;
|
*ucs = 0;
|
||||||
*ucs += byte_1 & 0b0001'1111; // NOLINT
|
*ucs += C0 & 0b0001'1111; // NOLINT
|
||||||
*ucs <<= 6; // NOLINT
|
*ucs <<= 6; // NOLINT
|
||||||
*ucs += byte_2 & 0b0011'1111; // NOLINT
|
*ucs += C1 & 0b0011'1111; // NOLINT
|
||||||
*end = start + 2;
|
*end = start + 2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3 byte string.
|
// 3 byte string.
|
||||||
if ((byte_1 & 0b1111'0000) == 0b1110'0000 && // NOLINT
|
if ((C0 & 0b1111'0000) == 0b1110'0000 && // NOLINT
|
||||||
start + 2 < input.size()) {
|
start + 2 < input.size()) {
|
||||||
uint8_t byte_2 = input[start + 1];
|
uint8_t C1 = input[start + 1];
|
||||||
uint8_t byte_3 = input[start + 2];
|
uint8_t C2 = input[start + 2];
|
||||||
*ucs = 0;
|
*ucs = 0;
|
||||||
*ucs += byte_1 & 0b0000'1111; // NOLINT
|
*ucs += C0 & 0b0000'1111; // NOLINT
|
||||||
*ucs <<= 6; // NOLINT
|
*ucs <<= 6; // NOLINT
|
||||||
*ucs += byte_2 & 0b0011'1111; // NOLINT
|
*ucs += C1 & 0b0011'1111; // NOLINT
|
||||||
*ucs <<= 6; // NOLINT
|
*ucs <<= 6; // NOLINT
|
||||||
*ucs += byte_3 & 0b0011'1111; // NOLINT
|
*ucs += C2 & 0b0011'1111; // NOLINT
|
||||||
*end = start + 3;
|
*end = start + 3;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4 byte string.
|
// 4 byte string.
|
||||||
if ((byte_1 & 0b1111'1000) == 0b1111'0000 && // NOLINT
|
if ((C0 & 0b1111'1000) == 0b1111'0000 && // NOLINT
|
||||||
start + 3 < input.size()) {
|
start + 3 < input.size()) {
|
||||||
uint8_t byte_2 = input[start + 1];
|
uint8_t C1 = input[start + 1];
|
||||||
uint8_t byte_3 = input[start + 2];
|
uint8_t C2 = input[start + 2];
|
||||||
uint8_t byte_4 = input[start + 3];
|
uint8_t C3 = input[start + 3];
|
||||||
*ucs = 0;
|
*ucs = 0;
|
||||||
*ucs += byte_1 & 0b0000'0111; // NOLINT
|
*ucs += C0 & 0b0000'0111; // NOLINT
|
||||||
*ucs <<= 6; // NOLINT
|
*ucs <<= 6; // NOLINT
|
||||||
*ucs += byte_2 & 0b0011'1111; // NOLINT
|
*ucs += C1 & 0b0011'1111; // NOLINT
|
||||||
*ucs <<= 6; // NOLINT
|
*ucs <<= 6; // NOLINT
|
||||||
*ucs += byte_3 & 0b0011'1111; // NOLINT
|
*ucs += C2 & 0b0011'1111; // NOLINT
|
||||||
*ucs <<= 6; // NOLINT
|
*ucs <<= 6; // NOLINT
|
||||||
*ucs += byte_4 & 0b0011'1111; // NOLINT
|
*ucs += C3 & 0b0011'1111; // NOLINT
|
||||||
*end = start + 4;
|
*end = start + 4;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1645,6 +1632,49 @@ bool EatCodePoint(const std::string& input,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From UTF16 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::wstring& input,
|
||||||
|
size_t start,
|
||||||
|
size_t* end,
|
||||||
|
uint32_t* ucs) {
|
||||||
|
if (start >= input.size()) {
|
||||||
|
*end = start + 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// On linux wstring uses the UTF32 encoding:
|
||||||
|
if constexpr (sizeof(wchar_t) == 4) {
|
||||||
|
*ucs = input[start]; // NOLINT
|
||||||
|
*end = start + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On windows, wstring uses the UTF16 encoding:
|
||||||
|
int32_t C0 = input[start]; // NOLINT
|
||||||
|
|
||||||
|
// 1 word size:
|
||||||
|
if (C0 < 0xd800 || C0 >= 0xdc00) { // NOLINT
|
||||||
|
*ucs = C0;
|
||||||
|
*end = start + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 word size:
|
||||||
|
if (start + 1 >= input.size()) {
|
||||||
|
*end = start + 2;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t C1 = input[start + 1]; // NOLINT
|
||||||
|
*ucs = ((C0 & 0x3ff) << 10) + (C1 & 0x3ff) + 0x10000; // NOLINT
|
||||||
|
*end = start + 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace ftxui {
|
namespace ftxui {
|
||||||
@ -1865,32 +1895,107 @@ std::vector<WordBreakProperty> Utf8ToWordBreakProperty(
|
|||||||
|
|
||||||
/// Convert a UTF8 std::string into a std::wstring.
|
/// Convert a UTF8 std::string into a std::wstring.
|
||||||
std::string to_string(const std::wstring& s) {
|
std::string to_string(const std::wstring& s) {
|
||||||
#if defined(_WIN32)
|
std::string out;
|
||||||
if (s.empty())
|
|
||||||
return std::string();
|
size_t i = 0;
|
||||||
int size = WideCharToMultiByte(CP_UTF8, 0, &s[0], (int)s.size(), nullptr, 0,
|
uint32_t codepoint = 0;
|
||||||
nullptr, nullptr);
|
while (EatCodePoint(s, i, &i, &codepoint)) {
|
||||||
std::string out(size, 0);
|
// Code point <-> UTF-8 conversion
|
||||||
WideCharToMultiByte(CP_UTF8, 0, &s[0], (int)s.size(), &out[0], size, nullptr,
|
//
|
||||||
nullptr);
|
// ┏━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
|
||||||
|
// ┃Byte 1 ┃Byte 2 ┃Byte 3 ┃Byte 4 ┃
|
||||||
|
// ┡━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
|
||||||
|
// │0xxxxxxx│ │ │ │
|
||||||
|
// ├────────┼────────┼────────┼────────┤
|
||||||
|
// │110xxxxx│10xxxxxx│ │ │
|
||||||
|
// ├────────┼────────┼────────┼────────┤
|
||||||
|
// │1110xxxx│10xxxxxx│10xxxxxx│ │
|
||||||
|
// ├────────┼────────┼────────┼────────┤
|
||||||
|
// │11110xxx│10xxxxxx│10xxxxxx│10xxxxxx│
|
||||||
|
// └────────┴────────┴────────┴────────┘
|
||||||
|
|
||||||
|
// 1 byte UTF8
|
||||||
|
if (codepoint <= 0b000'0000'0111'1111) { // NOLINT
|
||||||
|
uint8_t p1 = codepoint;
|
||||||
|
out.push_back(p1); // NOLINT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2 bytes UTF8
|
||||||
|
if (codepoint <= 0b000'0111'1111'1111) { // NOLINT
|
||||||
|
uint8_t p2 = codepoint & 0b111111; // NOLINT
|
||||||
|
codepoint >>= 6; // NOLINT
|
||||||
|
uint8_t p1 = codepoint; // NOLINT
|
||||||
|
out.push_back(0b11000000 + p1); // NOLINT
|
||||||
|
out.push_back(0b10000000 + p2); // NOLINT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3 bytes UTF8
|
||||||
|
if (codepoint <= 0b1111'1111'1111'1111) { // NOLINT
|
||||||
|
uint8_t p3 = codepoint & 0b111111; // NOLINT
|
||||||
|
codepoint >>= 6; // NOLINT
|
||||||
|
uint8_t p2 = codepoint & 0b111111; // NOLINT
|
||||||
|
codepoint >>= 6; // NOLINT
|
||||||
|
uint8_t p1 = codepoint; // NOLINT
|
||||||
|
out.push_back(0b11100000 + p1); // NOLINT
|
||||||
|
out.push_back(0b10000000 + p2); // NOLINT
|
||||||
|
out.push_back(0b10000000 + p3); // NOLINT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4 bytes UTF8
|
||||||
|
if (codepoint <= 0b1'0000'1111'1111'1111'1111) { // NOLINT
|
||||||
|
uint8_t p4 = codepoint & 0b111111; // NOLINT
|
||||||
|
codepoint >>= 6; // NOLINT
|
||||||
|
uint8_t p3 = codepoint & 0b111111; // NOLINT
|
||||||
|
codepoint >>= 6; // NOLINT
|
||||||
|
uint8_t p2 = codepoint & 0b111111; // NOLINT
|
||||||
|
codepoint >>= 6; // NOLINT
|
||||||
|
uint8_t p1 = codepoint; // NOLINT
|
||||||
|
out.push_back(0b11110000 + p1); // NOLINT
|
||||||
|
out.push_back(0b10000000 + p2); // NOLINT
|
||||||
|
out.push_back(0b10000000 + p3); // NOLINT
|
||||||
|
out.push_back(0b10000000 + p4); // NOLINT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something else?
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
#else
|
|
||||||
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(s);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a std::wstring into a UTF8 std::string.
|
/// Convert a std::wstring into a UTF8 std::string.
|
||||||
std::wstring to_wstring(const std::string& s) {
|
std::wstring to_wstring(const std::string& s) {
|
||||||
#if defined(_WIN32)
|
std::wstring out;
|
||||||
if (s.empty())
|
|
||||||
return std::wstring();
|
size_t i = 0;
|
||||||
int size = MultiByteToWideChar(CP_UTF8, 0, &s[0], (int)s.size(), nullptr, 0);
|
uint32_t codepoint = 0;
|
||||||
std::wstring out(size, 0);
|
while (EatCodePoint(s, i, &i, &codepoint)) {
|
||||||
MultiByteToWideChar(CP_UTF8, 0, &s[0], (int)s.size(), &out[0], size);
|
// On linux wstring are UTF32 encoded:
|
||||||
|
if constexpr (sizeof(wchar_t) == 4) {
|
||||||
|
out.push_back(codepoint); // NOLINT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows, wstring are UTF16 encoded:
|
||||||
|
|
||||||
|
// Codepoint encoded using 1 word:
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
if (codepoint < 0xD800 || (codepoint > 0xDFFF && codepoint < 0x10000)) {
|
||||||
|
uint16_t p0 = codepoint; // NOLINT
|
||||||
|
out.push_back(p0); // NOLINT
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Codepoint encoded using 2 words:
|
||||||
|
codepoint -= 0x010000; // NOLINT
|
||||||
|
uint16_t p0 = (((codepoint << 12) >> 22) + 0xD800); // NOLINT
|
||||||
|
uint16_t p1 = (((codepoint << 22) >> 22) + 0xDC00); // NOLINT
|
||||||
|
out.push_back(p0); // NOLINT
|
||||||
|
out.push_back(p1); // NOLINT
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
#else
|
|
||||||
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(s);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -138,6 +138,28 @@ TEST(StringTest, Utf8ToWordBreakProperty) {
|
|||||||
EXPECT_EQ(Utf8ToWordBreakProperty("\n"), T({})); // FIXME
|
EXPECT_EQ(Utf8ToWordBreakProperty("\n"), T({})); // FIXME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StringTest, to_string) {
|
||||||
|
EXPECT_EQ(to_string(L"hello"), "hello");
|
||||||
|
EXPECT_EQ(to_string(L"€"), "€");
|
||||||
|
EXPECT_EQ(to_string(L"ÿ"), "ÿ");
|
||||||
|
EXPECT_EQ(to_string(L"߿"), "߿");
|
||||||
|
EXPECT_EQ(to_string(L"ɰɱ"), "ɰɱ");
|
||||||
|
EXPECT_EQ(to_string(L"«»"), "«»");
|
||||||
|
EXPECT_EQ(to_string(L"嵰嵲嵫"), "嵰嵲嵫");
|
||||||
|
EXPECT_EQ(to_string(L"🎅🎄"), "🎅🎄");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringTest, to_wstring) {
|
||||||
|
EXPECT_EQ(to_wstring(std::string("hello")), L"hello");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("€")), L"€");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("ÿ")), L"ÿ");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("߿")), L"߿");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("ɰɱ")), L"ɰɱ");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("«»")), L"«»");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("嵰嵲嵫")), L"嵰嵲嵫");
|
||||||
|
EXPECT_EQ(to_wstring(std::string("🎅🎄")), L"🎅🎄");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
// Use of this source code is governed by the MIT license that can be found in
|
// Use of this source code is governed by the MIT license that can be found in
|
||||||
|
Loading…
Reference in New Issue
Block a user