-
Notifications
You must be signed in to change notification settings - Fork 1
/
Terminal.cpp
97 lines (87 loc) · 3.08 KB
/
Terminal.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "Forward.h"
#include "Terminal.h"
bool Terminal::disableFormatting = false;
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#include <WinCon.h>
enum class WindowsColor : WORD {
Red = FOREGROUND_RED,
Green = FOREGROUND_GREEN,
Blue = FOREGROUND_BLUE,
Yellow = FOREGROUND_RED | FOREGROUND_GREEN,
Magneta = FOREGROUND_RED | FOREGROUND_BLUE,
Cyan = FOREGROUND_GREEN | FOREGROUND_BLUE,
White = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
};
//This may look kinda obfuscated
//and that's because it is - Microsoft has made this purposefully complicated for the sake of
//making it harder to have compatibility between seven and ten.
static bool IsWindows10() {
const auto getSysOpType = []()
{
NTSTATUS(WINAPI * RtlGetVersion)(LPOSVERSIONINFOEXW);
OSVERSIONINFOEXW osInfo;
auto ntdll = GetModuleHandleA("ntdll");
if (ntdll == NULL)
return 0.0;
*(FARPROC*)&RtlGetVersion = GetProcAddress(ntdll, "RtlGetVersion");
if (RtlGetVersion == NULL)
return 0.0;
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
RtlGetVersion(&osInfo);
return (double)osInfo.dwMajorVersion;
};
if(getSysOpType() < 10.0)
return false;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleMode(hConsole,ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
return true;
}
#endif
#ifdef _WIN32
static bool CanUseANSIColors = IsWindows10();
#else // All Unix OSes a user could reasonably use, supports ANSI colours in its terminal, so
constexpr bool CanUseANSIColors = true;
#endif
void Terminal::SetColor(std::ostream& stream, Color color) {
if(disableFormatting)
return;
if (CanUseANSIColors) {
stream << "\x1b[" + std::to_string(static_cast<int>(color)) + 'm';
return;
}
//Here lies an insane Windows 7 fallback for this
#ifdef _WIN32
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // FIXME: Try to use the error handle when stream is std::cerr.
if (!hConsole)
return;
if (color == Color::RESET || color == Color::DarkGrey) {
SetConsoleTextAttribute(hConsole, 7);
return;
}
static HashTable<Color, WindowsColor> colorMap = {
{Color::Red, WindowsColor::Red},
{Color::Green, WindowsColor::Green},
{Color::Yellow, WindowsColor::Yellow},
{Color::Blue, WindowsColor::Blue},
{Color::Magneta, WindowsColor::Magneta},
{Color::Cyan, WindowsColor::Cyan},
{Color::White, WindowsColor::White},
};
if (!colorMap.contains(color))
return;
SetConsoleTextAttribute(hConsole, static_cast<WORD>(colorMap.at(color)) | FOREGROUND_INTENSITY);
#endif
}
void Terminal::SetBold(std::ostream& stream, bool isBold) {
if(!CanUseANSIColors)
return; // FIXME: Do bolding in Windows 7 emissions!
if(disableFormatting)
return;
stream << std::string("\x1b[") + (isBold ? "1" : "0") + "m";
}
void Terminal::ClearFormatting(std::ostream& stream) {
SetColor(stream, Color::RESET);
SetBold(stream, false);
}