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__)
56 constexpr int fallback_width = 140;
57 constexpr int fallback_height = 43;
60 constexpr int fallback_width = 80;
61 constexpr int fallback_height = 24;
63 static Dimensions g_fallback_size{
67 return g_fallback_size;
70bool Contains(std::string_view s, std::string_view key) {
74 const auto it = std::search(
75 s.begin(), s.end(), key.begin(), key.end(), [](
char a,
char b) {
76 return std::tolower(static_cast<unsigned char>(a)) ==
77 std::tolower(static_cast<unsigned char>(b));
82bool ContainsAny(std::string_view s,
83 std::initializer_list<std::string_view> keys) {
84 for (
const std::string_view key : keys) {
85 if (Contains(s, key)) {
93 static const std::vector<int> empty_capabilities;
96 util::GetEnv(
"TERM_PROGRAM"),
"unknown",
"unknown", empty_capabilities);
104 bool block_characters =
true;
105 bool cursor_hiding =
true;
106 bool component_ascii =
false;
110Quirks::Quirks() : impl_(std::make_unique<Impl>()) {}
111Quirks::~Quirks() =
default;
112Quirks::Quirks(
const Quirks& other)
113 : impl_(std::make_unique<Impl>(*other.impl_)) {}
114Quirks& Quirks::operator=(
const Quirks& other) {
115 if (
this != &other) {
116 *impl_ = *other.impl_;
120Quirks::Quirks(Quirks&&) noexcept = default;
121Quirks& Quirks::operator=(Quirks&&) noexcept = default;
123bool Quirks::BlockCharacters()
const {
124 return impl_->block_characters;
126void Quirks::SetBlockCharacters(
bool v) {
127 impl_->block_characters = v;
130bool Quirks::CursorHiding()
const {
131 return impl_->cursor_hiding;
133void Quirks::SetCursorHiding(
bool v) {
134 impl_->cursor_hiding = v;
137bool Quirks::ComponentAscii()
const {
138 return impl_->component_ascii;
140void Quirks::SetComponentAscii(
bool v) {
141 impl_->component_ascii = v;
144Color Quirks::ColorSupport()
const {
145 return impl_->color_support;
147void Quirks::SetColorSupport(Color v) {
148 impl_->color_support = v;
151struct TerminalInfo::Impl {
153 std::string colorterm;
154 std::string term_program;
155 std::string terminal_name;
156 std::string terminal_emulator_name;
157 std::vector<int> capabilities;
160TerminalInfo::TerminalInfo() : impl_(std::make_unique<Impl>()) {}
161TerminalInfo::~TerminalInfo() =
default;
162TerminalInfo::TerminalInfo(TerminalInfo&&) noexcept = default;
163TerminalInfo& TerminalInfo::operator=(TerminalInfo&&) noexcept = default;
165void TerminalInfo::SetTerm(std::string_view term) {
168void TerminalInfo::SetColorterm(std::string_view colorterm) {
169 impl_->colorterm = colorterm;
171void TerminalInfo::SetTermProgram(std::string_view term_program) {
172 impl_->term_program = term_program;
174void TerminalInfo::SetTerminalName(std::string_view terminal_name) {
175 impl_->terminal_name = terminal_name;
177void TerminalInfo::SetTerminalEmulatorName(
178 std::string_view terminal_emulator_name) {
179 impl_->terminal_emulator_name = terminal_emulator_name;
181void TerminalInfo::SetCapabilities(std::vector<int> capabilities) {
182 impl_->capabilities = std::move(capabilities);
193 std::string_view colorterm,
194 std::string_view term_program,
195 std::string_view terminal_name,
196 std::string_view terminal_emulator_name,
197 const std::vector<int>& capabilities) {
200 info.SetColorterm(colorterm);
201 info.SetTermProgram(term_program);
202 info.SetTerminalName(terminal_name);
203 info.SetTerminalEmulatorName(terminal_emulator_name);
204 info.SetCapabilities(capabilities);
205 return info.ComputeColorSupport();
208Color TerminalInfo::ComputeColorSupport()
const {
215 if (util::GetEnv(
"NO_COLOR")[0] !=
'\0') {
216 return Terminal::Color::Palette1;
220#if defined(__EMSCRIPTEN__)
221 return Terminal::Color::TrueColor;
225 auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
227 if (GetConsoleMode(stdout_handle, &out_mode)) {
228 const int enable_virtual_terminal_processing = 0x0004;
229 const int disable_newline_auto_return = 0x0008;
230 out_mode |= enable_virtual_terminal_processing;
231 out_mode |= disable_newline_auto_return;
232 if (!SetConsoleMode(stdout_handle, out_mode)) {
233 return Terminal::Color::Palette16;
236 return Terminal::Color::TrueColor;
240 if (util::GetEnv(
"WT_SESSION")[0] !=
'\0') {
241 return Terminal::Color::TrueColor;
245 if (ContainsAny(impl_->colorterm, {
"24bit",
"truecolor"})) {
246 return Terminal::Color::TrueColor;
248 if (ContainsAny(impl_->term,
249 {
"direct",
"truecolor",
"kitty",
"alacritty",
"foot"})) {
250 return Terminal::Color::TrueColor;
252 if (ContainsAny(impl_->colorterm, {
"256"}) ||
253 ContainsAny(impl_->term, {
"256",
"xterm",
"screen",
"tmux"})) {
254 return Terminal::Color::Palette256;
258 if (ContainsAny(impl_->term_program, {
265 return Terminal::Color::TrueColor;
269 if (Contains(impl_->term_program,
"apple_terminal")) {
270 return Terminal::Color::Palette256;
276 if (!impl_->terminal_emulator_name.empty() &&
277 impl_->terminal_emulator_name !=
"unknown") {
278 return Terminal::Color::TrueColor;
280 if (impl_->terminal_name ==
"xterm") {
281 return Terminal::Color::TrueColor;
283 for (
const int x : impl_->capabilities) {
289 return Terminal::Color::Palette256;
293 return Terminal::Color::Palette16;
300#if defined(__EMSCRIPTEN__)
303 return FallbackSize();
305 CONSOLE_SCREEN_BUFFER_INFO csbi;
307 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
308 return Dimensions{csbi.srWindow.Right - csbi.srWindow.Left + 1,
309 csbi.srWindow.Bottom - csbi.srWindow.Top + 1};
312 return FallbackSize();
315 const int status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
318 if (w.ws_col == 0 || w.ws_row == 0 || status < 0) {
319 return FallbackSize();
321 return Dimensions{w.ws_col, w.ws_row};
327void SetFallbackSize(
const Dimensions& fallbackSize) {
328 FallbackSize() = fallbackSize;
334 if (!ColorSupportDetected()) {
335 GetQuirksInternal().SetColorSupport(ComputeColorSupportInternal());
336 ColorSupportDetected() =
true;
338 return GetQuirksInternal().ColorSupport();
344 GetQuirksInternal().SetColorSupport(color);
345 ColorSupportDetected() =
true;
351 if (!ColorSupportDetected()) {
352 GetQuirksInternal().SetColorSupport(ComputeColorSupportInternal());
353 ColorSupportDetected() =
true;
355 return GetQuirksInternal();
360void SetQuirks(
const Quirks& quirks) {
361 GetQuirksInternal() = quirks;
362 ColorSupportDetected() =
true;
Color
Colorは、ターミナルの色サポートを表す列挙型です。
FTXUI ftxui::Terminal::名前空間
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)
環境変数とターミナル識別に基づいて色サポートを計算します。
const char * GetEnv(const char *name)