How to Achieve Colored Output Using fmtlib: A Complete Guide to ANSI Styling
Use fmt::print with text_style objects constructed via fg(), bg(), and emphasis flags combined with the | operator.
The {fmt} library provides a built-in, header-only API for ANSI-styled terminal output through include/fmt/color.h. This implementation generates escape sequences at compile time with zero runtime overhead beyond the actual terminal writes.
Understanding the Color System Architecture
The coloring capability in fmtlib centers on three core enumerations and a composable style class.
Color Definitions: enum class color
The color enumeration in include/fmt/color.h defines 256 RGB color values accessible by name:
// Lines 16-38: Named RGB colors
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
crimson = 0xDC143C, // rgb(220,20,60)
// ... 250+ additional named colors
};
These values store raw 24-bit RGB integers. The implementation extracts red, green, and blue components to generate \x1b[38;2;<r>;<g>;<b>m foreground sequences or \x1b[48;2;<r>;<g>;<b>m for backgrounds.
Terminal Colors: enum class terminal_color
For compatibility with limited terminals, include/fmt/color.h provides standard 8/16 color palette mappings:
// Lines 60-77: Standard ANSI terminal colors
enum class terminal_color : uint8_t {
black = 0,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
bright_black = 8,
bright_red,
// ... through bright_white
};
These map to escape codes \x1b[30m through \x1b[37m and \x1b[90m through \x1b[97m for bright variants.
Text Emphasis: enum class emphasis
Style attributes beyond color live in the emphasis enumeration:
// Lines 79-88: Style flags
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
};
These are bitwise flags, enabling combination through |.
Composing Styles with text_style
The text_style class packs foreground, background, and emphasis into a 64-bit value. Located in include/fmt/color.h (lines 35-70), it exposes three key composition functions:
fg(color)orfg(terminal_color)— sets foreground colorbg(color)orbg(terminal_color)— sets background color- Emphasis flags — passed directly and combined with
|
The operator| implementation safely merges styles, rejecting incompatible terminal_color foreground/background combinations that would produce invalid escape sequences.
Internal Escape Sequence Generation
Helper functions in include/fmt/color.h (lines 46-64) convert style specifications to ANSI:
// Simplified view of internal mechanism
namespace detail {
constexpr void make_foreground_color(memory_buffer& buf, color c);
constexpr void make_background_color(memory_buffer& buf, color c);
constexpr void make_emphasis(memory_buffer& buf, emphasis em);
}
All generation is constexpr — escape codes compute at compile time when possible.
Printing with Colored Output
Overloads of fmt::print and fmt::println in include/fmt/color.h (lines 97-125) accept text_style as their first argument. The implementation:
- Creates a temporary buffer
- Writes opening escape sequences for the style
- Invokes
detail::vformat_toto format the payload - Appends reset code
\x1b[0mif the style changed
This automatic reset ensures subsequent output returns to default terminal styling.
Practical Code Examples
Basic Colored Error Message
#include <fmt/color.h>
int main() {
fmt::print(
fmt::emphasis::bold | fmt::fg(fmt::color::red),
"Error: {}\n", "file not found");
}
Output: Bold red "Error:" with plain argument text, then implicit reset.
Complex Style Composition
#include <fmt/color.h>
int main() {
fmt::println(
fmt::emphasis::underline | fmt::emphasis::italic |
fmt::fg(fmt::color::green) | fmt::bg(fmt::color::steel_blue),
"Success: {} items processed", 42);
}
Multiple emphases and full RGB foreground/background combination via chained | operators.
Terminal Palette for Portability
#include <fmt/color.h>
int main() {
fmt::print(
fmt::emphasis::bold | fmt::fg(fmt::terminal_color::bright_yellow),
"Warning: low disk space\n");
}
Use terminal_color when targeting terminals with limited color support.
Header-Only Usage
All colored output functionality requires a single include:
#define FMT_HEADER_ONLY // Optional: forces header-only mode
#include <fmt/color.h>
No library linking required when FMT_HEADER_ONLY is defined. The entire color system resolves at compile time.
Summary
include/fmt/color.hcontains all colored output declarations:color,terminal_color,emphasis,text_style, and style-awarefmt::printoverloads- Style composition uses
fg(),bg(), emphasis flags, and|operator - Escape generation is
constexprwith zero runtime overhead beyond I/O - Automatic reset (
\x1b[0m) ensures clean terminal state after each styled print - Both RGB and terminal palettes supported for broad compatibility
Frequently Asked Questions
Does fmtlib colored output work on Windows?
Yes. {fmt} automatically detects Windows terminals and uses appropriate console APIs when standard ANSI escape sequences aren't supported. The public API remains identical — text_style objects work transparently across platforms.
Can I store and reuse styled formats?
Absolutely. text_style is a lightweight value type (64 bits). Store composed styles in variables:
const auto error_style = fmt::emphasis::bold | fmt::fg(fmt::color::red);
fmt::print(error_style, "First error\n");
fmt::print(error_style, "Second error\n");
How do I disable colors at runtime?
The {fmt} API doesn't provide runtime toggles directly. Implement a wrapper:
void conditional_print(bool use_color, fmt::text_style style,
fmt::string_view fmt, auto&&... args) {
if (use_color) {
fmt::print(style, fmt, std::forward<decltype(args)>(args)...);
} else {
fmt::print(fmt, std::forward<decltype(args)>(args)...);
}
}
Check environment variables like NO_COLOR or terminal capability before calling.
Are 256-color terminal codes supported?
The color enum provides 24-bit RGB values. Terminals supporting 256 colors receive approximate mappings; true-color terminals display exact RGB. For strict 256-color palette control, map RGB values to the 6×6×6 color cube manually or use terminal_color for guaranteed basic support.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →