forked from Alepha/Alepha
Update and consolidate the console and colors code.
This introduces a subset of SGR-Name syntax.
This commit is contained in:
@ -13,7 +13,7 @@ main( const int argcnt, const char *const argvec[] )
|
|||||||
|
|
||||||
static auto tests= Alepha::Utility::enroll <=[]
|
static auto tests= Alepha::Utility::enroll <=[]
|
||||||
{
|
{
|
||||||
using namespace Alepha::exports::auto_raii;
|
using namespace Alepha::Hydrogen::exports::auto_raii;
|
||||||
using namespace Alepha::Testing::exports::literals;
|
using namespace Alepha::Testing::exports::literals;
|
||||||
|
|
||||||
using Alepha::Testing::exports::TestState;
|
using Alepha::Testing::exports::TestState;
|
||||||
|
|||||||
182
Console.cpp
182
Console.cpp
@ -39,7 +39,7 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
// universally supported for effectively all cases modern users will care about.
|
// universally supported for effectively all cases modern users will care about.
|
||||||
|
|
||||||
|
|
||||||
namespace Alepha::Cavorite ::detail:: console
|
namespace Alepha::Hydrogen ::detail:: console
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -87,6 +87,7 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
auto screenWidthEnvLimit() { return applicationName() + "_SCREEN_WIDTH_LIMIT"; }
|
auto screenWidthEnvLimit() { return applicationName() + "_SCREEN_WIDTH_LIMIT"; }
|
||||||
auto disableColorsEnv() { return applicationName() + "_DISABLE_COLOR_TEXT"; }
|
auto disableColorsEnv() { return applicationName() + "_DISABLE_COLOR_TEXT"; }
|
||||||
auto colorsEnv() { return applicationName() + "_COLORS"; }
|
auto colorsEnv() { return applicationName() + "_COLORS"; }
|
||||||
|
auto sgr_nameEnv() { return applicationName() + "_SGR_NAMES"; }
|
||||||
|
|
||||||
// TODO: Put this in a library
|
// TODO: Put this in a library
|
||||||
int
|
int
|
||||||
@ -113,7 +114,7 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
bool
|
bool
|
||||||
colorEnabled()
|
colorEnabled()
|
||||||
{
|
{
|
||||||
if( not colorState.has_value() ) return getenv( disableColorsEnv().c_str() );
|
if( not colorState.has_value() ) return not ::getenv( disableColorsEnv().c_str() );
|
||||||
|
|
||||||
if( colorState.value() == "never"_value ) return false;
|
if( colorState.value() == "never"_value ) return false;
|
||||||
if( colorState.value() == "always"_value ) return true;
|
if( colorState.value() == "always"_value ) return true;
|
||||||
@ -124,6 +125,98 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
|
|
||||||
StaticValue< std::map< Style, SGR_String > > colorVariables;
|
StaticValue< std::map< Style, SGR_String > > colorVariables;
|
||||||
|
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
parse( const std::string &token )
|
||||||
|
{
|
||||||
|
const std::map< std::string, std::function< SGR_String () > > simple=
|
||||||
|
{
|
||||||
|
{ "reset", resetTextEffects },
|
||||||
|
{ "bold", setBold },
|
||||||
|
{ "dim", setFaint },
|
||||||
|
{ "faint", setFaint },
|
||||||
|
{ "italic", setItalic },
|
||||||
|
{ "underline", setUnderline },
|
||||||
|
{ "under", setUnderline },
|
||||||
|
{ "blink", setBlink },
|
||||||
|
{ "strike", setStrike },
|
||||||
|
{ "strikethrough", setStrike },
|
||||||
|
{ "strikethru", setStrike },
|
||||||
|
{ "doubleunderline", setDoubleUnderline },
|
||||||
|
{ "doubleunder", setDoubleUnderline },
|
||||||
|
{ "framed", setFramed },
|
||||||
|
{ "encircled", setEncircled },
|
||||||
|
{ "overline", setOverline },
|
||||||
|
};
|
||||||
|
if( simple.contains( token ) ) return simple.at( token )();
|
||||||
|
|
||||||
|
// The `fg:` is optional in "SGR Name"...
|
||||||
|
if( token.starts_with( "fg:" ) ) return parse( token.substr( 2 ) );
|
||||||
|
|
||||||
|
if( token.starts_with( "ansi:" ) ) return { '3' + token.substr( 5 ) };
|
||||||
|
if( token.starts_with( "ext:grey" ) )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "3;5;";
|
||||||
|
oss << int( TextColor::greyscale_base ) + boost::lexical_cast< int >( token.substr( 8 ) );
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
if( token.starts_with( "ext:rgb" ) )
|
||||||
|
{
|
||||||
|
const std::string rgb= token.substr( 7 );
|
||||||
|
if( rgb.size() != 3 ) throw std::runtime_error{ "RGB request with more than 3 digits..." };
|
||||||
|
const int r= boost::lexical_cast< int >( rgb.substr( 0, 1 ) );
|
||||||
|
const int g= boost::lexical_cast< int >( rgb.substr( 1, 1 ) );
|
||||||
|
const int b= boost::lexical_cast< int >( rgb.substr( 2, 1 ) );
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "3;5;";
|
||||||
|
oss << int( TextColor::rgb_base ) + r * int( TextColor::red_radix ) + g * int( TextColor::green_radix ) + b * int( TextColor::blue_radix );
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
if( token.starts_with( "ext:" ) ) return { "38;5;" + token.substr( 4 ) };
|
||||||
|
if( token.starts_with( "#" ) )
|
||||||
|
{
|
||||||
|
const auto code= token.substr( 1 );
|
||||||
|
const auto [ r_s, g_s, b_s ]= evaluate <=[&]
|
||||||
|
{
|
||||||
|
if( code.size() == 3 ) return std::tuple{ code.substr( 0, 1 ), code.substr( 1, 1 ), code.substr( 2, 1 ) };
|
||||||
|
if( code.size() == 6 ) return std::tuple{ code.substr( 0, 2 ), code.substr( 2, 2 ), code.substr( 4, 2 ) };
|
||||||
|
throw std::runtime_error( "True color code parse error." );
|
||||||
|
};
|
||||||
|
int r, g, b;
|
||||||
|
{
|
||||||
|
std::istringstream iss{ r_s };
|
||||||
|
iss >> std::hex >> r;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::istringstream iss{ g_s };
|
||||||
|
iss >> std::hex >> g;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::istringstream iss{ b_s };
|
||||||
|
iss >> std::hex >> b;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "38;2;" << std::dec << r << ';' << g << ';' << b;
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error{ "Unrecognized SGR Name keyword: `" + token + "`" };
|
||||||
|
}
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
parseTokens( std::vector< std::string > tokens )
|
||||||
|
{
|
||||||
|
|
||||||
|
SGR_String rv;
|
||||||
|
for( const auto token: tokens ) rv+= parse( token );
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
auto init= enroll <=[]
|
auto init= enroll <=[]
|
||||||
{
|
{
|
||||||
--"screen-width"_option << affectsHelp << cachedScreenWidth << "Sets the screen width for use in automatic word-wrapping. !default!";
|
--"screen-width"_option << affectsHelp << cachedScreenWidth << "Sets the screen width for use in automatic word-wrapping. !default!";
|
||||||
@ -136,6 +229,7 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
{
|
{
|
||||||
std::cout << name.name << ": ^[[" << sgr.code << "m" << std::endl;
|
std::cout << name.name << ": ^[[" << sgr.code << "m" << std::endl;
|
||||||
}
|
}
|
||||||
|
::exit( EXIT_SUCCESS );
|
||||||
}
|
}
|
||||||
<< "Emit a list with the color variables supported by this application. For use with the `" << colorsEnv()
|
<< "Emit a list with the color variables supported by this application. For use with the `" << colorsEnv()
|
||||||
<< "` environment variable.";
|
<< "` environment variable.";
|
||||||
@ -156,7 +250,27 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
<< "Emit a BASH command which will set the appropriate environment variable to capture the current color settings for this "
|
<< "Emit a BASH command which will set the appropriate environment variable to capture the current color settings for this "
|
||||||
<< "application.";
|
<< "application.";
|
||||||
|
|
||||||
parse_environment_variable_for_color:
|
parse_environment_variables_for_color:
|
||||||
|
// First the SGR Name language
|
||||||
|
if( getenv( sgr_nameEnv().c_str() ) )
|
||||||
|
{
|
||||||
|
const std::string contents= getenv( sgr_nameEnv().c_str() );
|
||||||
|
|
||||||
|
for( const auto var: split( contents, ';' ) )
|
||||||
|
{
|
||||||
|
const auto parsed= split( var, '=' );
|
||||||
|
if( parsed.size() != 2 )
|
||||||
|
{
|
||||||
|
throw std::runtime_error{ "Color environment variable parse error in: `" + var + "`." };
|
||||||
|
}
|
||||||
|
|
||||||
|
const Style name{ parsed.at( 0 ) };
|
||||||
|
const auto value= parsed.at( 1 );
|
||||||
|
|
||||||
|
colorVariables()[ name ]= parseTokens( split( value, ' ' ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then the regular terminal codes
|
||||||
if( getenv( colorsEnv().c_str() ) )
|
if( getenv( colorsEnv().c_str() ) )
|
||||||
{
|
{
|
||||||
const std::string contents= getenv( colorsEnv().c_str() );
|
const std::string contents= getenv( colorsEnv().c_str() );
|
||||||
@ -180,7 +294,7 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
std::ostream &
|
std::ostream &
|
||||||
csi( std::ostream &os )
|
csi( std::ostream &os )
|
||||||
{
|
{
|
||||||
return os << "\e";
|
return os << "\e[";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +327,7 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
std::ostream &
|
std::ostream &
|
||||||
exports::operator << ( std::ostream &os, decltype( resetStyle ) )
|
exports::operator << ( std::ostream &os, decltype( resetStyle ) )
|
||||||
{
|
{
|
||||||
if( colorEnabled )
|
if( colorEnabled() )
|
||||||
{
|
{
|
||||||
sendSGR( os, resetTextEffects() );
|
sendSGR( os, resetTextEffects() );
|
||||||
}
|
}
|
||||||
@ -370,9 +484,18 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
|
|
||||||
void Console::clearScreen() { csi() << "2J"; }
|
void Console::clearScreen() { csi() << "2J"; }
|
||||||
|
|
||||||
SGR_String exports::resetTextEffects() { return {}; }
|
SGR_String exports::resetTextEffects() { return { "0" }; }
|
||||||
|
|
||||||
|
SGR_String exports::setBold() { return { "1" }; }
|
||||||
|
SGR_String exports::setFaint() { return { "2" }; }
|
||||||
|
SGR_String exports::setItalic() { return { "3" }; }
|
||||||
|
SGR_String exports::setUnderline() { return { "4" }; }
|
||||||
SGR_String exports::setBlink() { return { "5" }; }
|
SGR_String exports::setBlink() { return { "5" }; }
|
||||||
|
SGR_String exports::setStrike() { return { "9" }; }
|
||||||
|
SGR_String exports::setDoubleUnderline() { return { "21" }; }
|
||||||
|
SGR_String exports::setFramed() { return { "51" }; }
|
||||||
|
SGR_String exports::setEncircled() { return { "52" }; }
|
||||||
|
SGR_String exports::setOverline() { return { "52" }; }
|
||||||
|
|
||||||
SGR_String
|
SGR_String
|
||||||
exports::setFgColor( const BasicTextColor c )
|
exports::setFgColor( const BasicTextColor c )
|
||||||
@ -423,6 +546,53 @@ namespace Alepha::Cavorite ::detail:: console
|
|||||||
return { std::move( oss ).str() };
|
return { std::move( oss ).str() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
exports::setExtUlColor( const TextColor ul )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "58;5;" << int( ul );
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
|
||||||
|
SGR_String exports::setFgTrueColor( const int rgb ) { return setFgTrueColor( rgb & 0xFF, ( rgb >> 8 ) & 0xFF, ( rgb >> 16 ) & 0xFF ); }
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
exports::setFgTrueColor( const int r, const int g, const int b )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "38;2;" << r << ';' << g << ';' << b;
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
|
||||||
|
SGR_String exports::setBgTrueColor( const int rgb ) { return setBgTrueColor( rgb & 0xFF, ( rgb >> 8 ) & 0xFF, ( rgb >> 16 ) & 0xFF ); }
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
exports::setBgTrueColor( const int r, const int g, const int b )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "48;2;" << r << ';' << g << ';' << b;
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
|
||||||
|
SGR_String exports::setUlTrueColor( const int rgb ) { return setUlTrueColor( rgb & 0xFF, ( rgb >> 8 ) & 0xFF, ( rgb >> 16 ) & 0xFF ); }
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
exports::setUlTrueColor( const int r, const int g, const int b )
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "58;2;" << r << ';' << g << ';' << b;
|
||||||
|
return { std::move( oss ).str() };
|
||||||
|
}
|
||||||
|
|
||||||
|
SGR_String
|
||||||
|
exports::operator ""_sgr( const char *const p, const std::size_t sz )
|
||||||
|
{
|
||||||
|
const std::string s{ p, p + sz };
|
||||||
|
|
||||||
|
const auto tokens= split( s, ' ' );
|
||||||
|
return parseTokens( tokens );
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
exports::getConsoleWidth()
|
exports::getConsoleWidth()
|
||||||
{
|
{
|
||||||
|
|||||||
81
Console.h
81
Console.h
@ -2,6 +2,8 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Alepha/Alepha.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -14,7 +16,7 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
// As long as this works on most (all?) modern terminal emulators, this should be
|
// As long as this works on most (all?) modern terminal emulators, this should be
|
||||||
// fine.
|
// fine.
|
||||||
|
|
||||||
namespace Alepha::inline Cavorite ::detail:: console
|
namespace Alepha::Hydrogen ::detail:: console
|
||||||
{
|
{
|
||||||
inline namespace exports {}
|
inline namespace exports {}
|
||||||
|
|
||||||
@ -30,12 +32,23 @@ namespace Alepha::inline Cavorite ::detail:: console
|
|||||||
std::string code;
|
std::string code;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto
|
[[nodiscard]] inline SGR_String
|
||||||
operator ""_sgr( const char *const p, const std::size_t sz )
|
operator + ( const SGR_String lhs, const SGR_String rhs )
|
||||||
{
|
{
|
||||||
return SGR_String{ { p, p + sz } };
|
if( lhs.code.empty() ) return rhs;
|
||||||
|
if( rhs.code.empty() ) return lhs;
|
||||||
|
return SGR_String{ lhs.code + ';' + rhs.code };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline SGR_String &
|
||||||
|
operator += ( SGR_String &lhs, const SGR_String rhs )
|
||||||
|
{
|
||||||
|
return lhs= lhs + rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses sgr token names, like "bold ext:red"
|
||||||
|
[[nodiscard]] SGR_String operator ""_sgr( const char *p, std::size_t sz );
|
||||||
|
|
||||||
enum class BasicTextColor : int;
|
enum class BasicTextColor : int;
|
||||||
enum class TextColor : int;
|
enum class TextColor : int;
|
||||||
|
|
||||||
@ -143,7 +156,17 @@ namespace Alepha::inline Cavorite ::detail:: console
|
|||||||
{
|
{
|
||||||
[[nodiscard]] SGR_String resetTextEffects();
|
[[nodiscard]] SGR_String resetTextEffects();
|
||||||
|
|
||||||
|
// Non Colour effects (Mostly sorted by ANSI/ECMA SGR code numeric order)
|
||||||
|
[[nodiscard]] SGR_String setBold();
|
||||||
|
[[nodiscard]] SGR_String setFaint();
|
||||||
|
[[nodiscard]] SGR_String setItalic();
|
||||||
|
[[nodiscard]] SGR_String setUnderline();
|
||||||
[[nodiscard]] SGR_String setBlink();
|
[[nodiscard]] SGR_String setBlink();
|
||||||
|
[[nodiscard]] SGR_String setStrike();
|
||||||
|
[[nodiscard]] SGR_String setDoubleUnderline();
|
||||||
|
[[nodiscard]] SGR_String setFramed();
|
||||||
|
[[nodiscard]] SGR_String setEncircled();
|
||||||
|
[[nodiscard]] SGR_String setOverline();
|
||||||
|
|
||||||
[[nodiscard]] SGR_String setFgColor( BasicTextColor fg );
|
[[nodiscard]] SGR_String setFgColor( BasicTextColor fg );
|
||||||
[[nodiscard]] SGR_String setBgColor( BasicTextColor bg );
|
[[nodiscard]] SGR_String setBgColor( BasicTextColor bg );
|
||||||
@ -152,6 +175,7 @@ namespace Alepha::inline Cavorite ::detail:: console
|
|||||||
[[nodiscard]] SGR_String setExtFgColor( TextColor fg );
|
[[nodiscard]] SGR_String setExtFgColor( TextColor fg );
|
||||||
[[nodiscard]] SGR_String setExtBgColor( TextColor fg );
|
[[nodiscard]] SGR_String setExtBgColor( TextColor fg );
|
||||||
[[nodiscard]] SGR_String setExtColor( TextColor fg, TextColor bg );
|
[[nodiscard]] SGR_String setExtColor( TextColor fg, TextColor bg );
|
||||||
|
[[nodiscard]] SGR_String setExtUlColor( TextColor ul );
|
||||||
|
|
||||||
// Basic color wrapping aliases:
|
// Basic color wrapping aliases:
|
||||||
[[nodiscard]] inline SGR_String setExtFgColor( const BasicTextColor fg ) { return setExtFgColor( static_cast< TextColor >( fg ) ); }
|
[[nodiscard]] inline SGR_String setExtFgColor( const BasicTextColor fg ) { return setExtFgColor( static_cast< TextColor >( fg ) ); }
|
||||||
@ -167,13 +191,60 @@ namespace Alepha::inline Cavorite ::detail:: console
|
|||||||
[[nodiscard]] SGR_String setBgTrueColor( int rgb );
|
[[nodiscard]] SGR_String setBgTrueColor( int rgb );
|
||||||
[[nodiscard]] SGR_String setBgTrueColor( int r, int g, int b );
|
[[nodiscard]] SGR_String setBgTrueColor( int r, int g, int b );
|
||||||
|
|
||||||
|
[[nodiscard]] SGR_String setUlTrueColor( int rgb );
|
||||||
|
[[nodiscard]] SGR_String setUlTrueColor( int r, int g, int b );
|
||||||
|
|
||||||
void sendSGR( std::ostream &os, SGR_String );
|
void sendSGR( std::ostream &os, SGR_String );
|
||||||
|
|
||||||
int getConsoleWidth();
|
int getConsoleWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class exports::BasicTextColor : int
|
||||||
|
{
|
||||||
|
black= 0,
|
||||||
|
red= 1,
|
||||||
|
green= 2,
|
||||||
|
brown= 3,
|
||||||
|
blue= 4,
|
||||||
|
magenta= 5,
|
||||||
|
cyan= 6,
|
||||||
|
grey= 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class exports::TextColor : int
|
||||||
|
{
|
||||||
|
black= 0,
|
||||||
|
dim_red= 1,
|
||||||
|
dim_green= 2,
|
||||||
|
dim_brown= 3,
|
||||||
|
dim_blue= 4,
|
||||||
|
dim_magenta= 5,
|
||||||
|
dim_cyan= 6,
|
||||||
|
bright_grey= 7,
|
||||||
|
|
||||||
|
// Note that bright and dim grey are reverse, since bright grey is dim white and dim grey si bright black.
|
||||||
|
// The names are more understandable this way, I think
|
||||||
|
|
||||||
|
dim_grey= 8,
|
||||||
|
bright_red= 9,
|
||||||
|
bright_green= 10,
|
||||||
|
bright_brown= 11,
|
||||||
|
bright_blue= 12,
|
||||||
|
bright_magenta= 13,
|
||||||
|
bright_cyan= 14,
|
||||||
|
white= 15,
|
||||||
|
|
||||||
|
rgb_base= 16,
|
||||||
|
red_radix= 36,
|
||||||
|
green_radix= 6,
|
||||||
|
blue_radix= 0,
|
||||||
|
|
||||||
|
greyscale_base= 232, // Add N to this to get the greyscale offset.
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Alepha::Cavorite::inline exports::inline console
|
namespace Alepha::Hydrogen::inline exports::inline console
|
||||||
{
|
{
|
||||||
using namespace detail::console::exports;
|
using namespace detail::console::exports;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,9 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
#include <Alepha/Utility/evaluation_helpers.h>
|
#include <Alepha/Utility/evaluation_helpers.h>
|
||||||
|
|
||||||
#include <Alepha/TotalOrder.h>
|
#include <Alepha/TotalOrder.h>
|
||||||
#include <Alepha/console.h>
|
#include <Alepha/Console.h>
|
||||||
|
|
||||||
|
#include "colors.h"
|
||||||
|
|
||||||
namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
||||||
{
|
{
|
||||||
@ -41,6 +43,14 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
enum class OutputMode { All, Relaxed };
|
enum class OutputMode { All, Relaxed };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace C
|
||||||
|
{
|
||||||
|
inline namespace Colors
|
||||||
|
{
|
||||||
|
using namespace testing_colors::C::Colors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template< typename F >
|
template< typename F >
|
||||||
concept FunctionVariable=
|
concept FunctionVariable=
|
||||||
requires( const F &f )
|
requires( const F &f )
|
||||||
@ -60,7 +70,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
{
|
{
|
||||||
const bool debug= false;
|
const bool debug= false;
|
||||||
const bool debugCaseTypes= false or C::debug;
|
const bool debugCaseTypes= false or C::debug;
|
||||||
using namespace Alepha::console::C;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using std::begin, std::end;
|
using std::begin, std::end;
|
||||||
@ -260,11 +269,11 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
const auto result= witness == expected;
|
const auto result= witness == expected;
|
||||||
if( not result )
|
if( not result )
|
||||||
{
|
{
|
||||||
std::cout << C::red << " FAILURE" << C::normal << ": " << comment << std::endl;
|
std::cout << C::testFail << " FAILURE" << resetStyle << ": " << comment << std::endl;
|
||||||
++failureCount;
|
++failureCount;
|
||||||
printDebugging< outputMode >( witness, expected );
|
printDebugging< outputMode >( witness, expected );
|
||||||
}
|
}
|
||||||
else std::cout << C::green << " SUCCESS" << C::normal << ": " << comment << std::endl;
|
else std::cout << C::testPass << " SUCCESS" << resetStyle << ": " << comment << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return failureCount;
|
return failureCount;
|
||||||
|
|||||||
17
Testing/colors.h
Normal file
17
Testing/colors.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
static_assert( __cplusplus > 2020'00 );
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Alepha/Console.h>
|
||||||
|
|
||||||
|
namespace Alepha::Hydrogen::Testing ::detail:: testing_colors
|
||||||
|
{
|
||||||
|
namespace C
|
||||||
|
{
|
||||||
|
inline namespace Colors
|
||||||
|
{
|
||||||
|
inline const auto testFail= createStyle( "test-failure", setFgColor( BasicTextColor::red ) );
|
||||||
|
inline const auto testPass= createStyle( "test-success", setFgColor( BasicTextColor::green ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,12 +13,14 @@ static_assert( __cplusplus > 2020'00 );
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <Alepha/console.h>
|
#include <Alepha/Console.h>
|
||||||
#include <Alepha/types.h>
|
#include <Alepha/types.h>
|
||||||
|
|
||||||
#include <Alepha/Utility/evaluation_helpers.h>
|
#include <Alepha/Utility/evaluation_helpers.h>
|
||||||
#include <Alepha/Utility/StaticValue.h>
|
#include <Alepha/Utility/StaticValue.h>
|
||||||
|
|
||||||
|
#include "colors.h"
|
||||||
|
|
||||||
namespace Alepha::Hydrogen::Testing
|
namespace Alepha::Hydrogen::Testing
|
||||||
{
|
{
|
||||||
inline namespace exports { inline namespace testing {} }
|
inline namespace exports { inline namespace testing {} }
|
||||||
@ -33,7 +35,7 @@ namespace Alepha::Hydrogen::Testing
|
|||||||
const bool debugTestRegistration= false or C::debug;
|
const bool debugTestRegistration= false or C::debug;
|
||||||
const bool debugTestRun= false or C::debug;
|
const bool debugTestRun= false or C::debug;
|
||||||
|
|
||||||
using namespace Alepha::Hydrogen::exports::C;
|
using namespace testing_colors::C::Colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
@ -196,9 +198,9 @@ namespace Alepha::Hydrogen::Testing
|
|||||||
|
|
||||||
if( explicitlyNamed( name ) or not disabled and selected( name ) )
|
if( explicitlyNamed( name ) or not disabled and selected( name ) )
|
||||||
{
|
{
|
||||||
std::cout << C::green << "BEGIN " << C::normal << ": " << name << std::endl;
|
std::cout << C::testPass << "BEGIN " << resetStyle << ": " << name << std::endl;
|
||||||
test();
|
test();
|
||||||
std::cout << C::green << "SUCCESS" << C::normal << ": " << name << std::endl;
|
std::cout << C::testPass << "SUCCESS" << resetStyle << ": " << name << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( ... )
|
catch( ... )
|
||||||
@ -206,7 +208,7 @@ namespace Alepha::Hydrogen::Testing
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
failed= true;
|
failed= true;
|
||||||
std::cout << C::red << "FAILURE" << C::normal << ": " << name;
|
std::cout << C::testFail << "FAILURE" << resetStyle << ": " << name;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch( const TestFailureException &fail ) { std::cout << " -- " << fail.failureCount << " failures."; }
|
catch( const TestFailureException &fail ) { std::cout << " -- " << fail.failureCount << " failures."; }
|
||||||
|
|||||||
91
console.h
91
console.h
@ -1,91 +0,0 @@
|
|||||||
static_assert( __cplusplus > 2020'00 );
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Alepha/Alepha.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Alepha::Hydrogen
|
|
||||||
{
|
|
||||||
inline namespace exports { inline namespace console {} }
|
|
||||||
|
|
||||||
namespace detail::console
|
|
||||||
{
|
|
||||||
inline namespace exports {}
|
|
||||||
|
|
||||||
namespace C
|
|
||||||
{
|
|
||||||
const std::string csi= "\e[";
|
|
||||||
const std::string color_code= "m";
|
|
||||||
|
|
||||||
enum Layer
|
|
||||||
{
|
|
||||||
fg_code= '3',
|
|
||||||
bg_code= '4',
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Color : char
|
|
||||||
{
|
|
||||||
black= '0',
|
|
||||||
red= '1',
|
|
||||||
green= '2',
|
|
||||||
brown= '3',
|
|
||||||
blue= '4',
|
|
||||||
magenta= '5',
|
|
||||||
cyan= '6',
|
|
||||||
white= '7',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
using C::Layer;
|
|
||||||
using C::Color;
|
|
||||||
|
|
||||||
inline std::string
|
|
||||||
make_color( const Layer layer, const Color color )
|
|
||||||
{
|
|
||||||
return C::csi + char(layer) + char(color) + C::color_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace C
|
|
||||||
{
|
|
||||||
inline namespace exports
|
|
||||||
{
|
|
||||||
const std::string normal= C::csi + '0' + color_code;
|
|
||||||
|
|
||||||
inline namespace fg
|
|
||||||
{
|
|
||||||
const std::string black= make_color( C::fg_code, C::Color::black );
|
|
||||||
const std::string red= make_color( C::fg_code, C::Color::red );
|
|
||||||
const std::string green= make_color( C::fg_code, C::Color::green );
|
|
||||||
const std::string brown= make_color( C::fg_code, C::Color::brown );
|
|
||||||
const std::string blue= make_color( C::fg_code, C::Color::blue );
|
|
||||||
const std::string magenta= make_color( C::fg_code, C::Color::magenta );
|
|
||||||
const std::string cyan= make_color( C::fg_code, C::Color::cyan );
|
|
||||||
const std::string white= make_color( C::fg_code, C::Color::white );
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace bg
|
|
||||||
{
|
|
||||||
const std::string black= make_color( C::bg_code, C::Color::black );
|
|
||||||
const std::string red= make_color( C::bg_code, C::Color::red );
|
|
||||||
const std::string green= make_color( C::bg_code, C::Color::green );
|
|
||||||
const std::string brown= make_color( C::bg_code, C::Color::brown );
|
|
||||||
const std::string blue= make_color( C::bg_code, C::Color::blue );
|
|
||||||
const std::string magenta= make_color( C::bg_code, C::Color::magenta );
|
|
||||||
const std::string cyan= make_color( C::bg_code, C::Color::cyan );
|
|
||||||
const std::string white= make_color( C::bg_code, C::Color::white );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace exports
|
|
||||||
{
|
|
||||||
namespace C= detail::console::C;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace exports::console
|
|
||||||
{
|
|
||||||
using namespace detail::console::exports;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user