Config file and package tracking utility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

176 lines
4.1 KiB

/*
* 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