How to Use fmt::print for Colored Terminal Output in C++

fmt::print supports colored terminal output by accepting a text_style object as its first argument, which combines foreground/background colors via fg()/bg() helpers and text styles via emphasis flags, automatically generating ANSI escape sequences defined in include/fmt/color.h.

The {fmt} library provides a lightweight, type-safe API for applying colors and text styles to terminal output without manual ANSI escape code management. By leveraging the utilities in include/fmt/color.h, you can use fmt::print to render styled text using a declarative syntax that works across platforms.

Understanding the Color API Architecture

The color system is implemented separately from the core formatting engine in include/fmt/color.h. This design allows the standard {} placeholder syntax to work identically for both plain and styled output.

The header defines several key types:

  • enum class color – A set of named 4-bit terminal colors (e.g., red, green, blue).
  • enum class terminal_color – The underlying terminal color codes.
  • struct rgb – A 24-bit true-color representation using RGB values.
  • emphasis – A flag-type enum providing text styles such as bold, italic, underline, and strikethrough.

When fmt::print receives a text_style value, the library internally instantiates the ansi_color_escape template (lines 366-401 in color.h) to insert the appropriate ANSI escape sequences before the formatted text, followed by a reset_color call (lines 466-468) to restore terminal defaults after output.

Applying Foreground and Background Colors

The fg() and bg() helper functions create text_style objects containing foreground or background colors, respectively. These are defined at lines 348-353 and 353-357 in color.h.

Use predefined colors from the fmt::color enum:

#include <fmt/color.h>
#include <fmt/core.h>

int main() {
    // Red foreground text
    fmt::print(fg(fmt::color::red), "Error: {}\n", "file not found");
    
    // Yellow background with formatted output
    fmt::print(bg(fmt::color::yellow), "Warning code: {}\n", 404);
}

For true-color support, pass an rgb struct with 8-bit channel values:

// Custom RGB foreground (true color)
fmt::print(fg(fmt::rgb{0x12, 0x34, 0xAB}), "Custom color text\n");

Adding Text Emphasis Styles

The emphasis enum provides bitmask flags for text styling. Available options include bold, italic, underline, strikethrough, and reverse.

Apply a single emphasis flag:

// Bold text
fmt::print(fmt::emphasis::bold, "Important message\n");

// Italic text
fmt::print(fmt::emphasis::italic, "Emphasized note\n");

Combining Colors and Styles

Arbitrary styles can be composed using the bitwise OR operator (|). This allows you to mix foreground colors, background colors, and multiple emphasis flags in a single text_style object.

Combine multiple attributes:

// Background color + bold emphasis
fmt::print(bg(fmt::color::yellow) | fmt::emphasis::bold,
           "Warning: low disk space\n");

// Full RGB foreground with italic style
fmt::print(fg(fmt::rgb{0x12, 0x34, 0xAB}) | fmt::emphasis::italic,
           "Custom RGB text\n");

// Complex combination: foreground, background, underline, and bold
fmt::print(fg(fmt::color::green) | bg(fmt::color::black) |
           fmt::emphasis::underline | fmt::emphasis::bold,
           "Success: operation completed\n");

The text_style object created by these compositions is passed as the first argument to fmt::print or fmt::println, immediately followed by the format string and arguments. The library handles all ANSI sequence generation internally through the ansi_color_escape implementation.

Summary

  • Include fmt/color.h to access the color API alongside fmt/core.h.
  • Use fg() and bg() helper functions to set foreground and background colors, supporting both named terminal colors and 24-bit RGB values.
  • Apply text styles via fmt::emphasis flags such as bold, italic, and underline.
  • Compose styles using the bitwise OR operator (|) to combine colors and emphasis before passing to fmt::print.
  • Implementation relies on the ansi_color_escape template in include/fmt/color.h to generate platform-compatible ANSI codes.

Frequently Asked Questions

Does fmt::print automatically detect if the terminal supports colors?

The library generates ANSI escape sequences unconditionally when a text_style is provided. Terminal emulators that do not support ANSI codes will typically display the raw escape sequences or ignore them. For production applications, you may need to implement terminal capability detection separately before constructing color arguments.

Can I use fmt::print with custom RGB colors instead of named colors?

Yes. Pass an rgb struct with three 8-bit values (0-255) to fg() or bg() instead of a fmt::color enum value. This triggers 24-bit true-color ANSI sequences according to the ansi_color_escape<unsigned char> specialization around line 366 in include/fmt/color.h.

How do I reset the color back to default after printing?

You do not need to manually reset colors. The implementation automatically appends a reset sequence after the formatted output using the reset_color helper (lines 466-468 in color.h). This ensures subsequent terminal output returns to default styling regardless of previous fmt::print calls.

What is the difference between color and terminal_color enums?

The color enum provides user-friendly named constants (e.g., red, green) mapped to standard 4-bit ANSI colors. The terminal_color enum exposes the underlying numeric terminal codes directly. Most users should use color for readability, while terminal_color is available for low-level control requiring specific code values.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →