Browse Source

Util: Split formatting print into print and colored print

master
Riyyi 2 years ago
parent
commit
c90369181f
  1. 176
      src/util/format/color.cpp
  2. 156
      src/util/format/color.h
  3. 107
      src/util/format/print.cpp
  4. 111
      src/util/format/print.h

176
src/util/format/color.cpp

@ -0,0 +1,176 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cstdint> // uint8_t
#include <cstdio> // FILE, fputs, stdout
#include <sstream> // stringstream
#include <string>
#include <string_view>
#include "util/format/color.h"
#include "util/format/format.h"
#include "util/meta/assert.h"
namespace Util::Format {
TextStyle::TextStyle(Emphasis emphasis)
: m_emphasis(emphasis)
{
}
TextStyle::TextStyle(bool isForeground, TerminalColor color)
{
if (isForeground) {
m_foregroundColor = color;
}
else {
m_backgroundColor = color;
}
}
// -----------------------------------------
TextStyle& TextStyle::operator|=(const TextStyle& rhs)
{
if (m_foregroundColor == TerminalColor::None) {
m_foregroundColor = rhs.m_foregroundColor;
}
else {
VERIFY(rhs.m_foregroundColor == TerminalColor::None, "can't OR a terminal color");
}
if (m_backgroundColor == TerminalColor::None) {
m_backgroundColor = rhs.m_backgroundColor;
}
else {
VERIFY(rhs.m_backgroundColor == TerminalColor::None, "can't OR a terminal color");
}
m_emphasis = static_cast<Emphasis>(static_cast<uint8_t>(m_emphasis) | static_cast<uint8_t>(rhs.m_emphasis));
return *this;
}
TextStyle fg(TerminalColor foreground)
{
return TextStyle(true, foreground);
}
TextStyle bg(TerminalColor background)
{
return TextStyle(false, background);
}
TextStyle operator|(TextStyle lhs, const TextStyle& rhs)
{
return lhs |= rhs;
}
TextStyle operator|(Emphasis lhs, Emphasis rhs)
{
return TextStyle { lhs } | rhs;
}
bool operator&(Emphasis lhs, Emphasis rhs)
{
return static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs);
}
// -----------------------------------------
void setDisplayAttributes(std::stringstream& stream, const TextStyle& style)
{
bool hasForeground = style.foregroundColor() != TerminalColor::None;
bool hasBackground = style.backgroundColor() != TerminalColor::None;
bool hasEmphasis = style.emphasis() != Emphasis::None;
if (!hasForeground && !hasBackground && !hasEmphasis) {
return;
}
stream.write("\033[", 2);
if (hasForeground) {
stream << format("{}", static_cast<uint8_t>(style.foregroundColor()));
}
if (hasBackground) {
if (hasForeground) {
stream.write(";", 1);
}
stream << format("{}", static_cast<uint8_t>(style.backgroundColor()) + 10);
}
stream.write("m", 1);
if (hasEmphasis) {
#define ESCAPE_ATTRIBUTE(escape, attribute) \
if (style.emphasis() & escape) { \
stream.write("\033[", 2); \
stream.write(attribute, 1); \
stream.write("m", 1); \
}
ESCAPE_ATTRIBUTE(Emphasis::Bold, "1");
ESCAPE_ATTRIBUTE(Emphasis::Faint, "2");
ESCAPE_ATTRIBUTE(Emphasis::Italic, "3");
ESCAPE_ATTRIBUTE(Emphasis::Underline, "4");
ESCAPE_ATTRIBUTE(Emphasis::Blink, "5");
ESCAPE_ATTRIBUTE(Emphasis::Reverse, "7");
ESCAPE_ATTRIBUTE(Emphasis::Conceal, "8");
ESCAPE_ATTRIBUTE(Emphasis::Strikethrough, "9");
}
}
void coloredVariadicFormat(std::stringstream& stream, const TextStyle& style, std::string_view format, TypeErasedParameters& parameters)
{
setDisplayAttributes(stream, style);
variadicFormat(stream, format, parameters);
stream.write("\033[0m", 4);
}
// -----------------------------------------
void coloredVariadicPrint(FILE* file, const TextStyle& style, std::string_view format, TypeErasedParameters& parameters)
{
std::stringstream stream;
setDisplayAttributes(stream, style);
variadicFormat(stream, format, parameters);
stream.write("\033[0m", 4);
std::string string = stream.str();
fputs(string.c_str(), file);
}
// -----------------------------------------
ColorPrintOperatorStyle::ColorPrintOperatorStyle(FILE* file, const TextStyle& style)
: m_file(file)
, m_style(style)
, m_stream()
, m_builder(m_stream)
{
setDisplayAttributes(m_stream, style);
}
ColorPrintOperatorStyle::~ColorPrintOperatorStyle()
{
m_stream.write("\033[0m", 4);
std::string string = m_stream.str();
fputs(string.c_str(), m_file);
}
ColorPrintOperatorStyle print(const TextStyle& style)
{
return ColorPrintOperatorStyle(stdout, style);
}
ColorPrintOperatorStyle print(FILE* file, const TextStyle& style)
{
return ColorPrintOperatorStyle(file, style);
}
} // namespace Util::Format

