cpp-terminal 1.0.0
Small C++ library for writing multiplatform terminal applications
Loading...
Searching...
No Matches
terminfo.cpp
Go to the documentation of this file.
1/*
2* cpp-terminal
3* C++ library for writing multi-platform terminal applications.
4*
5* SPDX-FileCopyrightText: 2019-2024 cpp-terminal
6*
7* SPDX-License-Identifier: MIT
8*/
9
10#ifdef _WIN32
11 #pragma warning(push)
12 #pragma warning(disable : 4668)
13 #include <windows.h>
14 #pragma warning(pop)
15#endif
16
21
22#include <cstddef>
23#include <string>
24
29
31{
32 check();
33 return m_booleans[static_cast<std::size_t>(key)];
34}
35
37{
38 check();
39 return m_integers[static_cast<std::size_t>(key)];
40}
41
43{
44 check();
45 return m_strings[static_cast<std::size_t>(key)];
46}
47
48void Term::Terminfo::set(const Term::Terminfo::Bool& key, const bool& value) { m_booleans[static_cast<std::size_t>(key)] = value; }
49void Term::Terminfo::set(const Term::Terminfo::Integer& key, const std::uint32_t& value) { m_integers[static_cast<std::size_t>(key)] = value; }
50void Term::Terminfo::set(const Term::Terminfo::String& key, const std::string& value) { m_strings[static_cast<std::size_t>(key)] = value; }
51
52#if defined(_WIN32)
53bool WindowsVersionGreater(const DWORD& major, const DWORD& minor, const DWORD& patch)
54{
55 #if defined(_MSC_VER)
56 #pragma warning(push)
57 #pragma warning(disable : 4191)
58 #else
59 #pragma GCC diagnostic push
60 #pragma GCC diagnostic ignored "-Wcast-function-type"
61 #endif
62 NTSTATUS(WINAPI * getVersion)
63 (PRTL_OSVERSIONINFOW) = (reinterpret_cast<NTSTATUS(WINAPI*)(PRTL_OSVERSIONINFOW)>(GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "RtlGetVersion")));
64 #if defined(_MSC_VER)
65 #pragma warning(pop)
66 #else
67 #pragma GCC diagnostic pop
68 #endif
69 if(getVersion != nullptr)
70 {
71 RTL_OSVERSIONINFOW rovi;
72 rovi.dwOSVersionInfoSize = sizeof(rovi);
73 if(getVersion(&rovi) == 0)
74 {
75 if(rovi.dwMajorVersion > major || (rovi.dwMajorVersion == major && (rovi.dwMinorVersion > minor || (rovi.dwMinorVersion == minor && rovi.dwBuildNumber >= patch)))) return true;
76 else
77 return false;
78 }
79 }
80 return false;
81}
82#endif
83
85{
86#if defined(_WIN32)
87 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
88 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
89 #endif
90 if(!m_booleans[static_cast<std::size_t>(Terminfo::Bool::ControlSequences)]) { set(Terminfo::Bool::Legacy, true); }
91 else
92 {
93 DWORD dwOriginalOutMode{0};
94 GetConsoleMode(Private::out.handle(), &dwOriginalOutMode);
95 if(!SetConsoleMode(Private::out.handle(), dwOriginalOutMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { set(Terminfo::Bool::Legacy, true); }
96 else
97 {
98 SetConsoleMode(Private::out.handle(), dwOriginalOutMode);
99 set(Terminfo::Bool::Legacy, false);
100 }
101 }
102#else
103 set(Terminfo::Bool::Legacy, false);
104#endif
105}
106
108
110{
111 std::string name;
112 name = Private::getenv("TERM_PROGRAM").second;
113 if(name.empty()) { name = Private::getenv("TERMINAL_EMULATOR").second; }
114 if(Private::getenv("ANSICON").first) { name = "ansicon"; }
116}
117
119
121{
122 static bool checked{false};
123 if(!checked)
124 {
125 checkTermEnv();
126 checkTerminalName();
127 checkTerminalVersion();
128 checkControlSequences();
129 checkLegacy();
130 checkColorMode();
131 checkUTF8();
132 checked = true;
133 }
134}
135
137{
138 checkColorMode();
139 return m_colorMode;
140}
141
143
145{
146 std::string name{m_strings[static_cast<std::size_t>(Terminfo::String::TermName)]};
147 if(name == "Apple_Terminal") { m_colorMode = Term::Terminfo::ColorMode::Bit8; }
148 else if(name == "JetBrains-JediTerm") { m_colorMode = Term::Terminfo::ColorMode::Bit24; }
149 else if(name == "vscode") { m_colorMode = Term::Terminfo::ColorMode::Bit24; }
150 else if(name == "linux") { m_colorMode = Term::Terminfo::ColorMode::Bit4; }
151 else if(name == "ansicon") { m_colorMode = Term::Terminfo::ColorMode::Bit4; }
152 else if(m_strings[static_cast<std::size_t>(Terminfo::String::TermEnv)] == "linux") { m_colorMode = Term::Terminfo::ColorMode::Bit4; }
153#if defined(_WIN32)
154 else if(WindowsVersionGreater(10, 0, 10586) && !m_booleans[static_cast<std::size_t>(Terminfo::Bool::Legacy)]) { m_colorMode = Term::Terminfo::ColorMode::Bit24; }
155 else if(m_booleans[static_cast<std::size_t>(Terminfo::Bool::Legacy)]) { m_colorMode = Term::Terminfo::ColorMode::Bit4; }
156#endif
157 else { m_colorMode = Term::Terminfo::ColorMode::Bit24; }
158 std::string colorterm = Private::getenv("COLORTERM").second;
159 if((colorterm == "truecolor" || colorterm == "24bit") && m_colorMode != ColorMode::Unset) { m_colorMode = Term::Terminfo::ColorMode::Bit24; }
160}
161
163{
164#ifdef _WIN32
165 if(WindowsVersionGreater(10, 0, 10586)) { set(Term::Terminfo::Bool::ControlSequences, true); }
166 else { set(Term::Terminfo::Bool::ControlSequences, false); }
167#else
169#endif
170}
171
173{
174#if defined(_WIN32)
175 (GetConsoleOutputCP() == CP_UTF8 && GetConsoleCP() == CP_UTF8) ? set(Terminfo::Bool::UTF8, true) : set(Terminfo::Bool::UTF8, false);
176#else
177 Term::Cursor cursor_before{Term::cursor_position()};
178 Term::Private::out.write("\xe2\x82\xac"); // € 3bits in utf8 one character
179 std::string read{Term::Private::in.read()};
180 Term::Cursor cursor_after{Term::cursor_position()};
181 std::size_t moved{cursor_after.column() - cursor_before.column()};
182 if(moved == 1) { set(Terminfo::Bool::UTF8, true); }
183 else { set(Terminfo::Bool::UTF8, false); }
184 for(std::size_t i = 0; i != moved; ++i) { Term::Private::out.write("\b \b"); }
185#endif
186}
std::size_t column() const
Definition cursor.cpp:16
std::string read() const
Definition file.cpp:127
std::size_t write(const std::string &str) const
Definition file.cpp:101
static bool get(const Term::Terminfo::Bool &key)
Definition terminfo.cpp:30
static void checkTerminalName()
Definition terminfo.cpp:109
static void checkControlSequences()
Definition terminfo.cpp:162
static void checkLegacy()
Definition terminfo.cpp:84
static ColorMode getColorMode()
Definition terminfo.cpp:136
@ Legacy
Terminal is in legacy mode (Windows only).
@ ControlSequences
Terminal support control sequences.
@ UTF8
terminal has UTF-8 activated.
static void checkColorMode()
Definition terminfo.cpp:144
static Strings m_strings
Definition terminfo.hpp:28
static void check()
Definition terminfo.cpp:120
static void set(const Term::Terminfo::Bool &key, const bool &value)
Definition terminfo.cpp:48
static void checkTermEnv()
Definition terminfo.cpp:107
static void checkUTF8()
Definition terminfo.cpp:172
std::array< bool, BoolNumber > Booleans
Definition terminfo.hpp:65
std::array< std::uint32_t, IntegerNumber > Integers
Definition terminfo.hpp:67
static ColorMode m_colorMode
Definition terminfo.hpp:25
static Integers m_integers
Definition terminfo.hpp:27
@ TermName
Name of the terminal program if available.
@ TermVersion
Terminal version.
@ TermEnv
TERM environment variable value.
static Booleans m_booleans
Definition terminfo.hpp:26
std::array< std::string, StringNumber > Strings
Definition terminfo.hpp:66
static void checkTerminalVersion()
Definition terminfo.cpp:118
InputFileHandler & in
Definition file.cpp:43
OutputFileHandler & out
Definition file.cpp:44
std::pair< bool, std::string > getenv(const std::string &env)
Value of an environment variables.
Definition env.cpp:14
Term::Cursor cursor_position()
Definition cursor.cpp:26
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING
bool WindowsVersionGreater(const DWORD &major, const DWORD &minor, const DWORD &patch)
Definition terminfo.cpp:53