aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/cli/displaytoolbox.cpp72
-rw-r--r--src/bin/cli/displaytoolbox.h3
-rw-r--r--src/bin/cli/main.cpp34
-rw-r--r--src/bin/cli/rang.hpp503
4 files changed, 542 insertions, 70 deletions
diff --git a/src/bin/cli/displaytoolbox.cpp b/src/bin/cli/displaytoolbox.cpp
index 1709d18..ec629a8 100644
--- a/src/bin/cli/displaytoolbox.cpp
+++ b/src/bin/cli/displaytoolbox.cpp
@@ -2,6 +2,7 @@
#include <QBuffer>
#include <QJsonArray>
#include <QJsonObject>
+#include <sstream>
#ifdef PAINTER_OP
#include <QFont>
@@ -34,50 +35,25 @@ QString DisplayToolBox::makeImage(QByteArray svgCode)
}
#endif
-QString DisplayToolBox::colorToIntCode(QString str)
+rang::fg DisplayToolBox::colorToIntCode(QString str)
{
- if(str.isEmpty() || str == QStringLiteral("black"))
- {
- return QStringLiteral("0;31");
- }
- else if(str == QStringLiteral("white"))
- {
- return QStringLiteral("97");
- }
- else if(str == QStringLiteral("blue"))
- {
- return QStringLiteral("34");
- }
- else if(str == QStringLiteral("red"))
- {
- return QStringLiteral("31");
- }
- else if(str == QStringLiteral("black"))
- {
- return QStringLiteral("30");
- }
- else if(str == QStringLiteral("green"))
- {
- return QStringLiteral("32");
- }
- else if(str == QStringLiteral("yellow"))
- {
- return QStringLiteral("33");
- }
- else if(str == QStringLiteral("cyan"))
- {
- return QStringLiteral("36");
- }
- else if(str == QStringLiteral("reset"))
- {
- return QStringLiteral("0");
- }
- return {};
+ QHash<QString, rang::fg> data{
+ {"black", rang::fg::black}, {"red", rang::fg::red}, {"green", rang::fg::green},
+ {"yellow", rang::fg::yellow}, {"blue", rang::fg::blue}, {"magenta", rang::fg::magenta},
+ {"cyan", rang::fg::cyan}, {"gray", rang::fg::gray}, {"reset", rang::fg::reset}};
+
+ if(data.contains(str))
+ return data.value(str);
+
+ return rang::fg::black;
}
QString DisplayToolBox::colorToTermCode(QString str)
{
- return QStringLiteral("\e[").append(DisplayToolBox::colorToIntCode(str)).append("m");
+ rang::setControlMode(rang::control::Force);
+ std::stringstream s;
+ s << DisplayToolBox::colorToIntCode(str);
+ return QString::fromStdString(s.str());
}
QString DisplayToolBox::diceToSvg(QJsonArray array, bool withColor, bool allSameColor, bool allSameFaceCount)
@@ -91,7 +67,7 @@ QString DisplayToolBox::diceToSvg(QJsonArray array, bool withColor, bool allSame
QStringList subResult;
auto obj= item.toObject();
auto values= obj["values"].toArray();
- for(auto valRef : values)
+ for(auto valRef : std::as_const(values))
{
subResult.append(diceResultToString(valRef.toObject(), Output::Svg, withColor));
}
@@ -108,7 +84,7 @@ QString DisplayToolBox::diceToSvg(QJsonArray array, bool withColor, bool allSame
auto obj= item.toObject();
auto values= obj["values"].toArray();
- for(auto valRef : values)
+ for(auto valRef : std::as_const(values))
{
subResult.append(diceResultToString(valRef.toObject(), Output::Svg, withColor));
}
@@ -139,7 +115,7 @@ QString DisplayToolBox::diceResultToString(QJsonObject val, Output type, bool ha
auto subvalues= val["subvalues"].toArray();
QStringList subStr;
- for(auto subval : subvalues)
+ for(auto subval : std::as_const(subvalues))
{
subStr << QString::number(subval.toDouble());
}
@@ -151,17 +127,13 @@ QString DisplayToolBox::diceResultToString(QJsonObject val, Output type, bool ha
{
if(type == Output::Terminal)
{
- total= QStringLiteral("%1%2%3")
- .arg(DisplayToolBox::colorToTermCode(color))
- .arg(total)
- .arg(DisplayToolBox::colorToTermCode(QStringLiteral("reset")));
+ total= QStringLiteral("%1%2%3").arg(DisplayToolBox::colorToTermCode(color), total,
+ DisplayToolBox::colorToTermCode(QStringLiteral("reset")));
}
else if(type == Output::Svg)
{
- total= QStringLiteral("%1%2%3")
- .arg(QStringLiteral("<tspan fill=\"%1\">").arg(color))
- .arg(total)
- .arg(QStringLiteral("</tspan>"));
+ total= QStringLiteral("%1%2%3").arg(QStringLiteral("<tspan fill=\"%1\">").arg(color), total,
+ QStringLiteral("</tspan>"));
}
}
return total;
diff --git a/src/bin/cli/displaytoolbox.h b/src/bin/cli/displaytoolbox.h
index 5a22b0f..2b0b556 100644
--- a/src/bin/cli/displaytoolbox.h
+++ b/src/bin/cli/displaytoolbox.h
@@ -5,6 +5,7 @@
#include <QString>
#include "diceparser/diceparser.h"
+#include "rang.hpp"
class DisplayToolBox
{
@@ -20,7 +21,7 @@ public:
#ifdef PAINTER_OP
static QString makeImage(QByteArray svgCode);
#endif
- static QString colorToIntCode(QString str);
+ static rang::fg colorToIntCode(QString str);
static QString colorToTermCode(QString str);
static QString diceToSvg(QJsonArray array, bool withColor, bool allSameColor, bool allSameFaceCount);
static QString diceResultToString(QJsonObject val, Output type, bool hasColor);
diff --git a/src/bin/cli/main.cpp b/src/bin/cli/main.cpp
index a63f0ab..d82375f 100644
--- a/src/bin/cli/main.cpp
+++ b/src/bin/cli/main.cpp
@@ -41,10 +41,8 @@
#include "diceparser/dicealias.h"
#include "diceparser/diceparser.h"
-#include "diceparser/highlightdice.h"
#include "diceparser/parsingtoolbox.h"
#include "displaytoolbox.h"
-
/**
* @page Dice
* The cli for DiceParser the new dice system from rolisteam.
@@ -99,18 +97,18 @@ void displayMarkdown(QString json)
auto comment= obj["comment"].toString();
auto arrayInst= obj["instructions"].toArray();
QStringList diceResults;
- for(auto inst : arrayInst)
+ for(auto inst : std::as_const(arrayInst))
{
auto obj= inst.toObject();
auto diceVals= obj["diceval"].toArray();
- for(auto diceval : diceVals)
+ for(auto diceval : std::as_const(diceVals))
{
auto objval= diceval.toObject();
auto resultStr= QString::number(objval["value"].toDouble());
auto subvalues= objval["subvalues"].toArray();
QStringList subValueStr;
- for(auto sub : subvalues)
+ for(auto sub : std::as_const(subvalues))
{
subValueStr << QString::number(sub.toDouble());
}
@@ -145,7 +143,7 @@ void displayMarkdown(QString json)
}
else
{
- str.append(QObject::tr("# %1\nDetails:[%3 (%2)]\n").arg(scalarText).arg(diceList).arg(cmd));
+ str.append(QObject::tr("# %1\nDetails:[%3 (%2)]\n").arg(scalarText, diceList, cmd));
}
}
str.append(QStringLiteral("```"));
@@ -160,11 +158,11 @@ QString displaySVG(QString json, bool withColor)
auto comment= obj["warning"].toString();
auto arrayInst= obj["instructions"].toArray();
QStringList diceResults;
- for(auto inst : arrayInst)
+ for(auto inst : std::as_const(arrayInst))
{
auto obj= inst.toObject();
auto diceVals= obj["diceval"].toArray();
- for(auto diceval : diceVals)
+ for(auto diceval : std::as_const(diceVals))
{
auto objval= diceval.toObject();
auto resultStr= objval["string"].toString();
@@ -213,17 +211,13 @@ QString displaySVG(QString json, bool withColor)
str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"%4\"><tspan "
"fill=\"red\">%1</tspan>\n"
"<tspan x=\"0\" y=\"%5\">details:</tspan>[%3 (%2)]</text>")
- .arg(scalarText)
- .arg(diceList)
- .arg(cmd)
+ .arg(scalarText, diceList, cmd)
.arg(y)
.arg(y * 2));
else
str.append(QStringLiteral("<text font-size=\"16\" x=\"0\" y=\"%4\"><tspan>%1</tspan>\n"
"<tspan x=\"0\" y=\"%5\">details:</tspan>[%3 (%2)]</text>")
- .arg(scalarText)
- .arg(diceList)
- .arg(cmd)
+ .arg(scalarText, diceList, cmd)
.arg(y)
.arg(y * 2));
}
@@ -242,6 +236,7 @@ void displayImage(QString json, bool withColor)
void displayCommandResult(QString json, bool withColor, QString color)
{
+ using namespace Qt::Literals::StringLiterals;
QJsonDocument doc= QJsonDocument::fromJson(json.toUtf8());
auto obj= doc.object();
auto error= obj["error"].toString();
@@ -277,8 +272,9 @@ void displayCommandResult(QString json, bool withColor, QString color)
QString str;
if(withColor)
- str= QObject::tr("Result: \e[0;%4;1m%1\e[0m - details:[%3 (%2)]")
- .arg(scalarText, diceList, cmd, DisplayToolBox::colorToIntCode(color));
+ str= QObject::tr("Result: %4%1%5 - details:[%3 (%2)]")
+ .arg(scalarText, diceList, cmd, DisplayToolBox::colorToTermCode(color),
+ DisplayToolBox::colorToTermCode("reset"));
else
str= QObject::tr("Result: %1 - details:[%3 (%2)]").arg(scalarText, diceList, cmd);
@@ -291,7 +287,7 @@ void displayCommandResult(QString json, bool withColor, QString color)
if(!comment.isEmpty())
{
if(withColor)
- out << "\033[1m" << comment << "\033[0m\n";
+ out << DisplayToolBox::colorToTermCode("yellow") << comment << DisplayToolBox::colorToTermCode("reset");
else
out << comment << " ";
}
@@ -368,7 +364,7 @@ int startDiceParsing(QStringList& cmds, bool withColor, QString baseColor, EXPOR
style+= QStringLiteral("font-weight=\"bold\" ");
}
if(!style.isEmpty())
- result= QString("<tspan %2>%1</tspan>").arg(value).arg(style);
+ result= QString("<tspan %2>%1</tspan>").arg(value, style);
return result;
});
}
@@ -391,7 +387,7 @@ int startDiceParsing(QStringList& cmds, bool withColor, QString baseColor, EXPOR
auto front= DisplayToolBox::colorToTermCode(trueColor);
auto end= front.isEmpty() ? "" : DisplayToolBox::colorToTermCode("reset");
- return hightlight ? QString("%1%2%3").arg(front).arg(result).arg(end) : result;
+ return hightlight ? QString("%1%2%3").arg(front, result, end) : result;
});
}
else
diff --git a/src/bin/cli/rang.hpp b/src/bin/cli/rang.hpp
new file mode 100644
index 0000000..59e7b42
--- /dev/null
+++ b/src/bin/cli/rang.hpp
@@ -0,0 +1,503 @@
+#ifndef RANG_DOT_HPP
+#define RANG_DOT_HPP
+
+#if defined(__unix__) || defined(__unix) || defined(__linux__)
+#define OS_LINUX
+#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
+#define OS_WIN
+#elif defined(__APPLE__) || defined(__MACH__)
+#define OS_MAC
+#else
+#error Unknown Platform
+#endif
+
+#if defined(OS_LINUX) || defined(OS_MAC)
+#include <unistd.h>
+
+#elif defined(OS_WIN)
+
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
+#error \
+ "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA"
+#elif !defined(_WIN32_WINNT)
+#define _WIN32_WINNT _WIN32_WINNT_VISTA
+#endif
+
+#include <windows.h>
+#include <io.h>
+#include <memory>
+
+// Only defined in windows 10 onwards, redefining in lower windows since it
+// doesn't gets used in lower versions
+// https://docs.microsoft.com/en-us/windows/console/getconsolemode
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+#endif
+
+#include <algorithm>
+#include <atomic>
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+
+namespace rang {
+
+/* For better compability with most of terminals do not use any style settings
+ * except of reset, bold and reversed.
+ * Note that on Windows terminals bold style is same as fgB color.
+ */
+enum class style {
+ reset = 0,
+ bold = 1,
+ dim = 2,
+ italic = 3,
+ underline = 4,
+ blink = 5,
+ rblink = 6,
+ reversed = 7,
+ conceal = 8,
+ crossed = 9
+};
+
+enum class fg {
+ black = 30,
+ red = 31,
+ green = 32,
+ yellow = 33,
+ blue = 34,
+ magenta = 35,
+ cyan = 36,
+ gray = 37,
+ reset = 39
+};
+
+enum class bg {
+ black = 40,
+ red = 41,
+ green = 42,
+ yellow = 43,
+ blue = 44,
+ magenta = 45,
+ cyan = 46,
+ gray = 47,
+ reset = 49
+};
+
+enum class fgB {
+ black = 90,
+ red = 91,
+ green = 92,
+ yellow = 93,
+ blue = 94,
+ magenta = 95,
+ cyan = 96,
+ gray = 97
+};
+
+enum class bgB {
+ black = 100,
+ red = 101,
+ green = 102,
+ yellow = 103,
+ blue = 104,
+ magenta = 105,
+ cyan = 106,
+ gray = 107
+};
+
+enum class control { // Behaviour of rang function calls
+ Off = 0, // toggle off rang style/color calls
+ Auto = 1, // (Default) autodect terminal and colorize if needed
+ Force = 2 // force ansi color output to non terminal streams
+};
+// Use rang::setControlMode to set rang control mode
+
+enum class winTerm { // Windows Terminal Mode
+ Auto = 0, // (Default) automatically detects wheter Ansi or Native API
+ Ansi = 1, // Force use Ansi API
+ Native = 2 // Force use Native API
+};
+// Use rang::setWinTermMode to explicitly set terminal API for Windows
+// Calling rang::setWinTermMode have no effect on other OS
+
+namespace rang_implementation {
+
+ inline std::atomic<control> &controlMode() noexcept
+ {
+ static std::atomic<control> value(control::Auto);
+ return value;
+ }
+
+ inline std::atomic<winTerm> &winTermMode() noexcept
+ {
+ static std::atomic<winTerm> termMode(winTerm::Auto);
+ return termMode;
+ }
+
+ inline bool supportsColor() noexcept
+ {
+#if defined(OS_LINUX) || defined(OS_MAC)
+
+ static const bool result = [] {
+ const char *Terms[]
+ = { "ansi", "color", "console", "cygwin", "gnome",
+ "konsole", "kterm", "linux", "msys", "putty",
+ "rxvt", "screen", "vt100", "xterm" };
+
+ const char *env_p = std::getenv("TERM");
+ std::cout << "Rang: " <<env_p <<std::endl;
+ if (env_p == nullptr) {
+ return false;
+ }
+ return std::any_of(std::begin(Terms), std::end(Terms),
+ [&](const char *term) {
+ return std::strstr(env_p, term) != nullptr;
+ });
+ }();
+
+#elif defined(OS_WIN)
+ // All windows versions support colors through native console methods
+ static constexpr bool result = true;
+#endif
+ return result;
+ }
+
+#ifdef OS_WIN
+
+
+ inline bool isMsysPty(int fd) noexcept
+ {
+ // Dynamic load for binary compability with old Windows
+ const auto ptrGetFileInformationByHandleEx
+ = reinterpret_cast<decltype(&GetFileInformationByHandleEx)>(
+ GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "GetFileInformationByHandleEx"));
+ if (!ptrGetFileInformationByHandleEx) {
+ return false;
+ }
+
+ HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (h == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ // Check that it's a pipe:
+ if (GetFileType(h) != FILE_TYPE_PIPE) {
+ return false;
+ }
+
+ // POD type is binary compatible with FILE_NAME_INFO from WinBase.h
+ // It have the same alignment and used to avoid UB in caller code
+ struct MY_FILE_NAME_INFO {
+ DWORD FileNameLength;
+ WCHAR FileName[MAX_PATH];
+ };
+
+ auto pNameInfo = std::unique_ptr<MY_FILE_NAME_INFO>(
+ new (std::nothrow) MY_FILE_NAME_INFO());
+ if (!pNameInfo) {
+ return false;
+ }
+
+ // Check pipe name is template of
+ // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX
+ if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(),
+ sizeof(MY_FILE_NAME_INFO))) {
+ return false;
+ }
+ std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR));
+ if ((name.find(L"msys-") == std::wstring::npos
+ && name.find(L"cygwin-") == std::wstring::npos)
+ || name.find(L"-pty") == std::wstring::npos) {
+ return false;
+ }
+
+ return true;
+ }
+
+#endif
+
+ inline bool isTerminal(const std::streambuf *osbuf) noexcept
+ {
+ using std::cerr;
+ using std::clog;
+ using std::cout;
+#if defined(OS_LINUX) || defined(OS_MAC)
+ if (osbuf == cout.rdbuf()) {
+ static const bool cout_term = isatty(fileno(stdout)) != 0;
+ return cout_term;
+ } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
+ static const bool cerr_term = isatty(fileno(stderr)) != 0;
+ return cerr_term;
+ }
+#elif defined(OS_WIN)
+ if (osbuf == cout.rdbuf()) {
+ static const bool cout_term
+ = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout)));
+ return cout_term;
+ } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
+ static const bool cerr_term
+ = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr)));
+ return cerr_term;
+ }
+#endif
+ return false;
+ }
+
+ template <typename T>
+ using enableStd = typename std::enable_if<
+ std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value
+ || std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value
+ || std::is_same<T, rang::bgB>::value,
+ std::ostream &>::type;
+
+
+#ifdef OS_WIN
+
+ struct SGR { // Select Graphic Rendition parameters for Windows console
+ BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit
+ BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit
+ BYTE bold; // emulated as FOREGROUND_INTENSITY bit
+ BYTE underline; // emulated as BACKGROUND_INTENSITY bit
+ BOOLEAN inverse; // swap foreground/bold & background/underline
+ BOOLEAN conceal; // set foreground/bold to background/underline
+ };
+
+ enum class AttrColor : BYTE { // Color attributes for console screen buffer
+ black = 0,
+ red = 4,
+ green = 2,
+ yellow = 6,
+ blue = 1,
+ magenta = 5,
+ cyan = 3,
+ gray = 7
+ };
+
+ inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept
+ {
+ if (osbuf == std::cout.rdbuf()) {
+ static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ return hStdout;
+ } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) {
+ static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
+ return hStderr;
+ }
+ return INVALID_HANDLE_VALUE;
+ }
+
+ inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept
+ {
+ HANDLE h = getConsoleHandle(osbuf);
+ if (h == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+ DWORD dwMode = 0;
+ if (!GetConsoleMode(h, &dwMode)) {
+ return false;
+ }
+ dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ if (!SetConsoleMode(h, dwMode)) {
+ return false;
+ }
+ return true;
+ }
+
+ inline bool supportsAnsi(const std::streambuf *osbuf) noexcept
+ {
+ using std::cerr;
+ using std::clog;
+ using std::cout;
+ if (osbuf == cout.rdbuf()) {
+ static const bool cout_ansi
+ = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf));
+ return cout_ansi;
+ } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) {
+ static const bool cerr_ansi
+ = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf));
+ return cerr_ansi;
+ }
+ return false;
+ }
+
+ inline const SGR &defaultState() noexcept
+ {
+ static const SGR defaultSgr = []() -> SGR {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+ if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
+ &info)
+ || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE),
+ &info)) {
+ attrib = info.wAttributes;
+ }
+ SGR sgr = { 0, 0, 0, 0, FALSE, FALSE };
+ sgr.fgColor = attrib & 0x0F;
+ sgr.bgColor = (attrib & 0xF0) >> 4;
+ return sgr;
+ }();
+ return defaultSgr;
+ }
+
+ inline BYTE ansi2attr(BYTE rgb) noexcept
+ {
+ static const AttrColor rev[8]
+ = { AttrColor::black, AttrColor::red, AttrColor::green,
+ AttrColor::yellow, AttrColor::blue, AttrColor::magenta,
+ AttrColor::cyan, AttrColor::gray };
+ return static_cast<BYTE>(rev[rgb]);
+ }
+
+ inline void setWinSGR(rang::bg col, SGR &state) noexcept
+ {
+ if (col != rang::bg::reset) {
+ state.bgColor = ansi2attr(static_cast<BYTE>(col) - 40);
+ } else {
+ state.bgColor = defaultState().bgColor;
+ }
+ }
+
+ inline void setWinSGR(rang::fg col, SGR &state) noexcept
+ {
+ if (col != rang::fg::reset) {
+ state.fgColor = ansi2attr(static_cast<BYTE>(col) - 30);
+ } else {
+ state.fgColor = defaultState().fgColor;
+ }
+ }
+
+ inline void setWinSGR(rang::bgB col, SGR &state) noexcept
+ {
+ state.bgColor = (BACKGROUND_INTENSITY >> 4)
+ | ansi2attr(static_cast<BYTE>(col) - 100);
+ }
+
+ inline void setWinSGR(rang::fgB col, SGR &state) noexcept
+ {
+ state.fgColor
+ = FOREGROUND_INTENSITY | ansi2attr(static_cast<BYTE>(col) - 90);
+ }
+
+ inline void setWinSGR(rang::style style, SGR &state) noexcept
+ {
+ switch (style) {
+ case rang::style::reset: state = defaultState(); break;
+ case rang::style::bold: state.bold = FOREGROUND_INTENSITY; break;
+ case rang::style::underline:
+ case rang::style::blink:
+ state.underline = BACKGROUND_INTENSITY;
+ break;
+ case rang::style::reversed: state.inverse = TRUE; break;
+ case rang::style::conceal: state.conceal = TRUE; break;
+ default: break;
+ }
+ }
+
+ inline SGR &current_state() noexcept
+ {
+ static SGR state = defaultState();
+ return state;
+ }
+
+ inline WORD SGR2Attr(const SGR &state) noexcept
+ {
+ WORD attrib = 0;
+ if (state.conceal) {
+ if (state.inverse) {
+ attrib = (state.fgColor << 4) | state.fgColor;
+ if (state.bold)
+ attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
+ } else {
+ attrib = (state.bgColor << 4) | state.bgColor;
+ if (state.underline)
+ attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY;
+ }
+ } else if (state.inverse) {
+ attrib = (state.fgColor << 4) | state.bgColor;
+ if (state.bold) attrib |= BACKGROUND_INTENSITY;
+ if (state.underline) attrib |= FOREGROUND_INTENSITY;
+ } else {
+ attrib = state.fgColor | (state.bgColor << 4) | state.bold
+ | state.underline;
+ }
+ return attrib;
+ }
+
+ template <typename T>
+ inline void setWinColorAnsi(std::ostream &os, T const value)
+ {
+ os << "\033[" << static_cast<int>(value) << "m";
+ }
+
+ template <typename T>
+ inline void setWinColorNative(std::ostream &os, T const value)
+ {
+ const HANDLE h = getConsoleHandle(os.rdbuf());
+ if (h != INVALID_HANDLE_VALUE) {
+ setWinSGR(value, current_state());
+ // Out all buffered text to console with previous settings:
+ os.flush();
+ SetConsoleTextAttribute(h, SGR2Attr(current_state()));
+ }
+ }
+
+ template <typename T>
+ inline enableStd<T> setColor(std::ostream &os, T const value)
+ {
+ if (winTermMode() == winTerm::Auto) {
+ if (supportsAnsi(os.rdbuf())) {
+ setWinColorAnsi(os, value);
+ } else {
+ setWinColorNative(os, value);
+ }
+ } else if (winTermMode() == winTerm::Ansi) {
+ setWinColorAnsi(os, value);
+ } else {
+ setWinColorNative(os, value);
+ }
+ return os;
+ }
+#else
+ template <typename T>
+ inline enableStd<T> setColor(std::ostream &os, T const value)
+ {
+ return os << "\033[" << static_cast<int>(value) << "m";
+ }
+#endif
+} // namespace rang_implementation
+
+template <typename T>
+inline rang_implementation::enableStd<T> operator<<(std::ostream &os,
+ const T value)
+{
+ const control option = rang_implementation::controlMode();
+ switch (option) {
+ case control::Auto:
+ return rang_implementation::supportsColor()
+ && rang_implementation::isTerminal(os.rdbuf())
+ ? rang_implementation::setColor(os, value)
+ : os;
+ case control::Force: return rang_implementation::setColor(os, value);
+ default: return os;
+ }
+}
+
+inline void setWinTermMode(const rang::winTerm value) noexcept
+{
+ rang_implementation::winTermMode() = value;
+}
+
+inline void setControlMode(const control value) noexcept
+{
+ rang_implementation::controlMode() = value;
+}
+
+} // namespace rang
+
+#undef OS_LINUX
+#undef OS_WIN
+#undef OS_MAC
+
+#endif /* ifndef RANG_DOT_HPP */