156
src/util/format/color.h

@ -0,0 +1,156 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <cstddef> // size_t
#include <cstdint> // uint8_t
#include <cstdio> // FILE, stdout
#include <sstream> // stringstream
#include <string_view>
#include "util/format/format.h"
namespace Util::Format {
enum class TerminalColor : uint8_t {
None = 0,
Black = 30,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
BrightBlack = 90,
BrightRed,
BrightGreen,
BrightYellow,
BrightBlue,
BrightMagenta,
BrightCyan,
BrightWhite
};
// Bit field
enum class Emphasis : uint8_t {
None = 0, // Attribute 0
Bold = 1, // Attribute 1
Faint = 1 << 1, // Attribute 2
Italic = 1 << 2, // Attribute 3
Underline = 1 << 3, // Attribute 4
Blink = 1 << 4, // Attribute 5
Reverse = 1 << 5, // Attribute 7
Conceal = 1 << 6, // Attribute 8
Strikethrough = 1 << 7, // Attribute 9
};
class TextStyle {
private:
friend TextStyle fg(TerminalColor foreground);
friend TextStyle bg(TerminalColor background);
public:
TextStyle(Emphasis emphasis);
// Operator pipe equal, reads the same way as +=
TextStyle& operator|=(const TextStyle& rhs);
TerminalColor foregroundColor() const { return m_foregroundColor; }
TerminalColor backgroundColor() const { return m_backgroundColor; }
Emphasis emphasis() const { return m_emphasis; }
private:
TextStyle(bool isForeground, TerminalColor color);
TerminalColor m_foregroundColor { TerminalColor::None };
TerminalColor m_backgroundColor { TerminalColor::None };
Emphasis m_emphasis { 0 };
};
TextStyle fg(TerminalColor foreground);
TextStyle bg(TerminalColor background);
TextStyle operator|(TextStyle lhs, const TextStyle& rhs);
TextStyle operator|(Emphasis lhs, Emphasis rhs);
bool operator&(Emphasis lhs, Emphasis rhs);
// -----------------------------------------
void coloredVariadicFormat(std::stringstream& stream, const TextStyle& style, std::string_view format, TypeErasedParameters& parameters);
template<typename... Parameters>
std::string format(const TextStyle& style, std::string_view format, const Parameters&... parameters)
{
std::stringstream stream;
VariadicParameters variadicParameters { parameters... };
coloredVariadicFormat(stream, style, format, variadicParameters);
return stream.str();
}
template<typename... Parameters>
void formatTo(std::string& output, const TextStyle& style, std::string_view format, const Parameters&... parameters)
{
std::stringstream stream;
VariadicParameters variadicParameters { parameters... };
coloredVariadicFormat(stream, style, format, variadicParameters);
output += stream.str();
}
// -----------------------------------------
void coloredVariadicPrint(FILE* file, const TextStyle& style, std::string_view format, TypeErasedParameters& parameters);
template<size_t N, typename... Parameters>
void print(const TextStyle& style, const char (&format)[N], const Parameters&... parameters)
{
VariadicParameters variadicParameters { parameters... };
coloredVariadicPrint(stdout, style, { format, N - 1 }, variadicParameters);
}
template<size_t N, typename... Parameters>
void print(FILE* file, const TextStyle& style, const char (&format)[N], const Parameters&... parameters)
{
VariadicParameters variadicParameters { parameters... };
coloredVariadicPrint(file, style, { format, N - 1 }, variadicParameters);
}
// -----------------------------------------
class ColorPrintOperatorStyle {
public:
ColorPrintOperatorStyle(FILE* file, const TextStyle& style);
virtual ~ColorPrintOperatorStyle();
Builder& builder() { return m_builder; }
private:
FILE* m_file;
TextStyle m_style;
std::stringstream m_stream;
Builder m_builder;
};
template<typename T>
const ColorPrintOperatorStyle& operator<<(const ColorPrintOperatorStyle& colorPrintOperatorStyle, const T& value)
{
_format(const_cast<ColorPrintOperatorStyle&>(colorPrintOperatorStyle).builder(), value);
return colorPrintOperatorStyle;
}
ColorPrintOperatorStyle print(const TextStyle& style);
ColorPrintOperatorStyle print(FILE* file, const TextStyle& style);
} // namespace Util::Format
namespace Util {
using Util::Format::format;
using Util::Format::formatTo;
using Util::Format::print;
} // namespace Util

