Started implementing improved output utilities.

This commit is contained in:
Patrick Lühne 2016-11-24 00:21:01 +01:00
parent 5019922488
commit e6a9ee1cc7
Signed by: patrick
GPG Key ID: 05F3611E97A70ABF
7 changed files with 793 additions and 0 deletions

View File

@ -0,0 +1,32 @@
#ifndef __ANTHEM__OUTPUT__LOCATION_H
#define __ANTHEM__OUTPUT__LOCATION_H
namespace anthem
{
namespace input
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Location
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Location
{
const char *sectionStart = nullptr;
const char *sectionEnd = nullptr;
int rowStart = -1;
int rowEnd = -1;
int columnStart = -1;
int columnEnd = -1;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -0,0 +1,294 @@
#ifndef __ANTHEM__OUTPUT__COLOR_STREAM_H
#define __ANTHEM__OUTPUT__COLOR_STREAM_H
#include <iostream>
#include <unistd.h>
namespace anthem
{
namespace output
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ColorStream
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class ColorStream
{
public:
enum class ColorPolicy
{
Never,
Auto,
Always
};
private:
using CharacterType = std::ostream::char_type;
using TraitsType = std::ostream::traits_type;
public:
ColorStream(std::ostream &stream)
: m_stream{stream},
m_colorPolicy{ColorPolicy::Auto}
{
}
void setColorPolicy(ColorPolicy colorPolicy)
{
m_colorPolicy = colorPolicy;
}
bool supportsColor() const
{
if (m_colorPolicy == ColorPolicy::Never)
return false;
if (m_colorPolicy == ColorPolicy::Always)
return true;
if (&m_stream == &std::cout)
return isatty(fileno(stdin));
if (&m_stream == &std::cerr)
return isatty(fileno(stderr));
return false;
}
std::ostream &stream()
{
return m_stream;
}
inline ColorStream &operator<<(short value);
inline ColorStream &operator<<(unsigned short value);
inline ColorStream &operator<<(int value);
inline ColorStream &operator<<(unsigned int value);
inline ColorStream &operator<<(long value);
inline ColorStream &operator<<(unsigned long value);
inline ColorStream &operator<<(long long value);
inline ColorStream &operator<<(unsigned long long value);
inline ColorStream &operator<<(float value);
inline ColorStream &operator<<(double value);
inline ColorStream &operator<<(long double value);
inline ColorStream &operator<<(bool value);
inline ColorStream &operator<<(const void *value);
inline ColorStream &operator<<(const char *value);
inline ColorStream &operator<<(const signed char *value);
inline ColorStream &operator<<(const unsigned char *value);
inline ColorStream &operator<<(std::basic_streambuf<CharacterType, TraitsType> *sb);
inline ColorStream &operator<<(std::ios_base &(*func)(std::ios_base &));
inline ColorStream &operator<<(std::basic_ios<CharacterType, TraitsType> &(*func)(std::basic_ios<CharacterType, TraitsType> &));
inline ColorStream &operator<<(std::basic_ostream<CharacterType, TraitsType> &(*func)(std::basic_ostream<CharacterType, TraitsType> &));
inline ColorStream &operator<<(char value);
inline ColorStream &operator<<(signed char value);
inline ColorStream &operator<<(unsigned char value);
private:
std::ostream &m_stream;
ColorPolicy m_colorPolicy;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(short value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned short value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(int value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned int value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(long long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned long long value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(float value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(double value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(long double value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(bool value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const void *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const char *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const signed char *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(const unsigned char *value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::basic_streambuf<CharacterType, TraitsType>* sb)
{
m_stream << sb;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::ios_base &(*func)(std::ios_base &))
{
m_stream << func;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::basic_ios<CharacterType, TraitsType> &(*func)(std::basic_ios<CharacterType, TraitsType> &))
{
m_stream << func;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(std::basic_ostream<CharacterType, TraitsType> &(*func)(std::basic_ostream<CharacterType, TraitsType> &))
{
m_stream << func;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template<class CharacterType, class Traits, class Allocator>
inline ColorStream &operator<<(ColorStream &colorStream, const std::basic_string<CharacterType, Traits, Allocator> &string)
{
colorStream.stream() << string;
return colorStream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(char value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(signed char value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &ColorStream::operator<<(unsigned char value)
{
m_stream << value;
return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -0,0 +1,244 @@
#ifndef __ANTHEM_OUTPUT__FORMATTING_H
#define __ANTHEM_OUTPUT__FORMATTING_H
#include <iostream>
#include <anthem/output/ColorStream.h>
namespace anthem
{
namespace output
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Formatting
//
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Color
{
Default = 39,
Black = 30,
Red = 31,
Green = 32,
Yellow = 33,
Blue = 34,
Magenta = 35,
Cyan = 36,
LightGray = 37,
DarkGray = 90,
LightRed = 91,
LightGreen = 92,
LightYellow = 93,
LightBlue = 94,
LightMagenta = 95,
LightCyan = 96,
White = 97
};
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class FontWeight
{
Normal = 21,
Bold = 1
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Format
{
Color color = Color::Default;
FontWeight fontWeight = FontWeight::Normal;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Format &format)
{
if (!stream.supportsColor())
return stream;
const auto fontWeightCode = static_cast<int>(format.fontWeight);
const auto colorCode = static_cast<int>(format.color);
return (stream << "\033[" << fontWeightCode << ";" << colorCode << "m");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct ResetFormat
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const ResetFormat &)
{
if (!stream.supportsColor())
return stream;
return (stream << "\033[0m");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Token
{
const char *name;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Function: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Function &function)
{
return (stream
<< Format({Color::White, FontWeight::Bold})
<< function.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Keyword: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Keyword &keyword)
{
return (stream
<< Format({Color::Blue, FontWeight::Normal})
<< keyword.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Number: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Number &number)
{
return (stream
<< Format({Color::Yellow, FontWeight::Normal})
<< number.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Variable: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Variable &variable)
{
return (stream
<< Format({Color::Green, FontWeight::Bold})
<< variable.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct String: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const String &string)
{
return (stream
<< Format({Color::Green, FontWeight::Normal})
<< "\"" << string.name << "\""
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Boolean: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Boolean &boolean)
{
return (stream
<< Format({Color::Red, FontWeight::Normal})
<< boolean.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Reserved: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Reserved &reserved)
{
return (stream
<< Format({Color::White, FontWeight::Normal})
<< reserved.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Heading1: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Heading1 &heading1)
{
return (stream
<< Format({Color::Blue, FontWeight::Bold})
<< "%---------------------------------------" << std::endl
<< "% " << heading1.name << std::endl
<< "%---------------------------------------"
<< ResetFormat()
<< std::endl);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Heading2: public Token
{
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline ColorStream &operator<<(ColorStream &stream, const Heading2 &heading2)
{
return (stream
<< Format({Color::Blue, FontWeight::Bold})
<< "% " << heading2.name
<< ResetFormat());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -0,0 +1,54 @@
#ifndef __ANTHEM__OUTPUT__LOGGER_H
#define __ANTHEM__OUTPUT__LOGGER_H
#include <string>
#include <anthem/input/Location.h>
#include <anthem/output/ColorStream.h>
#include <anthem/output/Priority.h>
namespace anthem
{
namespace output
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Logger
//
////////////////////////////////////////////////////////////////////////////////////////////////////
class Logger
{
public:
Logger();
Logger(const Logger &other) = default;
Logger &operator=(const Logger &other) = default;
Logger(Logger &&other) = default;
Logger &operator=(Logger &&other) = default;
ColorStream &outputStream();
ColorStream &errorStream();
// The level from which on messages should be printed
void setOutputPriority(Priority outputLevel);
void setColorPolicy(ColorStream::ColorPolicy colorPolicy);
void log(Priority priority, const char *message);
void log(Priority priority, const input::Location &location, const char *message);
private:
ColorStream m_outputStream;
ColorStream m_errorStream;
Priority m_outputPriority;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -0,0 +1,28 @@
#ifndef __ANTHEM__OUTPUT__PRIORITY_H
#define __ANTHEM__OUTPUT__PRIORITY_H
namespace anthem
{
namespace output
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Priority
//
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Priority
{
Debug,
Note,
Warning,
Error
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}
#endif

View File

@ -3,9 +3,15 @@ set(target anthem)
file(GLOB core_sources "anthem/*.cpp") file(GLOB core_sources "anthem/*.cpp")
file(GLOB core_headers "../include/anthem/*.h") file(GLOB core_headers "../include/anthem/*.h")
file(GLOB output_sources "anthem/output/*.cpp")
file(GLOB output_headers "../include/anthem/output/*.h")
set(sources set(sources
${core_sources} ${core_sources}
${core_headers} ${core_headers}
${output_sources}
${output_headers}
) )
set(includes set(includes

View File

@ -0,0 +1,135 @@
#include <anthem/output/Logger.h>
#include <anthem/output/Formatting.h>
namespace anthem
{
namespace output
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Logger
//
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr Format priorityFormat(Priority priority)
{
switch (priority)
{
case Priority::Debug:
return {Color::Green, FontWeight::Bold};
case Priority::Note:
return {Color::Cyan, FontWeight::Bold};
case Priority::Warning:
return {Color::Magenta, FontWeight::Bold};
case Priority::Error:
return {Color::Red, FontWeight::Bold};
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr const char *priorityName(Priority priority)
{
switch (priority)
{
case Priority::Debug:
return "debug";
case Priority::Note:
return "note";
case Priority::Warning:
return "warning";
case Priority::Error:
return "error";
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr const Format MessageBodyFormat = {Color::White, FontWeight::Bold};
////////////////////////////////////////////////////////////////////////////////////////////////////
constexpr const Format LocationFormat = {Color::White, FontWeight::Bold};
////////////////////////////////////////////////////////////////////////////////////////////////////
Logger::Logger()
: m_outputStream{std::cout},
m_errorStream{std::cerr},
m_outputPriority{Priority::Warning}
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &Logger::outputStream()
{
return m_outputStream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ColorStream &Logger::errorStream()
{
return m_errorStream;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::setOutputPriority(Priority outputPriority)
{
m_outputPriority = outputPriority;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::setColorPolicy(ColorStream::ColorPolicy colorPolicy)
{
m_outputStream.setColorPolicy(colorPolicy);
m_errorStream.setColorPolicy(colorPolicy);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::log(Priority priority, const char *message)
{
const auto priorityID = static_cast<int>(priority);
auto &stream =
(priorityID > static_cast<int>(Priority::Warning))
? m_errorStream
: m_outputStream;
stream
<< priorityFormat(priority) << priorityName(priority) << ":"
<< ResetFormat() << " "
<< MessageBodyFormat << message
<< ResetFormat() << std::endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void Logger::log(Priority priority, const input::Location &location, const char *message)
{
const auto priorityID = static_cast<int>(priority);
auto &stream =
(priorityID > static_cast<int>(Priority::Warning))
? m_errorStream
: m_outputStream;
stream
<< LocationFormat
<< location.sectionStart << ":" << location.rowStart << ":" << location.columnStart << ":"
<< priorityFormat(priority) << priorityName(priority) << ":"
<< ResetFormat() << " "
<< MessageBodyFormat << message
<< ResetFormat() << std::endl;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
}