1 /* 2 * Created by Phil on 25/2/2012. 3 * Copyright 2012 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED 9 #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED 10 11 #include "catch_console_colour.hpp" 12 #include "catch_errno_guard.hpp" 13 14 namespace Catch { 15 namespace { 16 17 struct IColourImpl { ~IColourImplCatch::__anon81dd07840111::IColourImpl18 virtual ~IColourImpl() {} 19 virtual void use( Colour::Code _colourCode ) = 0; 20 }; 21 22 struct NoColourImpl : IColourImpl { useCatch::__anon81dd07840111::NoColourImpl23 void use( Colour::Code ) {} 24 instanceCatch::__anon81dd07840111::NoColourImpl25 static IColourImpl* instance() { 26 static NoColourImpl s_instance; 27 return &s_instance; 28 } 29 }; 30 31 } // anon namespace 32 } // namespace Catch 33 34 #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) 35 # ifdef CATCH_PLATFORM_WINDOWS 36 # define CATCH_CONFIG_COLOUR_WINDOWS 37 # else 38 # define CATCH_CONFIG_COLOUR_ANSI 39 # endif 40 #endif 41 42 43 #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// 44 45 #include "catch_windows_h_proxy.h" 46 47 namespace Catch { 48 namespace { 49 50 class Win32ColourImpl : public IColourImpl { 51 public: Win32ColourImpl()52 Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) 53 { 54 CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 55 GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); 56 originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); 57 originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); 58 } 59 use(Colour::Code _colourCode)60 virtual void use( Colour::Code _colourCode ) { 61 switch( _colourCode ) { 62 case Colour::None: return setTextAttribute( originalForegroundAttributes ); 63 case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); 64 case Colour::Red: return setTextAttribute( FOREGROUND_RED ); 65 case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); 66 case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); 67 case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); 68 case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); 69 case Colour::Grey: return setTextAttribute( 0 ); 70 71 case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); 72 case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); 73 case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); 74 case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); 75 76 case Colour::Bright: throw std::logic_error( "not a colour" ); 77 } 78 } 79 80 private: setTextAttribute(WORD _textAttribute)81 void setTextAttribute( WORD _textAttribute ) { 82 SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); 83 } 84 HANDLE stdoutHandle; 85 WORD originalForegroundAttributes; 86 WORD originalBackgroundAttributes; 87 }; 88 platformColourInstance()89 IColourImpl* platformColourInstance() { 90 static Win32ColourImpl s_instance; 91 92 Ptr<IConfig const> config = getCurrentContext().getConfig(); 93 UseColour::YesOrNo colourMode = config 94 ? config->useColour() 95 : UseColour::Auto; 96 if( colourMode == UseColour::Auto ) 97 colourMode = !isDebuggerActive() 98 ? UseColour::Yes 99 : UseColour::No; 100 return colourMode == UseColour::Yes 101 ? &s_instance 102 : NoColourImpl::instance(); 103 } 104 105 } // end anon namespace 106 } // end namespace Catch 107 108 #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// 109 110 #include <unistd.h> 111 112 namespace Catch { 113 namespace { 114 115 // use POSIX/ ANSI console terminal codes 116 // Thanks to Adam Strzelecki for original contribution 117 // (http://github.com/nanoant) 118 // https://github.com/philsquared/Catch/pull/131 119 class PosixColourImpl : public IColourImpl { 120 public: use(Colour::Code _colourCode)121 virtual void use( Colour::Code _colourCode ) { 122 switch( _colourCode ) { 123 case Colour::None: 124 case Colour::White: return setColour( "[0m" ); 125 case Colour::Red: return setColour( "[0;31m" ); 126 case Colour::Green: return setColour( "[0;32m" ); 127 case Colour::Blue: return setColour( "[0;34m" ); 128 case Colour::Cyan: return setColour( "[0;36m" ); 129 case Colour::Yellow: return setColour( "[0;33m" ); 130 case Colour::Grey: return setColour( "[1;30m" ); 131 132 case Colour::LightGrey: return setColour( "[0;37m" ); 133 case Colour::BrightRed: return setColour( "[1;31m" ); 134 case Colour::BrightGreen: return setColour( "[1;32m" ); 135 case Colour::BrightWhite: return setColour( "[1;37m" ); 136 137 case Colour::Bright: throw std::logic_error( "not a colour" ); 138 } 139 } instance()140 static IColourImpl* instance() { 141 static PosixColourImpl s_instance; 142 return &s_instance; 143 } 144 145 private: setColour(const char * _escapeCode)146 void setColour( const char* _escapeCode ) { 147 Catch::cout() << '\033' << _escapeCode; 148 } 149 }; 150 platformColourInstance()151 IColourImpl* platformColourInstance() { 152 ErrnoGuard guard; 153 Ptr<IConfig const> config = getCurrentContext().getConfig(); 154 UseColour::YesOrNo colourMode = config 155 ? config->useColour() 156 : UseColour::Auto; 157 if( colourMode == UseColour::Auto ) 158 colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) 159 ? UseColour::Yes 160 : UseColour::No; 161 return colourMode == UseColour::Yes 162 ? PosixColourImpl::instance() 163 : NoColourImpl::instance(); 164 } 165 166 } // end anon namespace 167 } // end namespace Catch 168 169 #else // not Windows or ANSI /////////////////////////////////////////////// 170 171 namespace Catch { 172 platformColourInstance()173 static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } 174 175 } // end namespace Catch 176 177 #endif // Windows/ ANSI/ None 178 179 namespace Catch { 180 Colour(Code _colourCode)181 Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } Colour(Colour const & _other)182 Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } ~Colour()183 Colour::~Colour(){ if( !m_moved ) use( None ); } 184 use(Code _colourCode)185 void Colour::use( Code _colourCode ) { 186 static IColourImpl* impl = platformColourInstance(); 187 impl->use( _colourCode ); 188 } 189 190 } // end namespace Catch 191 192 #endif // TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED 193