107
src/util/format/print.cpp

@ -4,7 +4,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstdio> // FILE, fputs #include <cstdio> // FILE, fputs, stdout, stderr
#include <iomanip> // setprecision #include <iomanip> // setprecision
#include <ios> // defaultfloat, fixed #include <ios> // defaultfloat, fixed
#include <sstream> // stringstream #include <sstream> // stringstream
@ -15,47 +15,9 @@
namespace Util::Format { namespace Util::Format {
void printTimeElapsedAndTypePrefix(std::stringstream& stream, Type type, bool bold) void variadicPrint(FILE* file, std::string_view format, TypeErasedParameters& parameters)
{
stream << std::fixed << std::setprecision(3)
<< s_timer.elapsedNanoseconds() / 1000000000.0 << "s "
<< std::defaultfloat << std::setprecision(6);
stream << "[\033[";
if (bold) {
stream << "1";
}
switch (type) {
case Type::None:
stream << ";35mdebug";
break;
case Type::Info:
stream << ";34minfo";
break;
case Type::Warn:
stream << ";33mwarn";
break;
case Type::Critical:
stream << ";31mcritical";
break;
case Type::Success:
stream << ";32msuccess";
break;
case Type::Comment:
stream << "mcomment";
break;
default:
break;
};
stream << "\033[0m] ";
}
void prettyVariadicFormat(FILE* file, Type type, bool bold, std::string_view format, TypeErasedParameters& parameters)
{ {
std::stringstream stream; std::stringstream stream;
printTimeElapsedAndTypePrefix(stream, type, bold);
variadicFormat(stream, format, parameters); variadicFormat(stream, format, parameters);
std::string string = stream.str(); std::string string = stream.str();
@ -64,80 +26,27 @@ void prettyVariadicFormat(FILE* file, Type type, bool bold, std::string_view for
// ----------------------------------------- // -----------------------------------------
FormatPrint::FormatPrint(FILE* file, Type type, bool bold) PrintOperatorStyle::PrintOperatorStyle(FILE* file)
: m_file(file) : m_file(file)
, m_type(type)
, m_bold(bold)
, m_stream() , m_stream()
, m_builder(m_stream) , m_builder(m_stream)
{ {
printTimeElapsedAndTypePrefix(m_stream, type, bold);
} }
FormatPrint::~FormatPrint() PrintOperatorStyle::~PrintOperatorStyle()
{ {
std::string string = m_stream.str(); std::string string = m_stream.str();
fputs(string.c_str(), m_file); fputs(string.c_str(), m_file);
} }
FormatPrint dbg() PrintOperatorStyle print()
{
return FormatPrint(stdout, Type::None, false);
}
FormatPrint dbgb()
{
return FormatPrint(stdout, Type::None, true);
}
FormatPrint info()
{
return FormatPrint(stdout, Type::Info, false);
}
FormatPrint infob()
{
return FormatPrint(stdout, Type::Info, true);
}
FormatPrint warn()
{
return FormatPrint(stdout, Type::Warn, false);
}
FormatPrint warnb()
{
return FormatPrint(stdout, Type::Warn, true);
}
FormatPrint critical()
{
return FormatPrint(stderr, Type::Critical, false);
}
FormatPrint criticalb()
{
return FormatPrint(stderr, Type::Critical, true);
}
FormatPrint success()
{
return FormatPrint(stdout, Type::Success, false);
}
FormatPrint successb()
{
return FormatPrint(stdout, Type::Success, true);
}
FormatPrint comment()
{ {
return FormatPrint(stdout, Type::Comment, false); return PrintOperatorStyle(stdout);
} }
FormatPrint commentb() PrintOperatorStyle print(FILE* file)
{ {
return FormatPrint(stdout, Type::Comment, true); return PrintOperatorStyle(file);
} }
} // namespace Util::Format } // namespace Util::Format

111
src/util/format/print.h

@ -4,90 +4,59 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include <cstdio> // FILE #pragma once
#include <cstdint> // uint8_t
#include <cstdio> // FILE, stdout
#include <sstream> // stringstream
#include <string_view>
#include "util/format/format.h" #include "util/format/format.h"
#include "util/timer.h" #include "util/timer.h"
namespace Util::Format { namespace Util::Format {
static Util::Timer s_timer; void variadicPrint(FILE* file, std::string_view format, TypeErasedParameters& parameters);
enum class Type { template<size_t N, typename... Parameters>
None, // Foreground void print(const char (&format)[N], const Parameters&... parameters)
Info, // Blue {
Warn, // Yellow VariadicParameters variadicParameters { parameters... };
Critical, // Red variadicPrint(stdout, { format, N - 1 }, variadicParameters);
Success, // Green }
Comment, // White
};
void prettyVariadicFormat(FILE* file, Type type, bool bold, std::string_view format, TypeErasedParameters& parameters); template<size_t N, typename... Parameters>
void print(FILE* file, const char (&format)[N], const Parameters&... parameters)
#define FORMAT_FUNCTION(name, type, bold) \ {
template<size_t N, typename... Parameters> \ VariadicParameters variadicParameters { parameters... };
void name(const char(&format)[N], const Parameters&... parameters) \ variadicPrint(file, { format, N - 1 }, variadicParameters);
{ \ }
VariadicParameters variadicParameters { parameters... }; \
prettyVariadicFormat(stdout, Type::type, bold, { format, N - 1 }, variadicParameters); \
} \
template<size_t N, typename... Parameters> \
void name(FILE* file, const char(&format)[N], const Parameters&... parameters) \
{ \
VariadicParameters variadicParameters { parameters... }; \
prettyVariadicFormat(file, Type::type, bold, { format, N - 1 }, variadicParameters); \
}
FORMAT_FUNCTION(dbgln, None, false);
FORMAT_FUNCTION(dbgbln, None, true);
FORMAT_FUNCTION(infoln, Info, false);
FORMAT_FUNCTION(infobln, Info, true);
FORMAT_FUNCTION(warnln, Warn, false);
FORMAT_FUNCTION(warnbln, Warn, true);
FORMAT_FUNCTION(criticalln, Critical, false);
FORMAT_FUNCTION(criticalbln, Critical, true);
FORMAT_FUNCTION(successln, Success, false);
FORMAT_FUNCTION(successbln, Success, true);
FORMAT_FUNCTION(commentln, Comment, false);
FORMAT_FUNCTION(commentbln, Comment, true);
// ----------------------------------------- // -----------------------------------------
class FormatPrint { class PrintOperatorStyle {
public: public:
FormatPrint(FILE* file, Type type, bool bold); PrintOperatorStyle(FILE* file);
virtual ~FormatPrint(); virtual ~PrintOperatorStyle();
Builder& builder() { return m_builder; } Builder& builder() { return m_builder; }
private: private:
FILE* m_file; FILE* m_file;
Type m_type;
bool m_bold;
std::stringstream m_stream; std::stringstream m_stream;
Builder m_builder; Builder m_builder;
}; };
template<typename T> template<typename T>
const FormatPrint& operator<<(const FormatPrint& formatPrint, const T& value) const PrintOperatorStyle& operator<<(const PrintOperatorStyle& printOperatorStyle, const T& value)
{ {
_format(const_cast<FormatPrint&>(formatPrint).builder(), value); _format(const_cast<PrintOperatorStyle&>(printOperatorStyle).builder(), value);
return formatPrint; return printOperatorStyle;
} }
FormatPrint dbg(); PrintOperatorStyle print();
FormatPrint dbgb(); PrintOperatorStyle print(FILE* file);
FormatPrint info();
FormatPrint infob();
FormatPrint warn();
FormatPrint warnb();
FormatPrint critical();
FormatPrint criticalb();
FormatPrint success();
FormatPrint successb();
FormatPrint comment();
FormatPrint commentb();
// ----------------------------------------- // -----------------------------------------
@ -95,30 +64,6 @@ FormatPrint commentb();
namespace Util { namespace Util {
using Util::Format::commentbln; using Util::Format::print;
using Util::Format::commentln;
using Util::Format::criticalbln;
using Util::Format::criticalln;
using Util::Format::dbgbln;
using Util::Format::dbgln;
using Util::Format::infobln;
using Util::Format::infoln;
using Util::Format::successbln;
using Util::Format::successln;
using Util::Format::warnbln;
using Util::Format::warnln;
using Util::Format::comment;
using Util::Format::commentb;
using Util::Format::critical;
using Util::Format::criticalb;
using Util::Format::dbg;
using Util::Format::dbgb;
using Util::Format::info;
using Util::Format::infob;
using Util::Format::success;
using Util::Format::successb;
using Util::Format::warn;
using Util::Format::warnb;
} // namespace Util } // namespace Util

Loading…
Cancel
Save