├── examples ├── stc.hpp ├── basic.cpp ├── modes.cpp ├── simple_term_colors.cpp ├── colors.cpp └── advanced.cpp ├── images ├── banner.png ├── basic.png ├── colors.png ├── modes.png └── advanced.png ├── .gitignore ├── LICENSE ├── README.md └── include └── stc.hpp /examples/stc.hpp: -------------------------------------------------------------------------------- 1 | ../include/stc.hpp -------------------------------------------------------------------------------- /images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illyigan/simple_term_colors/HEAD/images/banner.png -------------------------------------------------------------------------------- /images/basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illyigan/simple_term_colors/HEAD/images/basic.png -------------------------------------------------------------------------------- /images/colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illyigan/simple_term_colors/HEAD/images/colors.png -------------------------------------------------------------------------------- /images/modes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illyigan/simple_term_colors/HEAD/images/modes.png -------------------------------------------------------------------------------- /images/advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/illyigan/simple_term_colors/HEAD/images/advanced.png -------------------------------------------------------------------------------- /examples/basic.cpp: -------------------------------------------------------------------------------- 1 | #include "stc.hpp" 2 | #include 3 | 4 | int main() { 5 | std::cout << stc::rgb_fg(95, 21, 191) << "This text is now purple. " 6 | << stc::reset << "And this text is back to normal.\n"; 7 | return 0; 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | compile_commands.json 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | *.smod 25 | 26 | # Compiled Static libraries 27 | *.lai 28 | *.la 29 | *.a 30 | *.lib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | -------------------------------------------------------------------------------- /examples/modes.cpp: -------------------------------------------------------------------------------- 1 | #include "stc.hpp" 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | using namespace std; 6 | 7 | string mode{}; 8 | if (argc == 2) 9 | mode = argv[1]; 10 | // 256 color mode is set by default 11 | 12 | if (mode == "--no-color") 13 | cout << stc::no_color; 14 | else if (mode == "--true-color") 15 | cout << stc::true_color; 16 | 17 | // no extra logic needed when printing. 18 | cout << stc::rgb_fg(0, 0, 0) << stc::hsl_bg(0.8, 0.3, 0.6) << "Hello!" << stc::reset << '\n'; 19 | return 0; 20 | } -------------------------------------------------------------------------------- /examples/simple_term_colors.cpp: -------------------------------------------------------------------------------- 1 | #include "stc.hpp" 2 | #include 3 | 4 | void print_rainbow(std::string_view text) { 5 | const size_t size = text.length(); 6 | for (size_t i = 0; i < size; i++) { 7 | const auto progress = (float)i / (float)size; 8 | std::cout << stc::hsl_fg(progress, 1, 0.7) << text[i]; 9 | } 10 | std::cout << stc::reset; 11 | } 12 | 13 | int main() { 14 | std::cout << "is a " << stc::bold << "C++17 header-only library " 15 | << stc::reset << "for manipulating "; 16 | print_rainbow("terminal output colors"); 17 | std::cout << " using " << stc::underline << "ANSI escape sequences" 18 | << stc::reset << ".\n"; 19 | return 0; 20 | } -------------------------------------------------------------------------------- /examples/colors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "stc.hpp" 5 | 6 | void print_colors() { 7 | using namespace std; 8 | const int sizei = 15; 9 | const int sizej = sizei * 2; 10 | for (int i = 0; i < sizei; i++) { 11 | for (int k = 0; k < 2; k++) { 12 | if (k == 0) 13 | cout << stc::true_color; 14 | else 15 | cout << stc::color_256; 16 | for (int j = 0; j < sizej; j++) { 17 | const int x = i - (sizei / 2), y = j - (sizej / 2); 18 | const float pi = 3.141593; 19 | const float h = (pi + atan2((float)x, (float)y)) / (2 * pi); 20 | cout << stc::hsl_bg(h, 1, 0.5F) << " "; 21 | } 22 | cout << stc::reset << " "; 23 | } 24 | cout << '\n'; 25 | } 26 | } 27 | 28 | int main() { 29 | print_colors(); 30 | std::cout << "truecolor" << std::setw(33) << "256 color" << '\n'; 31 | return 0; 32 | } -------------------------------------------------------------------------------- /examples/advanced.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "stc.hpp" 3 | 4 | int main() { 5 | using namespace std; 6 | cout << stc::hsl_fg(0.3, 1, 0.5) << "Background and foreground colors can be " << stc::hsl_bg(0.7, 1, 0.5) << "layered over each other." << stc::reset << '\n'; 7 | 8 | constexpr auto my_fav_color = stc::rgb_fg(95, 21, 191); 9 | cout << my_fav_color << "When you provide an HSL or RGB representation of a color, the library will look for a closest match in the 256 color table at compile time.\n" << stc::reset; 10 | static_assert(my_fav_color.code == 55); // passes 11 | 12 | cout << stc::rgb_fg(255, 0, 0) << "This text is red,\n" << stc::reset; 13 | cout << stc::no_color << stc::rgb_fg(255, 0, 0) << "But this isn't because we set the color mode to no-color\n"; 14 | 15 | cout << stc::true_color << stc::hsl_fg(0.55, 0.9, 0.8) << "True color support enabled. See colors.cpp example for better visualisation.\n"; 16 | return 0; 17 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 illyigan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![C++17 header-only library for manipulating terminal output colors using ANSI escape sequences.](images/banner.png) 2 | 3 | # Features 4 | - Support for true color, 256 color and black and white terminals. The type of color escape sequences emitted can be changed at runtime. 5 | - RGB and HSL support. 6 | - Computation is done at compile-time, whenever possible. 7 | - MIT license. 8 | - C++17 required. 9 | 10 | # Usage 11 | ### The library provides the following manipulators: 12 | #### Colors 13 | - `stc::rgb_fg(r, g, b)` sets the foreground color using RGB color model. 14 | - `stc::rgb_bg(r, g, b)` sets the background color using RGB color model. 15 | > r, g, b are integer values and should be in range 0-255. 16 | - `stc::hsl_fg(h, s, l)` sets the foreground color using HSL color model. 17 | - `stc::hsl_bg(h, s, l)` sets the background color using HSL color model. 18 | > h, s, l are float values and should be in range 0-1. 19 | - `stc::code_fg(code)` sets the foreground color using a code. 20 | - `stc::code_bg(code)` sets the background color using a code. 21 | > code is an integer and should be in range 0-255. 22 | 23 | #### Extras 24 | - `stc::reset` resets the output style. 25 | - `stc::reset_fg` resets the output foreground color. 26 | - `stc::reset_bg` resets the output background color. 27 | - `stc::bold` makes the text bold. 28 | - `stc::faint` makes the text faint. 29 | - `stc::italic` makes the text italic. 30 | - `stc::underline` makes the text underlined. 31 | - `stc::inverse` swaps the background and foreground colors. 32 | - `stc::crossed_out` makes the text crossed out. (~~example~~) 33 | > terminal support may vary for some options. 34 | 35 | #### Color modes 36 | - `stc::color_256` sets the color mode to 256 color. (default) 37 | - `stc::true_color` sets the color mode to true color. 38 | - `stc::no_color` disables all color codes from being emitted to the stream. Note: if you set a style before dont forget to use `stc::reset` BEFORE `stc::no_color`, as it will still be visible even after you change the color mode. This mode simply guarantees no color codes will be printed, but it does not erase already existing ones. 39 | > the color mode is set per output stream. 40 | 41 | ### They can be used in the following way: 42 | 43 | ```cpp 44 | cout << stc::true_color; 45 | cout << stc::rgb_fg(255, 0, 255) << "See below for " << stc::bold << "more examples."; 46 | ``` 47 | 48 | # Examples 49 | ## Basic usage 50 | ```cpp 51 | #include "stc.hpp" 52 | #include 53 | 54 | int main() { 55 | std::cout << stc::rgb_fg(95, 21, 191) << "This text is now purple. " 56 | << stc::reset << "And this text is back to normal.\n"; 57 | return 0; 58 | } 59 | ``` 60 | > code: examples/basic.cpp 61 | 62 | ![Example 1](images/basic.png) 63 | 64 | ## Color modes 65 | ```cpp 66 | #include "stc.hpp" 67 | #include 68 | 69 | int main(int argc, char **argv) { 70 | using namespace std; 71 | 72 | string mode{}; 73 | if (argc == 2) 74 | mode = argv[1]; 75 | // 256 color mode is set by default 76 | 77 | if (mode == "--no-color") 78 | cout << stc::no_color; 79 | else if (mode == "--true-color") 80 | cout << stc::true_color; 81 | 82 | // no extra logic needed when printing. 83 | cout << stc::rgb_fg(0, 0, 0) << stc::hsl_bg(0.8, 0.3, 0.6) << "Hello!" << stc::reset << '\n'; 84 | return 0; 85 | } 86 | ``` 87 | > code: examples/modes.cpp 88 | 89 | ![Example 2](images/modes.png) 90 | 91 | ## Advanced usage 92 | ```cpp 93 | #include 94 | #include "stc.hpp" 95 | 96 | int main() { 97 | using namespace std; 98 | cout << stc::hsl_fg(0.3, 1, 0.5) << "Background and foreground colors can be " << stc::hsl_bg(0.7, 1, 0.5) << "layered over each other." << stc::reset << '\n'; 99 | 100 | constexpr auto my_fav_color = stc::rgb_fg(95, 21, 191); 101 | cout << my_fav_color << "When you provide an HSL or RGB representation of a color, the library will look for a closest match in the 256 color table at compile time.\n" << stc::reset; 102 | static_assert(my_fav_color.code == 55); // passes 103 | 104 | cout << stc::rgb_fg(255, 0, 0) << "This text is red,\n" << stc::reset; 105 | cout << stc::no_color << stc::rgb_fg(255, 0, 0) << "But this isn't because we set the color mode to no-color\n"; 106 | 107 | cout << stc::true_color << stc::hsl_fg(0.55, 0.9, 0.8) << "True color support enabled. See colors.cpp example for better visualisation.\n"; 108 | return 0; 109 | } 110 | ``` 111 | > code: examples/advanced.cpp 112 | 113 | ![Example 3](images/advanced.png) 114 | 115 | ## Color wheels 116 | ```cpp 117 | #include 118 | #include 119 | 120 | #include "stc.hpp" 121 | 122 | void print_colors() { 123 | using namespace std; 124 | const int sizei = 15; 125 | const int sizej = sizei * 2; 126 | for (int i = 0; i < sizei; i++) { 127 | for (int k = 0; k < 2; k++) { 128 | if (k == 0) 129 | cout << stc::true_color; 130 | else 131 | cout << stc::color_256; 132 | for (int j = 0; j < sizej; j++) { 133 | const int x = i - (sizei / 2), y = j - (sizej / 2); 134 | const float pi = 3.141593; 135 | const float h = (pi + atan2((float)x, (float)y)) / (2 * pi); 136 | cout << stc::hsl_bg(h, 1, 0.5F) << " "; 137 | } 138 | cout << stc::reset << " "; 139 | } 140 | cout << '\n'; 141 | } 142 | } 143 | 144 | int main() { 145 | print_colors(); 146 | std::cout << "truecolor" << std::setw(33) << "256 color" << '\n'; 147 | return 0; 148 | } 149 | ``` 150 | > code: examples/colors.cpp 151 | 152 | ![Example 4](images/colors.png) 153 | 154 | ## Demo 155 | ```cpp 156 | #include "stc.hpp" 157 | #include 158 | 159 | void print_rainbow(std::string_view text) { 160 | const size_t size = text.length(); 161 | for (size_t i = 0; i < size; i++) { 162 | const auto progress = (float)i / (float)size; 163 | std::cout << stc::hsl_fg(progress, 1, 0.7) << text[i]; 164 | } 165 | std::cout << stc::reset; 166 | } 167 | 168 | int main() { 169 | std::cout << "is a " << stc::bold << "C++17 header-only library " 170 | << stc::reset << "for manipulating "; 171 | print_rainbow("terminal output colors"); 172 | std::cout << " using " << stc::underline << "ANSI escape sequences" 173 | << stc::reset << ".\n"; 174 | return 0; 175 | } 176 | ``` 177 | > code: examples/simple_term_colors.cpp 178 | 179 | ![Example 5](images/banner.png) -------------------------------------------------------------------------------- /include/stc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | 4 | Copyright (c) 2024 illyigan 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | */ 24 | 25 | #pragma once 26 | #include 27 | 28 | namespace stc { 29 | 30 | enum _color_modes { COLOR_256 = 0, TRUE_COLOR = 1, NO_COLOR = 2 }; 31 | 32 | inline int _get_color_mode_index() { 33 | static const int i = std::ios_base::xalloc(); 34 | return i; 35 | } 36 | 37 | class _color_data { 38 | public: 39 | unsigned int r : 8, g : 8, b : 8, code : 8; 40 | constexpr _color_data(int r, int g, int b, int code) 41 | : r(r), g(g), b(b), code(code){}; 42 | }; 43 | 44 | template class _color_code : public _color_data { 45 | using _color_data::_color_data; 46 | }; 47 | 48 | // foreground 49 | inline std::ostream &operator<<(std::ostream &os, 50 | const _color_code &color_code) { 51 | const long mode = os.iword(_get_color_mode_index()); 52 | if (mode == _color_modes::COLOR_256) 53 | os << "\033[38;5;" << color_code.code << 'm'; 54 | else if (mode == _color_modes::TRUE_COLOR) 55 | os << "\033[38;2;" << color_code.r << ';' << color_code.g << ';' 56 | << color_code.b << 'm'; 57 | return os; 58 | } 59 | 60 | // background 61 | inline std::ostream &operator<<(std::ostream &os, 62 | const _color_code &color_code) { 63 | const long mode = os.iword(_get_color_mode_index()); 64 | if (mode == _color_modes::COLOR_256) 65 | os << "\033[48;5;" << color_code.code << 'm'; 66 | else if (mode == _color_modes::TRUE_COLOR) 67 | os << "\033[48;2;" << color_code.r << ';' << color_code.g << ';' 68 | << color_code.b << 'm'; 69 | return os; 70 | } 71 | 72 | constexpr const _color_data _256colors[256] = { 73 | _color_data{0, 0, 0, 0 /*Black(SYSTEM)*/}, 74 | _color_data{128, 0, 0, 1 /*Maroon(SYSTEM)*/}, 75 | _color_data{0, 128, 0, 2 /*Green(SYSTEM)*/}, 76 | _color_data{128, 128, 0, 3 /*Olive(SYSTEM)*/}, 77 | _color_data{0, 0, 128, 4 /*Navy(SYSTEM)*/}, 78 | _color_data{128, 0, 128, 5 /*Purple(SYSTEM)*/}, 79 | _color_data{0, 128, 128, 6 /*Teal(SYSTEM)*/}, 80 | _color_data{192, 192, 192, 7 /*Silver(SYSTEM)*/}, 81 | _color_data{128, 128, 128, 8 /*Grey(SYSTEM)*/}, 82 | _color_data{255, 0, 0, 9 /*Red(SYSTEM)*/}, 83 | _color_data{0, 255, 0, 10 /*Lime(SYSTEM)*/}, 84 | _color_data{255, 255, 0, 11 /*Yellow(SYSTEM)*/}, 85 | _color_data{0, 0, 255, 12 /*Blue(SYSTEM)*/}, 86 | _color_data{255, 0, 255, 13 /*Fuchsia(SYSTEM)*/}, 87 | _color_data{0, 255, 255, 14 /*Aqua(SYSTEM)*/}, 88 | _color_data{255, 255, 255, 15 /*White(SYSTEM)*/}, 89 | _color_data{0, 0, 0, 16 /*Grey0*/}, 90 | _color_data{0, 0, 95, 17 /*NavyBlue*/}, 91 | _color_data{0, 0, 135, 18 /*DarkBlue*/}, 92 | _color_data{0, 0, 175, 19 /*Blue3*/}, 93 | _color_data{0, 0, 215, 20 /*Blue3*/}, 94 | _color_data{0, 0, 255, 21 /*Blue1*/}, 95 | _color_data{0, 95, 0, 22 /*DarkGreen*/}, 96 | _color_data{0, 95, 95, 23 /*DeepSkyBlue4*/}, 97 | _color_data{0, 95, 135, 24 /*DeepSkyBlue4*/}, 98 | _color_data{0, 95, 175, 25 /*DeepSkyBlue4*/}, 99 | _color_data{0, 95, 215, 26 /*DodgerBlue3*/}, 100 | _color_data{0, 95, 255, 27 /*DodgerBlue2*/}, 101 | _color_data{0, 135, 0, 28 /*Green4*/}, 102 | _color_data{0, 135, 95, 29 /*SpringGreen4*/}, 103 | _color_data{0, 135, 135, 30 /*Turquoise4*/}, 104 | _color_data{0, 135, 175, 31 /*DeepSkyBlue3*/}, 105 | _color_data{0, 135, 215, 32 /*DeepSkyBlue3*/}, 106 | _color_data{0, 135, 255, 33 /*DodgerBlue1*/}, 107 | _color_data{0, 175, 0, 34 /*Green3*/}, 108 | _color_data{0, 175, 95, 35 /*SpringGreen3*/}, 109 | _color_data{0, 175, 135, 36 /*DarkCyan*/}, 110 | _color_data{0, 175, 175, 37 /*LightSeaGreen*/}, 111 | _color_data{0, 175, 215, 38 /*DeepSkyBlue2*/}, 112 | _color_data{0, 175, 255, 39 /*DeepSkyBlue1*/}, 113 | _color_data{0, 215, 0, 40 /*Green3*/}, 114 | _color_data{0, 215, 95, 41 /*SpringGreen3*/}, 115 | _color_data{0, 215, 135, 42 /*SpringGreen2*/}, 116 | _color_data{0, 215, 175, 43 /*Cyan3*/}, 117 | _color_data{0, 215, 215, 44 /*DarkTurquoise*/}, 118 | _color_data{0, 215, 255, 45 /*Turquoise2*/}, 119 | _color_data{0, 255, 0, 46 /*Green1*/}, 120 | _color_data{0, 255, 95, 47 /*SpringGreen2*/}, 121 | _color_data{0, 255, 135, 48 /*SpringGreen1*/}, 122 | _color_data{0, 255, 175, 49 /*MediumSpringGreen*/}, 123 | _color_data{0, 255, 215, 50 /*Cyan2*/}, 124 | _color_data{0, 255, 255, 51 /*Cyan1*/}, 125 | _color_data{95, 0, 0, 52 /*DarkRed*/}, 126 | _color_data{95, 0, 95, 53 /*DeepPink4*/}, 127 | _color_data{95, 0, 135, 54 /*Purple4*/}, 128 | _color_data{95, 0, 175, 55 /*Purple4*/}, 129 | _color_data{95, 0, 215, 56 /*Purple3*/}, 130 | _color_data{95, 0, 255, 57 /*BlueViolet*/}, 131 | _color_data{95, 95, 0, 58 /*Orange4*/}, 132 | _color_data{95, 95, 95, 59 /*Grey37*/}, 133 | _color_data{95, 95, 135, 60 /*MediumPurple4*/}, 134 | _color_data{95, 95, 175, 61 /*SlateBlue3*/}, 135 | _color_data{95, 95, 215, 62 /*SlateBlue3*/}, 136 | _color_data{95, 95, 255, 63 /*RoyalBlue1*/}, 137 | _color_data{95, 135, 0, 64 /*Chartreuse4*/}, 138 | _color_data{95, 135, 95, 65 /*DarkSeaGreen4*/}, 139 | _color_data{95, 135, 135, 66 /*PaleTurquoise4*/}, 140 | _color_data{95, 135, 175, 67 /*SteelBlue*/}, 141 | _color_data{95, 135, 215, 68 /*SteelBlue3*/}, 142 | _color_data{95, 135, 255, 69 /*CornflowerBlue*/}, 143 | _color_data{95, 175, 0, 70 /*Chartreuse3*/}, 144 | _color_data{95, 175, 95, 71 /*DarkSeaGreen4*/}, 145 | _color_data{95, 175, 135, 72 /*CadetBlue*/}, 146 | _color_data{95, 175, 175, 73 /*CadetBlue*/}, 147 | _color_data{95, 175, 215, 74 /*SkyBlue3*/}, 148 | _color_data{95, 175, 255, 75 /*SteelBlue1*/}, 149 | _color_data{95, 215, 0, 76 /*Chartreuse3*/}, 150 | _color_data{95, 215, 95, 77 /*PaleGreen3*/}, 151 | _color_data{95, 215, 135, 78 /*SeaGreen3*/}, 152 | _color_data{95, 215, 175, 79 /*Aquamarine3*/}, 153 | _color_data{95, 215, 215, 80 /*MediumTurquoise*/}, 154 | _color_data{95, 215, 255, 81 /*SteelBlue1*/}, 155 | _color_data{95, 255, 0, 82 /*Chartreuse2*/}, 156 | _color_data{95, 255, 95, 83 /*SeaGreen2*/}, 157 | _color_data{95, 255, 135, 84 /*SeaGreen1*/}, 158 | _color_data{95, 255, 175, 85 /*SeaGreen1*/}, 159 | _color_data{95, 255, 215, 86 /*Aquamarine1*/}, 160 | _color_data{95, 255, 255, 87 /*DarkSlateGray2*/}, 161 | _color_data{135, 0, 0, 88 /*DarkRed*/}, 162 | _color_data{135, 0, 95, 89 /*DeepPink4*/}, 163 | _color_data{135, 0, 135, 90 /*DarkMagenta*/}, 164 | _color_data{135, 0, 175, 91 /*DarkMagenta*/}, 165 | _color_data{135, 0, 215, 92 /*DarkViolet*/}, 166 | _color_data{135, 0, 255, 93 /*Purple*/}, 167 | _color_data{135, 95, 0, 94 /*Orange4*/}, 168 | _color_data{135, 95, 95, 95 /*LightPink4*/}, 169 | _color_data{135, 95, 135, 96 /*Plum4*/}, 170 | _color_data{135, 95, 175, 97 /*MediumPurple3*/}, 171 | _color_data{135, 95, 215, 98 /*MediumPurple3*/}, 172 | _color_data{135, 95, 255, 99 /*SlateBlue1*/}, 173 | _color_data{135, 135, 0, 100 /*Yellow4*/}, 174 | _color_data{135, 135, 95, 101 /*Wheat4*/}, 175 | _color_data{135, 135, 135, 102 /*Grey53*/}, 176 | _color_data{135, 135, 175, 103 /*LightSlateGrey*/}, 177 | _color_data{135, 135, 215, 104 /*MediumPurple*/}, 178 | _color_data{135, 135, 255, 105 /*LightSlateBlue*/}, 179 | _color_data{135, 175, 0, 106 /*Yellow4*/}, 180 | _color_data{135, 175, 95, 107 /*DarkOliveGreen3*/}, 181 | _color_data{135, 175, 135, 108 /*DarkSeaGreen*/}, 182 | _color_data{135, 175, 175, 109 /*LightSkyBlue3*/}, 183 | _color_data{135, 175, 215, 110 /*LightSkyBlue3*/}, 184 | _color_data{135, 175, 255, 111 /*SkyBlue2*/}, 185 | _color_data{135, 215, 0, 112 /*Chartreuse2*/}, 186 | _color_data{135, 215, 95, 113 /*DarkOliveGreen3*/}, 187 | _color_data{135, 215, 135, 114 /*PaleGreen3*/}, 188 | _color_data{135, 215, 175, 115 /*DarkSeaGreen3*/}, 189 | _color_data{135, 215, 215, 116 /*DarkSlateGray3*/}, 190 | _color_data{135, 215, 255, 117 /*SkyBlue1*/}, 191 | _color_data{135, 255, 0, 118 /*Chartreuse1*/}, 192 | _color_data{135, 255, 95, 119 /*LightGreen*/}, 193 | _color_data{135, 255, 135, 120 /*LightGreen*/}, 194 | _color_data{135, 255, 175, 121 /*PaleGreen1*/}, 195 | _color_data{135, 255, 215, 122 /*Aquamarine1*/}, 196 | _color_data{135, 255, 255, 123 /*DarkSlateGray1*/}, 197 | _color_data{175, 0, 0, 124 /*Red3*/}, 198 | _color_data{175, 0, 95, 125 /*DeepPink4*/}, 199 | _color_data{175, 0, 135, 126 /*MediumVioletRed*/}, 200 | _color_data{175, 0, 175, 127 /*Magenta3*/}, 201 | _color_data{175, 0, 215, 128 /*DarkViolet*/}, 202 | _color_data{175, 0, 255, 129 /*Purple*/}, 203 | _color_data{175, 95, 0, 130 /*DarkOrange3*/}, 204 | _color_data{175, 95, 95, 131 /*IndianRed*/}, 205 | _color_data{175, 95, 135, 132 /*HotPink3*/}, 206 | _color_data{175, 95, 175, 133 /*MediumOrchid3*/}, 207 | _color_data{175, 95, 215, 134 /*MediumOrchid*/}, 208 | _color_data{175, 95, 255, 135 /*MediumPurple2*/}, 209 | _color_data{175, 135, 0, 136 /*DarkGoldenrod*/}, 210 | _color_data{175, 135, 95, 137 /*LightSalmon3*/}, 211 | _color_data{175, 135, 135, 138 /*RosyBrown*/}, 212 | _color_data{175, 135, 175, 139 /*Grey63*/}, 213 | _color_data{175, 135, 215, 140 /*MediumPurple2*/}, 214 | _color_data{175, 135, 255, 141 /*MediumPurple1*/}, 215 | _color_data{175, 175, 0, 142 /*Gold3*/}, 216 | _color_data{175, 175, 95, 143 /*DarkKhaki*/}, 217 | _color_data{175, 175, 135, 144 /*NavajoWhite3*/}, 218 | _color_data{175, 175, 175, 145 /*Grey69*/}, 219 | _color_data{175, 175, 215, 146 /*LightSteelBlue3*/}, 220 | _color_data{175, 175, 255, 147 /*LightSteelBlue*/}, 221 | _color_data{175, 215, 0, 148 /*Yellow3*/}, 222 | _color_data{175, 215, 95, 149 /*DarkOliveGreen3*/}, 223 | _color_data{175, 215, 135, 150 /*DarkSeaGreen3*/}, 224 | _color_data{175, 215, 175, 151 /*DarkSeaGreen2*/}, 225 | _color_data{175, 215, 215, 152 /*LightCyan3*/}, 226 | _color_data{175, 215, 255, 153 /*LightSkyBlue1*/}, 227 | _color_data{175, 255, 0, 154 /*GreenYellow*/}, 228 | _color_data{175, 255, 95, 155 /*DarkOliveGreen2*/}, 229 | _color_data{175, 255, 135, 156 /*PaleGreen1*/}, 230 | _color_data{175, 255, 175, 157 /*DarkSeaGreen2*/}, 231 | _color_data{175, 255, 215, 158 /*DarkSeaGreen1*/}, 232 | _color_data{175, 255, 255, 159 /*PaleTurquoise1*/}, 233 | _color_data{215, 0, 0, 160 /*Red3*/}, 234 | _color_data{215, 0, 95, 161 /*DeepPink3*/}, 235 | _color_data{215, 0, 135, 162 /*DeepPink3*/}, 236 | _color_data{215, 0, 175, 163 /*Magenta3*/}, 237 | _color_data{215, 0, 215, 164 /*Magenta3*/}, 238 | _color_data{215, 0, 255, 165 /*Magenta2*/}, 239 | _color_data{215, 95, 0, 166 /*DarkOrange3*/}, 240 | _color_data{215, 95, 95, 167 /*IndianRed*/}, 241 | _color_data{215, 95, 135, 168 /*HotPink3*/}, 242 | _color_data{215, 95, 175, 169 /*HotPink2*/}, 243 | _color_data{215, 95, 215, 170 /*Orchid*/}, 244 | _color_data{215, 95, 255, 171 /*MediumOrchid1*/}, 245 | _color_data{215, 135, 0, 172 /*Orange3*/}, 246 | _color_data{215, 135, 95, 173 /*LightSalmon3*/}, 247 | _color_data{215, 135, 135, 174 /*LightPink3*/}, 248 | _color_data{215, 135, 175, 175 /*Pink3*/}, 249 | _color_data{215, 135, 215, 176 /*Plum3*/}, 250 | _color_data{215, 135, 255, 177 /*Violet*/}, 251 | _color_data{215, 175, 0, 178 /*Gold3*/}, 252 | _color_data{215, 175, 95, 179 /*LightGoldenrod3*/}, 253 | _color_data{215, 175, 135, 180 /*Tan*/}, 254 | _color_data{215, 175, 175, 181 /*MistyRose3*/}, 255 | _color_data{215, 175, 215, 182 /*Thistle3*/}, 256 | _color_data{215, 175, 255, 183 /*Plum2*/}, 257 | _color_data{215, 215, 0, 184 /*Yellow3*/}, 258 | _color_data{215, 215, 95, 185 /*Khaki3*/}, 259 | _color_data{215, 215, 135, 186 /*LightGoldenrod2*/}, 260 | _color_data{215, 215, 175, 187 /*LightYellow3*/}, 261 | _color_data{215, 215, 215, 188 /*Grey84*/}, 262 | _color_data{215, 215, 255, 189 /*LightSteelBlue1*/}, 263 | _color_data{215, 255, 0, 190 /*Yellow2*/}, 264 | _color_data{215, 255, 95, 191 /*DarkOliveGreen1*/}, 265 | _color_data{215, 255, 135, 192 /*DarkOliveGreen1*/}, 266 | _color_data{215, 255, 175, 193 /*DarkSeaGreen1*/}, 267 | _color_data{215, 255, 215, 194 /*Honeydew2*/}, 268 | _color_data{215, 255, 255, 195 /*LightCyan1*/}, 269 | _color_data{255, 0, 0, 196 /*Red1*/}, 270 | _color_data{255, 0, 95, 197 /*DeepPink2*/}, 271 | _color_data{255, 0, 135, 198 /*DeepPink1*/}, 272 | _color_data{255, 0, 175, 199 /*DeepPink1*/}, 273 | _color_data{255, 0, 215, 200 /*Magenta2*/}, 274 | _color_data{255, 0, 255, 201 /*Magenta1*/}, 275 | _color_data{255, 95, 0, 202 /*OrangeRed1*/}, 276 | _color_data{255, 95, 95, 203 /*IndianRed1*/}, 277 | _color_data{255, 95, 135, 204 /*IndianRed1*/}, 278 | _color_data{255, 95, 175, 205 /*HotPink*/}, 279 | _color_data{255, 95, 215, 206 /*HotPink*/}, 280 | _color_data{255, 95, 255, 207 /*MediumOrchid1*/}, 281 | _color_data{255, 135, 0, 208 /*DarkOrange*/}, 282 | _color_data{255, 135, 95, 209 /*Salmon1*/}, 283 | _color_data{255, 135, 135, 210 /*LightCoral*/}, 284 | _color_data{255, 135, 175, 211 /*PaleVioletRed1*/}, 285 | _color_data{255, 135, 215, 212 /*Orchid2*/}, 286 | _color_data{255, 135, 255, 213 /*Orchid1*/}, 287 | _color_data{255, 175, 0, 214 /*Orange1*/}, 288 | _color_data{255, 175, 95, 215 /*SandyBrown*/}, 289 | _color_data{255, 175, 135, 216 /*LightSalmon1*/}, 290 | _color_data{255, 175, 175, 217 /*LightPink1*/}, 291 | _color_data{255, 175, 215, 218 /*Pink1*/}, 292 | _color_data{255, 175, 255, 219 /*Plum1*/}, 293 | _color_data{255, 215, 0, 220 /*Gold1*/}, 294 | _color_data{255, 215, 95, 221 /*LightGoldenrod2*/}, 295 | _color_data{255, 215, 135, 222 /*LightGoldenrod2*/}, 296 | _color_data{255, 215, 175, 223 /*NavajoWhite1*/}, 297 | _color_data{255, 215, 215, 224 /*MistyRose1*/}, 298 | _color_data{255, 215, 255, 225 /*Thistle1*/}, 299 | _color_data{255, 255, 0, 226 /*Yellow1*/}, 300 | _color_data{255, 255, 95, 227 /*LightGoldenrod1*/}, 301 | _color_data{255, 255, 135, 228 /*Khaki1*/}, 302 | _color_data{255, 255, 175, 229 /*Wheat1*/}, 303 | _color_data{255, 255, 215, 230 /*Cornsilk1*/}, 304 | _color_data{255, 255, 255, 231 /*Grey100*/}, 305 | _color_data{8, 8, 8, 232 /*Grey3*/}, 306 | _color_data{18, 18, 18, 233 /*Grey7*/}, 307 | _color_data{28, 28, 28, 234 /*Grey11*/}, 308 | _color_data{38, 38, 38, 235 /*Grey15*/}, 309 | _color_data{48, 48, 48, 236 /*Grey19*/}, 310 | _color_data{58, 58, 58, 237 /*Grey23*/}, 311 | _color_data{68, 68, 68, 238 /*Grey27*/}, 312 | _color_data{78, 78, 78, 239 /*Grey30*/}, 313 | _color_data{88, 88, 88, 240 /*Grey35*/}, 314 | _color_data{98, 98, 98, 241 /*Grey39*/}, 315 | _color_data{108, 108, 108, 242 /*Grey42*/}, 316 | _color_data{118, 118, 118, 243 /*Grey46*/}, 317 | _color_data{128, 128, 128, 244 /*Grey50*/}, 318 | _color_data{138, 138, 138, 245 /*Grey54*/}, 319 | _color_data{148, 148, 148, 246 /*Grey58*/}, 320 | _color_data{158, 158, 158, 247 /*Grey62*/}, 321 | _color_data{168, 168, 168, 248 /*Grey66*/}, 322 | _color_data{178, 178, 178, 249 /*Grey70*/}, 323 | _color_data{188, 188, 188, 250 /*Grey74*/}, 324 | _color_data{198, 198, 198, 251 /*Grey78*/}, 325 | _color_data{208, 208, 208, 252 /*Grey82*/}, 326 | _color_data{218, 218, 218, 253 /*Grey85*/}, 327 | _color_data{228, 228, 228, 254 /*Grey89*/}, 328 | _color_data{238, 238, 238, 255 /*Grey93*/}}; 329 | 330 | constexpr float _color_distance(int r, int g, int b, _color_data color) { 331 | // approximate color distance using redmean 332 | // (https://en.wikipedia.org/wiki/Color_difference) 333 | const auto red_difference = (float)(color.r - r); 334 | const auto green_difference = (float)(color.g - g); 335 | const auto blue_difference = (float)(color.b - b); 336 | const float red_average = (float)(r + color.r) / 2.0F; 337 | return ((2 + (red_average / 256)) * (red_difference * red_difference)) + 338 | (4 * (green_difference * green_difference)) + 339 | ((2 + ((255 - red_average) / 256)) * 340 | (blue_difference * blue_difference)); 341 | } 342 | 343 | constexpr int _find_closest_color_code(int r, int g, int b) { 344 | // for dark colors we return black, the cutoff values are arbitrary but 345 | // prevent artifacting from redmean color distance approximation 346 | if (r < 20 && g < 15 && b < 15) 347 | return _256colors[16].code; 348 | // we start at index 16, because colors 0 - 16 are system colors (terminal 349 | // emulators often define custom values for these) 350 | size_t best_index = 16; 351 | for (size_t i = best_index; i < 256; i++) { 352 | if (_color_distance(r, g, b, _256colors[i]) < 353 | _color_distance(r, g, b, _256colors[best_index])) 354 | best_index = i; 355 | } 356 | return _256colors[best_index].code; 357 | } 358 | 359 | constexpr void _hsl_to_rgb(float h, float s, float l, int &r, int &g, int &b) { 360 | auto fmod = [](float number, int divisor) { 361 | const int i = (int)number; 362 | return (float)(i % divisor) + (number - (float)i); 363 | }; 364 | auto round = [](float number) { 365 | const int i = (int)number; 366 | if (number - (float)i >= 0.5) 367 | return i + 1; 368 | return i; 369 | }; 370 | 371 | // (https://en.wikipedia.org/wiki/HSL_and_HSV#Color_conversion_formulae) 372 | if (s == 0) { 373 | r = g = b = round(l * 255); 374 | return; 375 | } 376 | const float alpha = s * std::min(l, 1 - l); 377 | auto f = [=](float n) { 378 | const float k = fmod((n + (h * 12)), 12); 379 | return l - (alpha * std::max(-1.0F, std::min({k - 3, 9 - k, 1.0F}))); 380 | }; 381 | r = round(f(0) * 255); 382 | g = round(f(8) * 255); 383 | b = round(f(4) * 255); 384 | } 385 | 386 | constexpr void _clamp(int &a, int min, int max) { 387 | if (a < min) 388 | a = min; 389 | else if (a > max) 390 | a = max; 391 | } 392 | 393 | constexpr void _clamp_rgb(int &r, int &g, int &b) { 394 | _clamp(r, 0, 255); 395 | _clamp(g, 0, 255); 396 | _clamp(b, 0, 255); 397 | } 398 | 399 | inline std::ostream &_print_if_color(std::ostream &os, std::string_view text) { 400 | const auto mode = os.iword(_get_color_mode_index()); 401 | if (mode != _color_modes::NO_COLOR) 402 | return os << text; 403 | return os; 404 | } 405 | 406 | inline std::ostream &color_256(std::ostream &os) { 407 | os.iword(_get_color_mode_index()) = _color_modes::COLOR_256; 408 | return os; 409 | } 410 | inline std::ostream &true_color(std::ostream &os) { 411 | os.iword(_get_color_mode_index()) = _color_modes::TRUE_COLOR; 412 | return os; 413 | } 414 | inline std::ostream &no_color(std::ostream &os) { 415 | os.iword(_get_color_mode_index()) = _color_modes::NO_COLOR; 416 | return os; 417 | } 418 | 419 | inline std::ostream &reset(std::ostream &os) { 420 | return _print_if_color(os, "\033[0m"); 421 | } 422 | inline std::ostream &bold(std::ostream &os) { 423 | return _print_if_color(os, "\033[1m"); 424 | } 425 | inline std::ostream &faint(std::ostream &os) { 426 | return _print_if_color(os, "\033[2m"); 427 | } 428 | inline std::ostream &italic(std::ostream &os) { 429 | return _print_if_color(os, "\033[3m"); 430 | } 431 | inline std::ostream &underline(std::ostream &os) { 432 | return _print_if_color(os, "\033[4m"); 433 | } 434 | inline std::ostream &inverse(std::ostream &os) { 435 | return _print_if_color(os, "\033[7m"); 436 | } 437 | inline std::ostream &crossed_out(std::ostream &os) { 438 | return _print_if_color(os, "\033[9m"); 439 | } 440 | inline std::ostream &reset_fg(std::ostream &os) { 441 | return _print_if_color(os, "\033[39m"); 442 | } 443 | inline std::ostream &reset_bg(std::ostream &os) { 444 | return _print_if_color(os, "\033[49m"); 445 | } 446 | 447 | constexpr _color_code rgb_fg(int r, int g, int b) { 448 | _clamp_rgb(r, g, b); 449 | return {r, g, b, _find_closest_color_code(r, g, b)}; 450 | } 451 | 452 | constexpr _color_code rgb_bg(int r, int g, int b) { 453 | _clamp_rgb(r, g, b); 454 | return {r, g, b, _find_closest_color_code(r, g, b)}; 455 | } 456 | 457 | constexpr _color_code hsl_fg(float h, float s, float l) { 458 | int r = 0, g = 0, b = 0; 459 | _hsl_to_rgb(h, s, l, r, g, b); 460 | _clamp_rgb(r, g, b); 461 | return {r, g, b, _find_closest_color_code(r, g, b)}; 462 | } 463 | 464 | constexpr _color_code hsl_bg(float h, float s, float l) { 465 | int r = 0, g = 0, b = 0; 466 | _hsl_to_rgb(h, s, l, r, g, b); 467 | _clamp_rgb(r, g, b); 468 | return {r, g, b, _find_closest_color_code(r, g, b)}; 469 | } 470 | 471 | constexpr _color_code code_fg(int code) { 472 | _clamp(code, 0, 255); 473 | const auto color_data = _256colors[code]; 474 | return {color_data.r, color_data.g, color_data.b, color_data.code}; 475 | } 476 | 477 | constexpr _color_code code_bg(int code) { 478 | _clamp(code, 0, 255); 479 | const auto color_data = _256colors[code]; 480 | return {color_data.r, color_data.g, color_data.b, color_data.code}; 481 | } 482 | 483 | } // namespace stc 484 | --------------------------------------------------------------------------------