Make use of escape codes configurable
This commit is contained in:
parent
6933b7b33e
commit
9829dbe727
|
@ -147,6 +147,18 @@ if(FORCE_UTF8_CODEPAGE)
|
|||
list(APPEND META_PRIVATE_COMPILE_DEFINITIONS ${META_PROJECT_VARNAME}_FORCE_UTF8_CODEPAGE)
|
||||
endif()
|
||||
|
||||
# configure whether escape codes should be enabled by default
|
||||
option(ENABLE_ESCAPE_CODES_BY_DEAULT "enables usage of escape codes by default" ON)
|
||||
if(ENABLE_ESCAPE_CODES_BY_DEAULT)
|
||||
set_source_files_properties(
|
||||
application/argumentparser.cpp
|
||||
io/ansiescapecodes.cpp
|
||||
PROPERTIES COMPILE_DEFINITIONS ${META_PROJECT_VARNAME}_ESCAPE_CODES_ENABLED_BY_DEFAULT
|
||||
)
|
||||
else()
|
||||
message(STATUS "Disabling use of escape codes by default.")
|
||||
endif()
|
||||
|
||||
# include modules to apply configuration
|
||||
include(BasicConfig)
|
||||
include(WindowsResources)
|
||||
|
|
|
@ -782,7 +782,9 @@ void ArgumentParser::readArgs(int argc, const char *const *argv)
|
|||
completionMode);
|
||||
try {
|
||||
reader.read();
|
||||
NoColorArgument::apply();
|
||||
} catch (const Failure &) {
|
||||
NoColorArgument::apply();
|
||||
if (!completionMode) {
|
||||
throw;
|
||||
}
|
||||
|
@ -1375,4 +1377,91 @@ HelpArgument::HelpArgument(ArgumentParser &parser)
|
|||
* \brief The ConfigValueArgument class is an Argument where setCombinable() is true by default.
|
||||
* \sa ConfigValueArgument::ConfigValueArgument()
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \class NoColorArgument
|
||||
* \brief The NoColorArgument class allows to specify whether use of escape codes or similar technique to provide formatted output
|
||||
* on the terminal should be enabled/disabled.
|
||||
*
|
||||
* This argument will either prevent or explicitely allow the use of escape codes or similar technique to provide formatted output
|
||||
* on the terminal. More explicitly, the argument will always allow to negate the default value of EscapeCodes::enabled which can be
|
||||
* configured at build time by setting the CMake variable ENABLE_ESCAPE_CODES_BY_DEFAULT.
|
||||
*
|
||||
* \remarks
|
||||
* - Only the first instance is considered for actually altering the value of EscapeCodes::enabled so it makes no sense to
|
||||
* instantiate this class multiple times.
|
||||
* - It is ensure that EscapeCodes::enabled will be set before any callback functions are invoked and even in the error case (if
|
||||
* the error doesn't prevent the argument from being detected). Hence this feature is implemented via NoColorArgument::apply()
|
||||
* rather than the usual callback mechanism.
|
||||
*
|
||||
* \sa NoColorArgument::NoColorArgument(), EscapeCodes::enabled
|
||||
*/
|
||||
|
||||
NoColorArgument *NoColorArgument::s_instance = nullptr;
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new NoColorArgument argument.
|
||||
* \remarks This will also set EscapeCodes::enabled to the value of the environment variable ENABLE_ESCAPE_CODES.
|
||||
*/
|
||||
NoColorArgument::NoColorArgument()
|
||||
#ifdef CPP_UTILITIES_ESCAPE_CODES_ENABLED_BY_DEFAULT
|
||||
: Argument("no-color", '\0', "disables formatted/colorized output")
|
||||
#else
|
||||
: Argument("enable-color", '\0', "enables formatted/colorized output")
|
||||
#endif
|
||||
{
|
||||
setCombinable(true);
|
||||
|
||||
if (s_instance) {
|
||||
return;
|
||||
}
|
||||
s_instance = this;
|
||||
|
||||
// set the environmentvariable: note that this is not directly used and just assigned for printing help
|
||||
setEnvironmentVariable("ENABLE_ESCAPE_CODES");
|
||||
|
||||
// default-initialize EscapeCodes::enabled from environment variable
|
||||
const char *envValue = getenv(environmentVariable());
|
||||
if (!envValue) {
|
||||
return;
|
||||
}
|
||||
for (; *envValue; ++envValue) {
|
||||
switch (*envValue) {
|
||||
case '0':
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
// enable escape codes if ENABLE_ESCAPE_CODES contains anything else than spaces or zeros
|
||||
EscapeCodes::enabled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// disable escape codes if ENABLE_ESCAPE_CODES is empty or only contains spaces and zeros
|
||||
EscapeCodes::enabled = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the object.
|
||||
*/
|
||||
NoColorArgument::~NoColorArgument()
|
||||
{
|
||||
if (s_instance == this) {
|
||||
s_instance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets EscapeCodes::enabled according to the presense of the first instantiation of NoColorArgument.
|
||||
*/
|
||||
void NoColorArgument::apply()
|
||||
{
|
||||
if (NoColorArgument::s_instance && NoColorArgument::s_instance->isPresent()) {
|
||||
#ifdef CPP_UTILITIES_ESCAPE_CODES_ENABLED_BY_DEFAULT
|
||||
EscapeCodes::enabled = false;
|
||||
#else
|
||||
EscapeCodes::enabled = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ApplicationUtilities
|
||||
|
|
|
@ -873,6 +873,17 @@ inline ConfigValueArgument::ConfigValueArgument(
|
|||
setRequiredValueCount(valueNames.size());
|
||||
setValueNames(valueNames);
|
||||
}
|
||||
|
||||
class CPP_UTILITIES_EXPORT NoColorArgument : public Argument {
|
||||
public:
|
||||
NoColorArgument();
|
||||
~NoColorArgument();
|
||||
static void apply();
|
||||
|
||||
private:
|
||||
static NoColorArgument *s_instance;
|
||||
};
|
||||
|
||||
} // namespace ApplicationUtilities
|
||||
|
||||
#endif // APPLICATION_UTILITIES_ARGUMENTPARSER_H
|
||||
|
|
|
@ -70,6 +70,12 @@ None of these are enabled or set by default, unless stated otherwise.
|
|||
* coverage report is stored in build directory
|
||||
* `ENABLE_INSTALL_TARGETS=ON/OFF`: enables creation of install targets (enabled
|
||||
by default)
|
||||
* `ENABLE_ESCAPE_CODES_BY_DEAULT`: enables use of escape codes for formatted
|
||||
output by default
|
||||
* enabled by default
|
||||
* see ApplicationUtilities::NoColorArgument and EscapeCodes::enabled
|
||||
* has to be set when building `c++utilities`; projects using that build of
|
||||
`c++utilities` will then use this default
|
||||
|
||||
#### Variables for specifying location of 3rd party dependencies
|
||||
The build script tries to find the required dependencies at standard loctions
|
||||
|
|
|
@ -1,7 +1,30 @@
|
|||
#include "./ansiescapecodes.h"
|
||||
|
||||
/*!
|
||||
* \brief Encapsulates functions for formatted terminal output using ANSI escape codes.
|
||||
*/
|
||||
namespace EscapeCodes {
|
||||
|
||||
/*!
|
||||
* \brief Controls whether the functions inside the EscapeCodes namespace actually make use of escape codes.
|
||||
*
|
||||
* This allows to disable use of escape codes when not appropriate.
|
||||
*
|
||||
* The default value can be configured at build time by setting the CMake variable ENABLE_ESCAPE_CODES_BY_DEFAULT.
|
||||
* The "default for the default" is true.
|
||||
* However, the default is overridden with the value of the environment variable ENABLE_ESCAPE_CODES when instantiating
|
||||
* an ApplicationUtilities::NoColorArgument (if ENABLE_ESCAPE_CODES is present).
|
||||
*
|
||||
* \sa ApplicationUtilities::NoColorArgument
|
||||
*/
|
||||
bool enabled =
|
||||
#ifdef CPP_UTILITIES_ESCAPE_CODES_ENABLED_BY_DEFAULT
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
;
|
||||
|
||||
/*!
|
||||
* \brief Prints the specified \a phrase.
|
||||
*/
|
||||
|
|
|
@ -6,12 +6,10 @@
|
|||
#include <ostream>
|
||||
#include <tuple>
|
||||
|
||||
/*!
|
||||
* \brief Encapsulates functions for formatted terminal output using ANSI escape codes.
|
||||
* \remarks The functions haven't been tested yet and are still experimental. API/ABI might change in next minor release.
|
||||
*/
|
||||
namespace EscapeCodes {
|
||||
|
||||
extern CPP_UTILITIES_EXPORT bool enabled;
|
||||
|
||||
enum class Color : char { Black = '0', Red, Green, Yellow, Blue, Purple, Cyan, White };
|
||||
|
||||
enum class ColorContext : char { Foreground = '3', Background = '4' };
|
||||
|
@ -31,55 +29,76 @@ enum class Direction : char { Up = 'A', Down = 'B', Forward = 'C', Backward = 'D
|
|||
|
||||
inline void setStyle(std::ostream &stream, TextAttribute displayAttribute = TextAttribute::Reset)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << '\e' << '[' << static_cast<char>(displayAttribute) << 'm';
|
||||
}
|
||||
}
|
||||
|
||||
inline void setStyle(
|
||||
std::ostream &stream, Color color, ColorContext context = ColorContext::Foreground, TextAttribute displayAttribute = TextAttribute::Reset)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << '\e' << '[' << static_cast<char>(displayAttribute) << ';' << static_cast<char>(context) << static_cast<char>(color) << 'm';
|
||||
}
|
||||
}
|
||||
|
||||
inline void setStyle(std::ostream &stream, Color foregroundColor, Color backgroundColor, TextAttribute displayAttribute = TextAttribute::Reset)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << '\e' << '[' << static_cast<char>(displayAttribute) << ';' << static_cast<char>(ColorContext::Foreground)
|
||||
<< static_cast<char>(foregroundColor) << ';' << static_cast<char>(ColorContext::Foreground) << static_cast<char>(backgroundColor) << 'm';
|
||||
<< static_cast<char>(foregroundColor) << ';' << static_cast<char>(ColorContext::Foreground) << static_cast<char>(backgroundColor)
|
||||
<< 'm';
|
||||
}
|
||||
}
|
||||
|
||||
inline void resetStyle(std::ostream &stream)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << '\e' << '[' << static_cast<char>(TextAttribute::Reset) << 'm';
|
||||
}
|
||||
}
|
||||
|
||||
inline void setCursor(std::ostream &stream, unsigned int row = 0, unsigned int col = 0)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << '\e' << '[' << row << ';' << col << 'H';
|
||||
}
|
||||
}
|
||||
|
||||
inline void moveCursor(std::ostream &stream, unsigned int cells, Direction direction)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << '\e' << '[' << cells << static_cast<char>(direction);
|
||||
}
|
||||
}
|
||||
|
||||
inline void saveCursor(std::ostream &stream)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << "\e[s";
|
||||
}
|
||||
}
|
||||
|
||||
inline void restoreCursor(std::ostream &stream)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << "\e[u";
|
||||
}
|
||||
}
|
||||
|
||||
inline void eraseDisplay(std::ostream &stream)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << "\e[2J";
|
||||
}
|
||||
}
|
||||
|
||||
inline void eraseLine(std::ostream &stream)
|
||||
{
|
||||
if (enabled) {
|
||||
stream << "\33[2K";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, TextAttribute displayAttribute)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue