6#include <initializer_list>
14#define WIN32_LEAN_AND_MEAN
25#if defined(__sun) || defined(__illumos__)
26#include <sys/termios.h>
33std::unique_ptr<Terminal::Quirks> g_quirks;
34bool g_color_support_detected =
false;
36bool& ColorSupportDetected() {
37 return g_color_support_detected;
40Terminal::Quirks& GetQuirksInternal() {
42 g_quirks = std::make_unique<Terminal::Quirks>();
44 g_quirks->SetBlockCharacters(
false);
45 g_quirks->SetCursorHiding(
false);
46 g_quirks->SetComponentAscii(
true);
52Dimensions& FallbackSize() {
53#if defined(__EMSCRIPTEN__)
58 constexpr int fallback_width = 140;
59 constexpr int fallback_height = 43;
64 constexpr int fallback_width = 80;
65 constexpr int fallback_height = 24;
67 static Dimensions g_fallback_size{
71 return g_fallback_size;
74bool Contains(std::string_view s, std::string_view key) {
78 const auto it = std::search(
79 s.begin(), s.end(), key.begin(), key.end(), [](
char a,
char b) {
80 return std::tolower(static_cast<unsigned char>(a)) ==
81 std::tolower(static_cast<unsigned char>(b));
86bool ContainsAny(std::string_view s,
87 std::initializer_list<std::string_view> keys) {
88 for (
const std::string_view key : keys) {
89 if (Contains(s, key)) {
97 static const std::vector<int> empty_capabilities;
100 util::GetEnv(
"TERM_PROGRAM"),
"unknown",
"unknown", empty_capabilities);
108 bool block_characters =
true;
109 bool cursor_hiding =
true;
110 bool component_ascii =
false;
114Quirks::Quirks() : impl_(std::make_unique<Impl>()) {}
115Quirks::~Quirks() =
default;
116Quirks::Quirks(
const Quirks& other)
117 : impl_(std::make_unique<Impl>(*other.impl_)) {}
118Quirks& Quirks::operator=(
const Quirks& other) {
119 if (
this != &other) {
120 *impl_ = *other.impl_;
124Quirks::Quirks(Quirks&&) noexcept = default;
125Quirks& Quirks::operator=(Quirks&&) noexcept = default;
127bool Quirks::BlockCharacters()
const {
128 return impl_->block_characters;
130void Quirks::SetBlockCharacters(
bool v) {
131 impl_->block_characters = v;
134bool Quirks::CursorHiding()
const {
135 return impl_->cursor_hiding;
137void Quirks::SetCursorHiding(
bool v) {
138 impl_->cursor_hiding = v;
141bool Quirks::ComponentAscii()
const {
142 return impl_->component_ascii;
144void Quirks::SetComponentAscii(
bool v) {
145 impl_->component_ascii = v;
148Color Quirks::ColorSupport()
const {
149 return impl_->color_support;
151void Quirks::SetColorSupport(Color v) {
152 impl_->color_support = v;
155struct TerminalInfo::Impl {
157 std::string colorterm;
158 std::string term_program;
159 std::string terminal_name;
160 std::string terminal_emulator_name;
161 std::vector<int> capabilities;
164TerminalInfo::TerminalInfo() : impl_(std::make_unique<Impl>()) {}
165TerminalInfo::~TerminalInfo() =
default;
166TerminalInfo::TerminalInfo(TerminalInfo&&) noexcept = default;
167TerminalInfo& TerminalInfo::operator=(TerminalInfo&&) noexcept = default;
169void TerminalInfo::SetTerm(std::string_view term) {
172void TerminalInfo::SetColorterm(std::string_view colorterm) {
173 impl_->colorterm = colorterm;
175void TerminalInfo::SetTermProgram(std::string_view term_program) {
176 impl_->term_program = term_program;
178void TerminalInfo::SetTerminalName(std::string_view terminal_name) {
179 impl_->terminal_name = terminal_name;
181void TerminalInfo::SetTerminalEmulatorName(
182 std::string_view terminal_emulator_name) {
183 impl_->terminal_emulator_name = terminal_emulator_name;
185void TerminalInfo::SetCapabilities(std::vector<int> capabilities) {
186 impl_->capabilities = std::move(capabilities);
197Color ComputeColorSupport(std::string_view term,
198 std::string_view colorterm,
199 std::string_view term_program,
200 std::string_view terminal_name,
201 std::string_view terminal_emulator_name,
202 const std::vector<int>& capabilities) {
205 info.SetColorterm(colorterm);
206 info.SetTermProgram(term_program);
207 info.SetTerminalName(terminal_name);
208 info.SetTerminalEmulatorName(terminal_emulator_name);
209 info.SetCapabilities(capabilities);
210 return info.ComputeColorSupport();
213Color TerminalInfo::ComputeColorSupport()
const {
220 if (util::GetEnv(
"NO_COLOR")[0] !=
'\0') {
221 return Terminal::Color::Palette1;
225#if defined(__EMSCRIPTEN__)
226 return Terminal::Color::TrueColor;
230 auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
232 if (GetConsoleMode(stdout_handle, &out_mode)) {
233 const int enable_virtual_terminal_processing = 0x0004;
234 const int disable_newline_auto_return = 0x0008;
235 out_mode |= enable_virtual_terminal_processing;
236 out_mode |= disable_newline_auto_return;
237 if (!SetConsoleMode(stdout_handle, out_mode)) {
238 return Terminal::Color::Palette16;
241 return Terminal::Color::TrueColor;
245 if (util::GetEnv(
"WT_SESSION")[0] !=
'\0') {
246 return Terminal::Color::TrueColor;
250 if (ContainsAny(impl_->colorterm, {
"24bit",
"truecolor"})) {
251 return Terminal::Color::TrueColor;
253 if (ContainsAny(impl_->term,
254 {
"direct",
"truecolor",
"kitty",
"alacritty",
"foot"})) {
255 return Terminal::Color::TrueColor;
257 if (ContainsAny(impl_->colorterm, {
"256"}) ||
258 ContainsAny(impl_->term, {
"256",
"xterm",
"screen",
"tmux"})) {
259 return Terminal::Color::Palette256;
263 if (ContainsAny(impl_->term_program, {
270 return Terminal::Color::TrueColor;
274 if (Contains(impl_->term_program,
"apple_terminal")) {
275 return Terminal::Color::Palette256;
281 if (!impl_->terminal_emulator_name.empty() &&
282 impl_->terminal_emulator_name !=
"unknown") {
283 return Terminal::Color::TrueColor;
285 if (impl_->terminal_name ==
"xterm") {
286 return Terminal::Color::TrueColor;
288 for (
const int x : impl_->capabilities) {
294 return Terminal::Color::Palette256;
298 return Terminal::Color::Palette16;
305#if defined(__EMSCRIPTEN__)
310 return FallbackSize();
312 CONSOLE_SCREEN_BUFFER_INFO csbi;
314 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
315 return Dimensions{csbi.srWindow.Right - csbi.srWindow.Left + 1,
316 csbi.srWindow.Bottom - csbi.srWindow.Top + 1};
319 return FallbackSize();
322 const int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
325 if (w.ws_col == 0 || w.ws_row == 0 || status < 0) {
326 return FallbackSize();
328 return Dimensions{w.ws_col, w.ws_row};
334void SetFallbackSize(
const Dimensions& fallbackSize) {
335 FallbackSize() = fallbackSize;
341 if (!ColorSupportDetected()) {
342 GetQuirksInternal().SetColorSupport(ComputeColorSupportInternal());
343 ColorSupportDetected() =
true;
345 return GetQuirksInternal().ColorSupport();
351 GetQuirksInternal().SetColorSupport(color);
352 ColorSupportDetected() =
true;
358 if (!ColorSupportDetected()) {
359 GetQuirksInternal().SetColorSupport(ComputeColorSupportInternal());
360 ColorSupportDetected() =
true;
362 return GetQuirksInternal();
367void SetQuirks(
const Quirks& quirks) {
368 GetQuirksInternal() = quirks;
369 ColorSupportDetected() =
true;
Color
Color is an enumeration that represents the color support of the terminal.
The FTXUI ftxui::Terminal:: namespace.
Color ComputeColorSupport(std::string_view term, std::string_view colorterm, std::string_view term_program, std::string_view terminal_name, std::string_view terminal_emulator_name, const std::vector< int > &capabilities)
Compute the color support based on environment variables and terminal identification.
const char * GetEnv(const char *name)
The FTXUI ftxui:: namespace.