Add clang-tidy. (#368)

This commit is contained in:
Arthur Sonzogni
2022-03-31 02:17:43 +02:00
committed by GitHub
parent 62fb6298be
commit aebde94352
80 changed files with 1958 additions and 1376 deletions

View File

@@ -17,7 +17,7 @@ Box Box::Intersection(Box a, Box b) {
/// @return whether (x,y) is contained inside the box.
/// @ingroup screen
bool Box::Contain(int x, int y) {
bool Box::Contain(int x, int y) const {
return x_min <= x && //
x_max >= x && //
y_min <= y && //

View File

@@ -1,20 +1,36 @@
#include "ftxui/screen/color.hpp"
#include <cassert>
#include <array> // for array
#include <string_view> // for literals
#include "ftxui/screen/color_info.hpp" // for GetColorInfo, ColorInfo
#include "ftxui/screen/terminal.hpp" // for Terminal, Terminal::Color, Terminal::Palette256, Terminal::TrueColor
#include "ftxui/screen/terminal.hpp" // for ColorSupport, Color, Palette256, TrueColor
namespace ftxui {
using namespace std::literals;
namespace {
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"},
const std::array<const char*, 33> palette16code = {
"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", //
};
}
} // namespace
bool Color::operator==(const Color& rhs) const {
return red_ == rhs.red_ && green_ == rhs.green_ && blue_ == rhs.blue_ &&
@@ -28,42 +44,43 @@ bool Color::operator!=(const Color& rhs) const {
std::string Color::Print(bool is_background_color) const {
switch (type_) {
case ColorType::Palette1:
return is_background_color ? "49" : "39";
return is_background_color ? "49"s : "39"s;
case ColorType::Palette16:
return palette16code[index_][is_background_color];
return palette16code[2 * red_ + is_background_color]; // NOLINT;
case ColorType::Palette256:
return (is_background_color ? "48;5;" : "38;5;") + std::to_string(index_);
return (is_background_color ? "48;5;"s : "38;5;"s) + std::to_string(red_);
case ColorType::TrueColor:
return (is_background_color ? "48;2;" : "38;2;") //
+ std::to_string(red_) + ";" //
+ std::to_string(green_) + ";" //
+ std::to_string(blue_); //
return (is_background_color ? "48;2;"s : "38;2;"s) //
+ std::to_string(red_) + ";" //
+ std::to_string(green_) + ";" //
+ std::to_string(blue_); //
}
return "";
}
/// @brief Build a transparent color.
/// @ingroup screen
Color::Color() : type_(ColorType::Palette1) {}
Color::Color() = default;
/// @brief Build a transparent color.
/// @ingroup screen
Color::Color(Palette1) : type_(ColorType::Palette1) {}
Color::Color(Palette1 /*value*/) : Color() {}
/// @brief Build a transparent using Palette16 colors.
/// @ingroup screen
Color::Color(Palette16 index) : type_(ColorType::Palette16), index_(index) {}
Color::Color(Palette16 index) : type_(ColorType::Palette16), red_(index) {}
/// @brief Build a transparent using Palette256 colors.
/// @ingroup screen
Color::Color(Palette256 index) : type_(ColorType::Palette256), index_(index) {
if (Terminal::ColorSupport() >= Terminal::Color::Palette256)
Color::Color(Palette256 index) : type_(ColorType::Palette256), red_(index) {
if (Terminal::ColorSupport() >= Terminal::Color::Palette256) {
return;
}
type_ = ColorType::Palette16;
index_ = GetColorInfo(Color::Palette256(index_)).index_16;
red_ = GetColorInfo(Color::Palette256(red_)).index_16;
}
/// @brief Build a Color from its RGB representation.
@@ -75,12 +92,17 @@ Color::Color(Palette256 index) : type_(ColorType::Palette256), index_(index) {
/// @ingroup screen
Color::Color(uint8_t red, uint8_t green, uint8_t blue)
: type_(ColorType::TrueColor), red_(red), green_(green), blue_(blue) {
if (Terminal::ColorSupport() == Terminal::Color::TrueColor)
if (Terminal::ColorSupport() == Terminal::Color::TrueColor) {
return;
}
int closest = 256 * 256 * 3;
// Find the closest coor from the database:
const int max_distance = 256 * 256 * 3;
int closest = max_distance;
int best = 0;
for (int i = 16; i < 256; ++i) {
const int database_begin = 16;
const int database_end = 256;
for (int i = database_begin; i < database_end; ++i) {
ColorInfo color_info = GetColorInfo(Color::Palette256(i));
int dr = color_info.red - red;
int dg = color_info.green - green;
@@ -94,10 +116,10 @@ Color::Color(uint8_t red, uint8_t green, uint8_t blue)
if (Terminal::ColorSupport() == Terminal::Color::Palette256) {
type_ = ColorType::Palette256;
index_ = best;
red_ = best;
} else {
type_ = ColorType::Palette16;
index_ = GetColorInfo(Color::Palette256(best)).index_16;
red_ = GetColorInfo(Color::Palette256(best)).index_16;
}
}
@@ -122,24 +144,25 @@ Color Color::RGB(uint8_t red, uint8_t green, uint8_t blue) {
/// @ingroup screen
// static
Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
if (s == 0)
if (s == 0) {
return Color(v, v, v);
}
uint8_t region = h / 43;
uint8_t remainder = (h - (region * 43)) * 6;
uint8_t p = (v * (255 - s)) >> 8;
uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8;
uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
uint8_t region = h / 43; // NOLINT
uint8_t remainder = (h - (region * 43)) * 6; // NOLINT
uint8_t p = (v * (255 - s)) >> 8; // NOLINT
uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8; // NOLINT
uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8; // NOLINT
// clang-format off
switch (region) {
case 0: return Color(v,t,p);
case 1: return Color(q,v,p);
case 2: return Color(p,v,t);
case 3: return Color(p,q,v);
case 4: return Color(t,p,v);
case 5: return Color(v,p,q);
}
switch (region) { // NOLINT
case 0: return Color(v,t,p); // NOLINT
case 1: return Color(q,v,p); // NOLINT
case 2: return Color(p,v,t); // NOLINT
case 3: return Color(p,q,v); // NOLINT
case 4: return Color(t,p,v); // NOLINT
case 5: return Color(v,p,q); // NOLINT
} // NOLINT
// clang-format on
return Color(0, 0, 0);
@@ -147,81 +170,77 @@ Color Color::HSV(uint8_t h, uint8_t s, uint8_t v) {
// static
Color Color::Interpolate(float t, const Color& a, const Color& b) {
float red = 0.f;
float green = 0.f;
float blue = 0.f;
switch (a.type_) {
case ColorType::Palette1: {
if (t < 0.5)
return a;
else
return b;
}
case ColorType::Palette16: {
ColorInfo info = GetColorInfo(Color::Palette16(a.index_));
red = info.red * (1 - t);
green = info.green * (1 - t);
blue = info.blue * (1 - t);
break;
}
case ColorType::Palette256: {
ColorInfo info = GetColorInfo(Color::Palette256(a.index_));
red = info.red * (1 - t);
green = info.green * (1 - t);
blue = info.blue * (1 - t);
break;
}
case ColorType::TrueColor: {
red = a.red_ * (1 - t);
green = a.green_ * (1 - t);
blue = a.blue_ * (1 - t);
break;
if (a.type_ == ColorType::Palette1) {
if (t < 0.5F) { // NOLINT
return a;
} else {
return b;
}
}
switch (b.type_) {
case ColorType::Palette1: {
if (t > 0.5)
return a;
else
return b;
}
case ColorType::Palette16: {
ColorInfo info = GetColorInfo(Color::Palette16(b.index_));
red += info.red * t;
green += info.green * t;
blue += info.blue * t;
break;
}
case ColorType::Palette256: {
ColorInfo info = GetColorInfo(Color::Palette256(b.index_));
red += info.red * t;
green += info.green * t;
blue += info.blue * t;
break;
}
case ColorType::TrueColor: {
red += b.red_ * t;
green += b.green_ * t;
blue += b.blue_ * t;
break;
if (b.type_ == ColorType::Palette1) {
if (t > 0.5F) { // NOLINT
return a;
} else {
return b;
}
}
return Color::RGB(red, green, blue);
auto get_color = [](const Color& color, //
uint8_t* red, uint8_t* green, uint8_t* blue) {
switch (color.type_) {
case ColorType::Palette1: {
return;
}
case ColorType::Palette16: {
ColorInfo info = GetColorInfo(Color::Palette16(color.red_));
*red = info.red;
*green = info.green;
*blue = info.blue;
return;
}
case ColorType::Palette256: {
ColorInfo info = GetColorInfo(Color::Palette256(color.red_));
*red = info.red;
*green = info.green;
*blue = info.blue;
return;
}
case ColorType::TrueColor: {
*red = color.red_;
*green = color.green_;
*blue = color.blue_;
return;
}
}
};
uint8_t red_a = 0;
uint8_t green_a = 0;
uint8_t blue_a = 0;
uint8_t red_b = 0;
uint8_t green_b = 0;
uint8_t blue_b = 0;
get_color(a, &red_a, &green_a, &blue_a);
get_color(b, &red_b, &green_b, &blue_b);
return Color::RGB(static_cast<uint8_t>(static_cast<float>(red_a) * (1 - t) +
static_cast<float>(red_b) * t),
static_cast<uint8_t>(static_cast<float>(green_a) * (1 - t) +
static_cast<float>(green_b) * t),
static_cast<uint8_t>(static_cast<float>(blue_a) * (1 - t) +
static_cast<float>(blue_b) * t));
}
inline namespace literals {
Color operator""_rgb(unsigned long long int combined) {
assert(combined <= 0xffffffU);
auto const red = static_cast<uint8_t>(combined >> 16);
auto const green = static_cast<uint8_t>(combined >> 8);
// assert(combined <= 0xffffffU);
auto const red = static_cast<uint8_t>(combined >> 16U);
auto const green = static_cast<uint8_t>(combined >> 8U);
auto const blue = static_cast<uint8_t>(combined);
return Color(red, green, blue);
}

View File

@@ -1,10 +1,13 @@
#include "ftxui/screen/color_info.hpp"
#include <array>
#include "ftxui/screen/color.hpp" // for Color, Color::Palette16, Color::Palette256
namespace ftxui {
// clang-format off
const ColorInfo palette256[] = {
const std::array<ColorInfo, 256> palette256 = {{
{"Black" , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{"Red" , 1 , 1 , 128 , 0 , 0 , 0 , 255 , 128 } ,
{"Green" , 2 , 2 , 0 , 128 , 0 , 85 , 255 , 128 } ,
@@ -261,14 +264,14 @@ const ColorInfo palette256[] = {
{"Grey85" , 253 , 7 , 218 , 218 , 218 , 0 , 0 , 218 } ,
{"Grey89" , 254 , 15 , 228 , 228 , 228 , 0 , 0 , 228 } ,
{"Grey93" , 255 , 15 , 238 , 238 , 238 , 0 , 0 , 238 } ,
} ;
}};
ColorInfo GetColorInfo(Color::Palette256 index) {
return palette256[int(index)];
return palette256[index]; // NOLINT;
}
ColorInfo GetColorInfo(Color::Palette16 index) {
return palette256[int(index)];
return palette256[index]; // NOLINT;
}
// clang-format off

View File

@@ -1,6 +1,7 @@
#include <stdint.h> // for uint8_t
#include <iostream> // for operator<<, stringstream, basic_ostream, flush, cout, ostream
#include <map> // for _Rb_tree_const_iterator, map, operator!=, operator==
#include <memory> // for allocator, allocator_traits<>::value_type
#include <memory> // for allocator
#include <sstream> // IWYU pragma: keep
#include <utility> // for pair
@@ -19,26 +20,11 @@
namespace ftxui {
namespace {
static const char BOLD_SET[] = "\x1B[1m";
static const char BOLD_RESET[] = "\x1B[22m"; // Can't use 21 here.
static const char DIM_SET[] = "\x1B[2m";
static const char DIM_RESET[] = "\x1B[22m";
static const char UNDERLINED_SET[] = "\x1B[4m";
static const char UNDERLINED_RESET[] = "\x1B[24m";
static const char BLINK_SET[] = "\x1B[5m";
static const char BLINK_RESET[] = "\x1B[25m";
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";
Pixel dev_null_pixel;
Pixel& dev_null_pixel() {
static Pixel pixel;
return pixel;
}
#if defined(_WIN32)
void WindowsEmulateVT100Terminal() {
@@ -66,20 +52,49 @@ void WindowsEmulateVT100Terminal() {
void UpdatePixelStyle(std::stringstream& ss,
Pixel& previous,
const Pixel& next) {
if (next.bold != previous.bold)
ss << (next.bold ? BOLD_SET : BOLD_RESET);
if (next == previous) {
return;
}
if (next.dim != previous.dim)
ss << (next.dim ? DIM_SET : DIM_RESET);
if (next.bold && !previous.bold) {
ss << "\x1B[1m"; // BOLD_SET
}
if (next.underlined != previous.underlined)
ss << (next.underlined ? UNDERLINED_SET : UNDERLINED_RESET);
if (!next.bold && previous.bold) {
ss << "\x1B[22m"; // BOLD_RESET
}
if (next.blink != previous.blink)
ss << (next.blink ? BLINK_SET : BLINK_RESET);
if (next.dim && !previous.dim) {
ss << "\x1B[2m"; // DIM_SET
}
if (next.inverted != previous.inverted)
ss << (next.inverted ? INVERTED_SET : INVERTED_RESET);
if (!next.dim && previous.dim) {
ss << "\x1B[22m"; // DIM_RESET
}
if (next.underlined && !previous.underlined) {
ss << "\x1B[4m"; // UNDERLINED_SET
}
if (!next.underlined && previous.underlined) {
ss << "\x1B[24m"; // UNDERLINED_RESET
}
if (next.blink && !previous.blink) {
ss << "\x1B[5m"; // BLINK_SET
}
if (!next.blink && previous.blink) {
ss << "\x1B[25m"; // BLINK_RESET
}
if (next.inverted && !previous.inverted) {
ss << "\x1B[7m"; // INVERTED_SET
}
if (!next.inverted && previous.inverted) {
ss << "\x1B[27m"; // INVERTED_RESET
}
if (next.foreground_color != previous.foreground_color ||
next.background_color != previous.background_color) {
@@ -91,31 +106,31 @@ void UpdatePixelStyle(std::stringstream& ss,
}
struct TileEncoding {
unsigned int left : 2;
unsigned int top : 2;
unsigned int right : 2;
unsigned int down : 2;
unsigned int round : 1;
uint8_t left : 2;
uint8_t top : 2;
uint8_t right : 2;
uint8_t down : 2;
uint8_t round : 1;
// clang-format off
bool operator<(const TileEncoding& other) const {
if (left < other.left) return true;
if (left > other.left) return false;
if (top < other.top) return true;
if (top > other.top) return false;
if (right < other.right) return true;
if (right > other.right) return false;
if (down < other.down) return true;
if (down > other.down) return false;
if (round < other.round) return true;
if (round > other.round) return false;
if (left < other.left) { return true; }
if (left > other.left) { return false; }
if (top < other.top) { return true; }
if (top > other.top) { return false; }
if (right < other.right) { return true; }
if (right > other.right) { return false; }
if (down < other.down) { return true; }
if (down > other.down) { return false; }
if (round < other.round) { return true; }
if (round > other.round) { return false; }
return false;
}
// clang-format on
};
// clang-format off
const std::map<std::string, TileEncoding> tile_encoding = {
const std::map<std::string, TileEncoding> tile_encoding = { // NOLINT
{"", {1, 0, 1, 0, 0}},
{"", {2, 0, 2, 0, 0}},
@@ -257,63 +272,72 @@ const std::map<std::string, TileEncoding> tile_encoding = {
// clang-format on
template <class A, class B>
const std::map<B, A> InvertMap(const std::map<A, B> input) {
std::map<B, A> InvertMap(const std::map<A, B> input) {
std::map<B, A> output;
for (const auto& it : input)
for (const auto& it : input) {
output[it.second] = it.first;
}
return output;
}
const std::map<TileEncoding, std::string> tile_encoding_inverse =
const std::map<TileEncoding, std::string> tile_encoding_inverse = // NOLINT
InvertMap(tile_encoding);
void UpgradeLeftRight(std::string& left, std::string& right) {
const auto it_left = tile_encoding.find(left);
if (it_left == tile_encoding.end())
if (it_left == tile_encoding.end()) {
return;
}
const auto it_right = tile_encoding.find(right);
if (it_right == tile_encoding.end())
if (it_right == tile_encoding.end()) {
return;
}
if (it_left->second.right == 0 && it_right->second.left != 0) {
TileEncoding encoding_left = it_left->second;
encoding_left.right = it_right->second.left;
const auto it_left_upgrade = tile_encoding_inverse.find(encoding_left);
if (it_left_upgrade != tile_encoding_inverse.end())
if (it_left_upgrade != tile_encoding_inverse.end()) {
left = it_left_upgrade->second;
}
}
if (it_right->second.left == 0 && it_left->second.right != 0) {
TileEncoding encoding_right = it_right->second;
encoding_right.left = it_left->second.right;
const auto it_right_upgrade = tile_encoding_inverse.find(encoding_right);
if (it_right_upgrade != tile_encoding_inverse.end())
if (it_right_upgrade != tile_encoding_inverse.end()) {
right = it_right_upgrade->second;
}
}
}
void UpgradeTopDown(std::string& top, std::string& down) {
const auto it_top = tile_encoding.find(top);
if (it_top == tile_encoding.end())
if (it_top == tile_encoding.end()) {
return;
}
const auto it_down = tile_encoding.find(down);
if (it_down == tile_encoding.end())
if (it_down == tile_encoding.end()) {
return;
}
if (it_top->second.down == 0 && it_down->second.top != 0) {
TileEncoding encoding_top = it_top->second;
encoding_top.down = it_down->second.top;
const auto it_top_down = tile_encoding_inverse.find(encoding_top);
if (it_top_down != tile_encoding_inverse.end())
if (it_top_down != tile_encoding_inverse.end()) {
top = it_top_down->second;
}
}
if (it_down->second.top == 0 && it_top->second.down != 0) {
TileEncoding encoding_down = it_down->second;
encoding_down.top = it_top->second.down;
const auto it_down_top = tile_encoding_inverse.find(encoding_down);
if (it_down_top != tile_encoding_inverse.end())
if (it_down_top != tile_encoding_inverse.end()) {
down = it_down_top->second;
}
}
}
@@ -323,6 +347,18 @@ bool ShouldAttemptAutoMerge(Pixel& pixel) {
} // namespace
bool Pixel::operator==(const Pixel& other) const {
return character == other.character && //
background_color == other.background_color && //
foreground_color == other.foreground_color && //
blink == other.blink && //
bold == other.bold && //
dim == other.dim && //
inverted == other.inverted && //
underlined == other.underlined && //
automerge == other.automerge; //
}
/// A fixed dimension.
/// @see Fit
/// @see Full
@@ -409,7 +445,7 @@ std::string& Screen::at(int x, int y) {
/// @param x The pixel position along the x-axis.
/// @param y The pixel position along the y-axis.
Pixel& Screen::PixelAt(int x, int y) {
return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel;
return stencil.Contain(x, y) ? pixels_[y][x] : dev_null_pixel();
}
/// @brief Return a string to be printed in order to reset the cursor position
@@ -431,17 +467,19 @@ Pixel& Screen::PixelAt(int x, int y) {
///
/// @return The string to print in order to reset the cursor position to the
/// beginning.
std::string Screen::ResetPosition(bool clear) {
std::string Screen::ResetPosition(bool clear) const {
std::stringstream ss;
if (clear) {
ss << MOVE_LEFT << CLEAR_LINE;
ss << "\r"; // MOVE_LEFT;
ss << "\x1b[2K"; // CLEAR_SCREEN;
for (int y = 1; y < dimy_; ++y) {
ss << MOVE_UP << CLEAR_LINE;
ss << "\x1B[1A"; // MOVE_UP;
ss << "\x1B[2K"; // CLEAR_LINE;
}
} else {
ss << MOVE_LEFT;
ss << "\r"; // MOVE_LEFT;
for (int y = 1; y < dimy_; ++y) {
ss << MOVE_UP;
ss << "\x1B[1A"; // MOVE_UP;
}
}
return ss.str();
@@ -462,16 +500,19 @@ void Screen::ApplyShader() {
for (int x = 1; x < dimx_; ++x) {
// Box drawing character uses exactly 3 byte.
Pixel& cur = pixels_[y][x];
if (!ShouldAttemptAutoMerge(cur))
if (!ShouldAttemptAutoMerge(cur)) {
continue;
}
Pixel& left = pixels_[y][x-1];
Pixel& top = pixels_[y-1][x];
if (ShouldAttemptAutoMerge(left))
if (ShouldAttemptAutoMerge(left)) {
UpgradeLeftRight(left.character, cur.character);
if (ShouldAttemptAutoMerge(top))
}
if (ShouldAttemptAutoMerge(top)) {
UpgradeTopDown(top.character, cur.character);
}
}
}
}

View File

@@ -7,11 +7,11 @@
#include "ftxui/screen/string.hpp"
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint8_t
#include <codecvt> // for codecvt_utf8_utf16
#include <locale> // for wstring_convert
#include <string> // for string, basic_string, wstring, allocator
#include <array> // for array
#include <codecvt> // for codecvt_utf8_utf16
#include <cstdint> // for uint32_t, uint8_t
#include <locale> // for wstring_convert
#include <string> // for string, basic_string, wstring
#include "ftxui/screen/deprecated.hpp" // for wchar_width, wstring_width
@@ -24,115 +24,149 @@ struct Interval {
// 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},
const std::array<Interval, 142> g_combining_characters = {
Interval{0x0300, 0x036F}, Interval{0x0483, 0x0486},
Interval{0x0488, 0x0489}, Interval{0x0591, 0x05BD},
Interval{0x05BF, 0x05BF}, Interval{0x05C1, 0x05C2},
Interval{0x05C4, 0x05C5}, Interval{0x05C7, 0x05C7},
Interval{0x0600, 0x0603}, Interval{0x0610, 0x0615},
Interval{0x064B, 0x065E}, Interval{0x0670, 0x0670},
Interval{0x06D6, 0x06E4}, Interval{0x06E7, 0x06E8},
Interval{0x06EA, 0x06ED}, Interval{0x070F, 0x070F},
Interval{0x0711, 0x0711}, Interval{0x0730, 0x074A},
Interval{0x07A6, 0x07B0}, Interval{0x07EB, 0x07F3},
Interval{0x0901, 0x0902}, Interval{0x093C, 0x093C},
Interval{0x0941, 0x0948}, Interval{0x094D, 0x094D},
Interval{0x0951, 0x0954}, Interval{0x0962, 0x0963},
Interval{0x0981, 0x0981}, Interval{0x09BC, 0x09BC},
Interval{0x09C1, 0x09C4}, Interval{0x09CD, 0x09CD},
Interval{0x09E2, 0x09E3}, Interval{0x0A01, 0x0A02},
Interval{0x0A3C, 0x0A3C}, Interval{0x0A41, 0x0A42},
Interval{0x0A47, 0x0A48}, Interval{0x0A4B, 0x0A4D},
Interval{0x0A70, 0x0A71}, Interval{0x0A81, 0x0A82},
Interval{0x0ABC, 0x0ABC}, Interval{0x0AC1, 0x0AC5},
Interval{0x0AC7, 0x0AC8}, Interval{0x0ACD, 0x0ACD},
Interval{0x0AE2, 0x0AE3}, Interval{0x0B01, 0x0B01},
Interval{0x0B3C, 0x0B3C}, Interval{0x0B3F, 0x0B3F},
Interval{0x0B41, 0x0B43}, Interval{0x0B4D, 0x0B4D},
Interval{0x0B56, 0x0B56}, Interval{0x0B82, 0x0B82},
Interval{0x0BC0, 0x0BC0}, Interval{0x0BCD, 0x0BCD},
Interval{0x0C3E, 0x0C40}, Interval{0x0C46, 0x0C48},
Interval{0x0C4A, 0x0C4D}, Interval{0x0C55, 0x0C56},
Interval{0x0CBC, 0x0CBC}, Interval{0x0CBF, 0x0CBF},
Interval{0x0CC6, 0x0CC6}, Interval{0x0CCC, 0x0CCD},
Interval{0x0CE2, 0x0CE3}, Interval{0x0D41, 0x0D43},
Interval{0x0D4D, 0x0D4D}, Interval{0x0DCA, 0x0DCA},
Interval{0x0DD2, 0x0DD4}, Interval{0x0DD6, 0x0DD6},
Interval{0x0E31, 0x0E31}, Interval{0x0E34, 0x0E3A},
Interval{0x0E47, 0x0E4E}, Interval{0x0EB1, 0x0EB1},
Interval{0x0EB4, 0x0EB9}, Interval{0x0EBB, 0x0EBC},
Interval{0x0EC8, 0x0ECD}, Interval{0x0F18, 0x0F19},
Interval{0x0F35, 0x0F35}, Interval{0x0F37, 0x0F37},
Interval{0x0F39, 0x0F39}, Interval{0x0F71, 0x0F7E},
Interval{0x0F80, 0x0F84}, Interval{0x0F86, 0x0F87},
Interval{0x0F90, 0x0F97}, Interval{0x0F99, 0x0FBC},
Interval{0x0FC6, 0x0FC6}, Interval{0x102D, 0x1030},
Interval{0x1032, 0x1032}, Interval{0x1036, 0x1037},
Interval{0x1039, 0x1039}, Interval{0x1058, 0x1059},
Interval{0x1160, 0x11FF}, Interval{0x135F, 0x135F},
Interval{0x1712, 0x1714}, Interval{0x1732, 0x1734},
Interval{0x1752, 0x1753}, Interval{0x1772, 0x1773},
Interval{0x17B4, 0x17B5}, Interval{0x17B7, 0x17BD},
Interval{0x17C6, 0x17C6}, Interval{0x17C9, 0x17D3},
Interval{0x17DD, 0x17DD}, Interval{0x180B, 0x180D},
Interval{0x18A9, 0x18A9}, Interval{0x1920, 0x1922},
Interval{0x1927, 0x1928}, Interval{0x1932, 0x1932},
Interval{0x1939, 0x193B}, Interval{0x1A17, 0x1A18},
Interval{0x1B00, 0x1B03}, Interval{0x1B34, 0x1B34},
Interval{0x1B36, 0x1B3A}, Interval{0x1B3C, 0x1B3C},
Interval{0x1B42, 0x1B42}, Interval{0x1B6B, 0x1B73},
Interval{0x1DC0, 0x1DCA}, Interval{0x1DFE, 0x1DFF},
Interval{0x200B, 0x200F}, Interval{0x202A, 0x202E},
Interval{0x2060, 0x2063}, Interval{0x206A, 0x206F},
Interval{0x20D0, 0x20EF}, Interval{0x302A, 0x302F},
Interval{0x3099, 0x309A}, Interval{0xA806, 0xA806},
Interval{0xA80B, 0xA80B}, Interval{0xA825, 0xA826},
Interval{0xFB1E, 0xFB1E}, Interval{0xFE00, 0xFE0F},
Interval{0xFE20, 0xFE23}, Interval{0xFEFF, 0xFEFF},
Interval{0xFFF9, 0xFFFB}, Interval{0x10A01, 0x10A03},
Interval{0x10A05, 0x10A06}, Interval{0x10A0C, 0x10A0F},
Interval{0x10A38, 0x10A3A}, Interval{0x10A3F, 0x10A3F},
Interval{0x1D167, 0x1D169}, Interval{0x1D173, 0x1D182},
Interval{0x1D185, 0x1D18B}, Interval{0x1D1AA, 0x1D1AD},
Interval{0x1D242, 0x1D244}, Interval{0xE0001, 0xE0001},
Interval{0xE0020, 0xE007F}, Interval{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},
const std::array<Interval, 13> g_full_width_characters = {
Interval{0x1100, 0x115f}, Interval{0x2329, 0x2329},
Interval{0x232a, 0x232a}, Interval{0x2e80, 0x303e},
Interval{0x3040, 0xa4cf}, Interval{0xac00, 0xd7a3},
Interval{0xf900, 0xfaff}, Interval{0xfe10, 0xfe19},
Interval{0xfe30, 0xfe6f}, Interval{0xff00, 0xff60},
Interval{0xffe0, 0xffe6}, Interval{0x20000, 0x2fffd},
Interval{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;
bool Bisearch(uint32_t ucs, const Interval* table, int max) {
if (ucs < table[0].first || ucs > table[max].last) { // NOLINT
return false;
}
int min = 0;
while (max >= min) {
int mid = (min + max) / 2;
if (ucs > table[mid].last)
if (ucs > table[mid].last) { // NOLINT
min = mid + 1;
else if (ucs < table[mid].first)
} else if (ucs < table[mid].first) { // NOLINT
max = mid - 1;
else
return 1;
} else {
return true;
}
}
return 0;
return false;
}
bool IsCombining(uint32_t ucs) {
return Bisearch(ucs, g_combining_characters,
sizeof(g_combining_characters) / sizeof(Interval) - 1);
return Bisearch(ucs, g_combining_characters.data(),
g_combining_characters.size() - 1);
}
bool IsFullWidth(uint32_t ucs) {
if (ucs < 0x0300) // Quick path:
if (ucs < 0x0300) // Quick path: // NOLINT
return false;
return Bisearch(ucs, g_full_width_characters,
sizeof(g_full_width_characters) / sizeof(Interval) - 1);
return Bisearch(ucs, g_full_width_characters.data(),
g_full_width_characters.size() - 1);
}
bool IsControl(uint32_t ucs) {
if (ucs == 0)
if (ucs == 0) {
return true;
if (ucs < 32)
}
if (ucs < 32) { // NOLINT
return true;
if (ucs >= 0x7f && ucs < 0xa0)
}
if (ucs >= 0x7f && ucs < 0xa0) { // NOLINT
return true;
}
return false;
}
int codepoint_width(uint32_t ucs) {
if (IsControl(ucs))
if (IsControl(ucs)) {
return -1;
}
if (IsCombining(ucs))
if (IsCombining(ucs)) {
return 0;
}
if (IsFullWidth(ucs))
if (IsFullWidth(ucs)) {
return 2;
}
return 1;
}
@@ -152,50 +186,53 @@ bool EatCodePoint(const std::string& input,
uint8_t byte_1 = input[start];
// 1 byte string.
if ((byte_1 & 0b1000'0000) == 0b0000'0000) {
*ucs = byte_1 & 0b0111'1111;
if ((byte_1 & 0b1000'0000) == 0b0000'0000) { // NOLINT
*ucs = byte_1 & 0b0111'1111; // NOLINT
*end = start + 1;
return true;
}
// 2 byte string.
if ((byte_1 & 0b1110'0000) == 0b1100'0000 && start + 1 < input.size()) {
if ((byte_1 & 0b1110'0000) == 0b1100'0000 && // NOLINT
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;
*ucs += byte_1 & 0b0001'1111; // NOLINT
*ucs <<= 6; // NOLINT
*ucs += byte_2 & 0b0011'1111; // NOLINT
*end = start + 2;
return true;
}
// 3 byte string.
if ((byte_1 & 0b1111'0000) == 0b1110'0000 && start + 2 < input.size()) {
if ((byte_1 & 0b1111'0000) == 0b1110'0000 && // NOLINT
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;
*ucs += byte_1 & 0b0000'1111; // NOLINT
*ucs <<= 6; // NOLINT
*ucs += byte_2 & 0b0011'1111; // NOLINT
*ucs <<= 6; // NOLINT
*ucs += byte_3 & 0b0011'1111; // NOLINT
*end = start + 3;
return true;
}
// 4 byte string.
if ((byte_1 & 0b1111'1000) == 0b1111'0000 && start + 3 < input.size()) {
if ((byte_1 & 0b1111'1000) == 0b1111'0000 && // NOLINT
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;
*ucs += byte_1 & 0b0000'0111; // NOLINT
*ucs <<= 6; // NOLINT
*ucs += byte_2 & 0b0011'1111; // NOLINT
*ucs <<= 6; // NOLINT
*ucs += byte_3 & 0b0011'1111; // NOLINT
*ucs <<= 6; // NOLINT
*ucs += byte_4 & 0b0011'1111; // NOLINT
*end = start + 4;
return true;
}
@@ -216,8 +253,9 @@ int wstring_width(const std::wstring& text) {
for (const wchar_t& it : text) {
int w = wchar_width(it);
if (w < 0)
if (w < 0) {
return -1;
}
width += w;
}
return width;
@@ -228,14 +266,17 @@ int string_width(const std::string& input) {
size_t start = 0;
while (start < input.size()) {
uint32_t codepoint = 0;
if (!EatCodePoint(input, start, &start, &codepoint))
if (!EatCodePoint(input, start, &start, &codepoint)) {
continue;
}
if (IsControl(codepoint))
if (IsControl(codepoint)) {
continue;
}
if (IsCombining(codepoint))
if (IsCombining(codepoint)) {
continue;
}
if (IsFullWidth(codepoint)) {
width += 2;
@@ -254,7 +295,7 @@ std::vector<std::string> Utf8ToGlyphs(const std::string& input) {
size_t start = 0;
size_t end = 0;
while (start < input.size()) {
uint32_t codepoint;
uint32_t codepoint = 0;
if (!EatCodePoint(input, start, &end, &codepoint)) {
start = end;
continue;
@@ -264,13 +305,15 @@ std::vector<std::string> Utf8ToGlyphs(const std::string& input) {
start = end;
// Ignore control characters.
if (IsControl(codepoint))
if (IsControl(codepoint)) {
continue;
}
// Combining characters are put with the previous glyph they are modifying.
if (IsCombining(codepoint)) {
if (out.size() != 0)
if (!out.empty()) {
out.back() += append;
}
continue;
}
@@ -278,7 +321,7 @@ std::vector<std::string> Utf8ToGlyphs(const std::string& input) {
// string to reserve the space the first is taking.
if (IsFullWidth(codepoint)) {
out.push_back(append);
out.push_back("");
out.emplace_back("");
continue;
}
@@ -288,14 +331,13 @@ std::vector<std::string> Utf8ToGlyphs(const std::string& input) {
return out;
}
int GlyphPosition(const std::string& input,
size_t glyph_to_skip,
size_t start) {
if (glyph_to_skip <= 0)
int GlyphPosition(const std::string& input, size_t glyph_index, size_t start) {
if (glyph_index <= 0) {
return 0;
}
size_t end = 0;
while (start < input.size()) {
uint32_t codepoint;
uint32_t codepoint = 0;
bool eaten = EatCodePoint(input, start, &end, &codepoint);
// Ignore invalid, control characters and combining characters.
@@ -306,14 +348,15 @@ int GlyphPosition(const std::string& input,
// We eat the beginning of the next glyph. If we are eating the one
// requested, return its start position immediately.
if (glyph_to_skip == 0)
return start;
if (glyph_index == 0) {
return static_cast<int>(start);
}
// Otherwise, skip this glyph and iterate:
glyph_to_skip--;
glyph_index--;
start = end;
}
return input.size();
return static_cast<int>(input.size());
}
std::vector<int> CellToGlyphIndex(const std::string& input) {
@@ -323,13 +366,14 @@ std::vector<int> CellToGlyphIndex(const std::string& input) {
size_t start = 0;
size_t end = 0;
while (start < input.size()) {
uint32_t codepoint;
uint32_t codepoint = 0;
bool eaten = EatCodePoint(input, start, &end, &codepoint);
start = end;
// Ignore invalid / control characters.
if (!eaten || IsControl(codepoint))
if (!eaten || IsControl(codepoint)) {
continue;
}
// Combining characters are put with the previous glyph they are modifying.
if (IsCombining(codepoint)) {
@@ -361,19 +405,21 @@ int GlyphCount(const std::string& input) {
size_t start = 0;
size_t end = 0;
while (start < input.size()) {
uint32_t codepoint;
uint32_t codepoint = 0;
bool eaten = EatCodePoint(input, start, &end, &codepoint);
start = end;
// Ignore invalid characters:
if (!eaten || IsControl(codepoint))
if (!eaten || IsControl(codepoint)) {
continue;
}
// Ignore combining characters, except when they don't have a preceding to
// combine with.
if (IsCombining(codepoint)) {
if (size == 0)
if (size == 0) {
size++;
}
continue;
}

View File

@@ -18,89 +18,57 @@
namespace ftxui {
#if defined(__EMSCRIPTEN__)
// This dimension was chosen arbitrarily to be able to display:
// https://arthursonzogni.com/FTXUI/examples
// This will have to be improved when someone has time to implement and need
// it.
static Dimensions fallback_size{140, 43};
Dimensions Terminal::Size() {
return fallback_size;
}
#elif defined(_WIN32)
// The terminal size in VT100 was 80x24. It is still used nowadays by
// default in many terminal emulator. That's a good choice for a fallback
// value.
static Dimensions fallback_size{80, 24};
Dimensions Terminal::Size() {
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
return Dimensions{csbi.srWindow.Right - csbi.srWindow.Left + 1,
csbi.srWindow.Bottom - csbi.srWindow.Top + 1};
}
return fallback_size;
}
#else
// The terminal size in VT100 was 80x24. It is still used nowadays by
// default in many terminal emulator. That's a good choice for a fallback
// value.
static Dimensions fallback_size{80, 24};
Dimensions Terminal::Size() {
winsize w{};
const int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
// The ioctl return value result should be checked. Some operating systems
// don't support TIOCGWINSZ.
if (w.ws_col == 0 || w.ws_row == 0 || status < 0) {
return fallback_size;
}
return Dimensions{w.ws_col, w.ws_row};
}
#endif
/// @brief Override terminal size in case auto-detection fails
/// @param fallbackSize Terminal dimensions to fallback to
void Terminal::SetFallbackSize(const Dimensions& fallbackSize) {
fallback_size = fallbackSize;
}
namespace {
Dimensions& FallbackSize() {
#if defined(__EMSCRIPTEN__)
// This dimension was chosen arbitrarily to be able to display:
// https://arthursonzogni.com/FTXUI/examples
// This will have to be improved when someone has time to implement and need
// it.
constexpr int fallback_width = 140;
constexpr int fallback_height = 43;
#else
// The terminal size in VT100 was 80x24. It is still used nowadays by
// default in many terminal emulator. That's a good choice for a fallback
// value.
constexpr int fallback_width = 80;
constexpr int fallback_height = 24;
#endif
static Dimensions g_fallback_size{fallback_width, fallback_height};
return g_fallback_size;
}
const char* Safe(const char* c) {
return c ? c : "";
return (c != nullptr) ? c : "";
}
bool Contains(const std::string& s, const char* key) {
return s.find(key) != std::string::npos;
}
static bool cached = false;
Terminal::Color cached_supported_color;
Terminal::Color ComputeColorSupport() {
#if defined(__EMSCRIPTEN__)
return Terminal::Color::TrueColor;
#endif
std::string COLORTERM = Safe(std::getenv("COLORTERM"));
if (Contains(COLORTERM, "24bit") || Contains(COLORTERM, "truecolor"))
std::string COLORTERM = Safe(std::getenv("COLORTERM")); // NOLINT
if (Contains(COLORTERM, "24bit") || Contains(COLORTERM, "truecolor")) {
return Terminal::Color::TrueColor;
}
std::string TERM = Safe(std::getenv("TERM"));
if (Contains(COLORTERM, "256") || Contains(TERM, "256"))
std::string TERM = Safe(std::getenv("TERM")); // NOLINT
if (Contains(COLORTERM, "256") || Contains(TERM, "256")) {
return Terminal::Color::Palette256;
}
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
// Microsoft terminals do not properly declare themselve supporting true
// colors: https://github.com/microsoft/terminal/issues/1040
// As a fallback, assume microsoft terminal are the ones not setting those
// variables, and enable true colors.
if (TERM == "" && COLORTERM == "")
if (TERM == "" && COLORTERM == "") {
return Terminal::Color::TrueColor;
}
#endif
return Terminal::Color::Palette16;
@@ -108,7 +76,43 @@ Terminal::Color ComputeColorSupport() {
} // namespace
Dimensions Terminal::Size() {
#if defined(__EMSCRIPTEN__)
// This dimension was chosen arbitrarily to be able to display:
// https://arthursonzogni.com/FTXUI/examples
// This will have to be improved when someone has time to implement and need
// it.
return FallbackSize();
#elif defined(_WIN32)
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
return Dimensions{csbi.srWindow.Right - csbi.srWindow.Left + 1,
csbi.srWindow.Bottom - csbi.srWindow.Top + 1};
}
return FallbackSize();
#else
winsize w{};
const int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); // NOLINT
// The ioctl return value result should be checked. Some operating systems
// don't support TIOCGWINSZ.
if (w.ws_col == 0 || w.ws_row == 0 || status < 0) {
return FallbackSize();
}
return Dimensions{w.ws_col, w.ws_row};
#endif
}
/// @brief Override terminal size in case auto-detection fails
/// @param fallbackSize Terminal dimensions to fallback to
void Terminal::SetFallbackSize(const Dimensions& fallbackSize) {
FallbackSize() = fallbackSize;
}
Terminal::Color Terminal::ColorSupport() {
static bool cached = false;
static Terminal::Color cached_supported_color;
if (!cached) {
cached = true;
cached_supported_color = ComputeColorSupport();