Commit cb82ec9b by Maarten L. Hekkelman

new colouring of output, first attempt

parent e84282cb
...@@ -29,11 +29,16 @@ ...@@ -29,11 +29,16 @@
#include "cif++/exports.hpp" #include "cif++/exports.hpp"
#include <filesystem> #include <filesystem>
#include <iostream>
#ifndef STDOUT_FILENO #ifndef STDOUT_FILENO
#define STDOUT_FILENO 1 #define STDOUT_FILENO 1
#endif #endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#if _WIN32 #if _WIN32
#include <io.h> #include <io.h>
#define isatty _isatty #define isatty _isatty
...@@ -49,44 +54,126 @@ ...@@ -49,44 +54,126 @@
#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1 #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1
#endif #endif
/// \file utilities.hpp /** \file utilities.hpp
/// This file contains code that is very generic in nature like a progress_bar *
* This file contains code that is very generic in nature like a progress_bar
*/
/// The cif namespace
namespace cif namespace cif
{ {
extern CIFPP_EXPORT int VERBOSE; extern CIFPP_EXPORT int VERBOSE;
// the git 'build' number /// return the git 'build' number
std::string get_version_nr(); std::string get_version_nr();
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Code helping with terminal i/o
/// Return the width of the current output terminal, or the default 80 in case output is not to a terminal
uint32_t get_terminal_width(); uint32_t get_terminal_width();
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Path of the current executable
/// Return the path of the current executable
std::string get_executable_path(); std::string get_executable_path();
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// some manipulators to write coloured text to terminals // some manipulators to write coloured text to terminals
enum StringColour /// @brief The defined string colours
{ enum class StringColour
scBLACK = 0, {
scRED, BLACK = 0,
scGREEN, RED,
scYELLOW, GREEN,
scBLUE, YELLOW,
scMAGENTA, BLUE,
scCYAN, MAGENTA,
scWHITE, CYAN,
scNONE = 9 WHITE,
NONE = 9
};
template<StringColour C>
struct ColourDefinition
{
static constexpr StringColour value = C;
};
enum class TextStyle
{
REGULAR = 22,
BOLD = 1
};
template<TextStyle S>
struct StyleDefinition
{
static constexpr TextStyle value = S;
};
template<typename ForeColour, typename BackColour, typename Style>
struct ColourAndStyle
{
static constexpr StringColour fore_colour = ForeColour::value;
static constexpr StringColour back_colour = BackColour::value;
static constexpr TextStyle text_style = Style::value;
static constexpr int fore_colour_number = static_cast<int>(fore_colour) + 30;
static constexpr int back_colour_number = static_cast<int>(back_colour) + 40;
static constexpr int style_number = static_cast<int>(text_style);
friend std::ostream &operator<<(std::ostream &os, ColourAndStyle clr)
{
bool use_colour = false;
if (os.rdbuf() == std::cout.rdbuf() and isatty(STDOUT_FILENO))
use_colour = true;
else if (os.rdbuf() == std::cerr.rdbuf() and isatty(STDERR_FILENO))
use_colour = true;
if (use_colour)
{
if (fore_colour == StringColour::NONE and back_colour == StringColour::NONE)
os << "\033[0m";
else
os << "\033[" << fore_colour_number << ';' << style_number << ';' << back_colour_number << 'm';
}
return os;
}
}; };
template<typename ForeColour, typename BackColour>
constexpr auto coloured(const ForeColour fore, const BackColour back)
{
return ColourAndStyle<ForeColour, BackColour, StyleDefinition<TextStyle::REGULAR>>{};
}
template<typename ForeColour, typename BackColour, typename Style>
constexpr auto coloured(const ForeColour fore, const BackColour back, Style style)
{
return ColourAndStyle<ForeColour, BackColour, Style>{};
}
namespace colour
{
constexpr ColourDefinition<StringColour::BLACK> black = ColourDefinition<StringColour::BLACK>();
constexpr ColourDefinition<StringColour::RED> red = ColourDefinition<StringColour::RED>();
constexpr ColourDefinition<StringColour::GREEN> green = ColourDefinition<StringColour::GREEN>();
constexpr ColourDefinition<StringColour::YELLOW> yellow = ColourDefinition<StringColour::YELLOW>();
constexpr ColourDefinition<StringColour::BLUE> blue = ColourDefinition<StringColour::BLUE>();
constexpr ColourDefinition<StringColour::MAGENTA> magenta = ColourDefinition<StringColour::MAGENTA>();
constexpr ColourDefinition<StringColour::CYAN> cyan = ColourDefinition<StringColour::CYAN>();
constexpr ColourDefinition<StringColour::WHITE> white = ColourDefinition<StringColour::WHITE>();
constexpr ColourDefinition<StringColour::NONE> none = ColourDefinition<StringColour::NONE>();
constexpr StyleDefinition<TextStyle::REGULAR> regular = StyleDefinition<TextStyle::REGULAR>();
constexpr StyleDefinition<TextStyle::BOLD> bold = StyleDefinition<TextStyle::BOLD>();
constexpr auto reset = cif::coloured(none, none, regular);
}
template <typename String, typename CharT> template <typename String, typename CharT>
struct ColouredString struct ColouredString
{ {
...@@ -94,8 +181,8 @@ struct ColouredString ...@@ -94,8 +181,8 @@ struct ColouredString
ColouredString(String s, StringColour fore, StringColour back, bool bold = true) ColouredString(String s, StringColour fore, StringColour back, bool bold = true)
: m_s(s) : m_s(s)
, m_fore(fore) , m_fore(30 + static_cast<int>(fore))
, m_back(back) , m_back(40 + static_cast<int>(back))
, m_bold(bold) , m_bold(bold)
{ {
} }
...@@ -103,7 +190,7 @@ struct ColouredString ...@@ -103,7 +190,7 @@ struct ColouredString
ColouredString &operator=(const ColouredString &) = delete; ColouredString &operator=(const ColouredString &) = delete;
String m_s; String m_s;
StringColour m_fore, m_back; int m_fore, m_back;
bool m_bold; bool m_bold;
}; };
...@@ -113,7 +200,7 @@ std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> ...@@ -113,7 +200,7 @@ std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits>
if (isatty(STDOUT_FILENO)) if (isatty(STDOUT_FILENO))
{ {
std::basic_ostringstream<CharT, Traits> ostr; std::basic_ostringstream<CharT, Traits> ostr;
ostr << "\033[" << (30 + s.m_fore) << ';' << (s.m_bold ? "1" : "22") << ';' << (40 + s.m_back) << 'm' ostr << "\033[" << s.m_fore << ';' << (s.m_bold ? "1" : "22") << ';' << s.m_back << 'm'
<< s.m_s << s.m_s
<< "\033[0m"; << "\033[0m";
...@@ -129,7 +216,7 @@ std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> ...@@ -129,7 +216,7 @@ std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits>
if (isatty(STDOUT_FILENO)) if (isatty(STDOUT_FILENO))
{ {
std::basic_ostringstream<CharT, Traits> ostr; std::basic_ostringstream<CharT, Traits> ostr;
ostr << "\033[" << (30 + s.m_fore) << ';' << (s.m_bold ? "1" : "22") << ';' << (40 + s.m_back) << 'm' ostr << "\033[" << s.m_fore << ';' << (s.m_bold ? "1" : "22") << ';' << s.m_back << 'm'
<< s.m_s << s.m_s
<< "\033[0m"; << "\033[0m";
...@@ -140,19 +227,19 @@ std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> ...@@ -140,19 +227,19 @@ std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits>
} }
template <typename CharT> template <typename CharT>
inline auto coloured(const CharT *s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true) inline auto coloured(const CharT *s, StringColour fore = StringColour::WHITE, StringColour back = StringColour::RED, bool bold = true)
{ {
return ColouredString<const CharT *, CharT>(s, fore, back, bold); return ColouredString<const CharT *, CharT>(s, fore, back, bold);
} }
template <typename CharT, typename Traits, typename Alloc> template <typename CharT, typename Traits, typename Alloc>
inline auto coloured(const std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true) inline auto coloured(const std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = StringColour::WHITE, StringColour back = StringColour::RED, bool bold = true)
{ {
return ColouredString<const std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold); return ColouredString<const std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold);
} }
template <typename CharT, typename Traits, typename Alloc> template <typename CharT, typename Traits, typename Alloc>
inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = scWHITE, StringColour back = scRED, bool bold = true) inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fore = StringColour::WHITE, StringColour back = StringColour::RED, bool bold = true)
{ {
return ColouredString<std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold); return ColouredString<std::basic_string<CharT, Traits, Alloc>, CharT>(s, fore, back, bold);
} }
......
...@@ -1056,7 +1056,7 @@ bool Remark3Parser::match(const char *expr, int nextState) ...@@ -1056,7 +1056,7 @@ bool Remark3Parser::match(const char *expr, int nextState)
if (result) if (result)
mState = nextState; mState = nextState;
else if (cif::VERBOSE >= 3) else if (cif::VERBOSE >= 3)
std::cerr << cif::coloured("No match:", cif::scWHITE, cif::scRED) << " '" << expr << '\'' << std::endl; std::cerr << cif::coloured("No match:", cif::StringColour::WHITE, cif::StringColour::RED) << " '" << expr << '\'' << std::endl;
return result; return result;
} }
...@@ -1116,7 +1116,7 @@ float Remark3Parser::parse() ...@@ -1116,7 +1116,7 @@ float Remark3Parser::parse()
} }
if (cif::VERBOSE >= 2) if (cif::VERBOSE >= 2)
std::cerr << cif::coloured("Dropping line:", cif::scWHITE, cif::scRED) << " '" << mLine << '\'' << std::endl; std::cerr << cif::coloured("Dropping line:", cif::StringColour::WHITE, cif::StringColour::RED) << " '" << mLine << '\'' << std::endl;
++dropped; ++dropped;
} }
......
...@@ -82,4 +82,19 @@ BOOST_AUTO_TEST_CASE(fmt_1) ...@@ -82,4 +82,19 @@ BOOST_AUTO_TEST_CASE(fmt_1)
BOOST_CHECK_EQUAL(cif::format("Hello, %-10.10s, the magic number is %d and pi is %g", world, 42, cif::kPI).str(), BOOST_CHECK_EQUAL(cif::format("Hello, %-10.10s, the magic number is %d and pi is %g", world, 42, cif::kPI).str(),
"Hello, world , the magic number is 42 and pi is 3.14159"); "Hello, world , the magic number is 42 and pi is 3.14159");
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(clr_1)
{
using namespace cif::colour;
std::cout << "Hello, " << cif::coloured(white, red, regular) << "world!" << reset << std::endl
<< "Hello, " << cif::coloured(white, red, bold) << "world!" << reset << std::endl
<< "Hello, " << cif::coloured(black, red) << "world!" << reset << std::endl
<< "Hello, " << cif::coloured(white, green) << "world!" << reset << std::endl
<< "Hello, " << cif::coloured(white, blue) << "world!" << reset << std::endl
<< "Hello, " << cif::coloured(blue, white) << "world!" << reset << std::endl
<< "Hello, " << cif::coloured(red, white, bold) << "world!" << reset << std::endl;
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment