How to Apply ANSI Terminal Colors and Styles Using fmtlib
The {fmt} library provides a type-safe, composable API in include/fmt/color.h for emitting ANSI escape sequences, using fg(), bg(), and emphasis enums combined via the | operator to control terminal colors and text styles.
The fmtlib/fmt repository offers a comprehensive solution for applying ANSI terminal colors and styles using fmtlib through its dedicated color formatting API. The implementation resides primarily in include/fmt/color.h, which extends the core formatting engine defined in include/fmt/format.h to support 24-bit RGB values, 8-bit terminal colors, and text emphasis attributes. All color operations are constexpr-compatible and integrate directly with the library’s existing print and format functions.
Core Color Types and Enums
The color system is built on strongly-typed enums that prevent runtime errors and provide compile-time validation of color values.
RGB and Terminal Color Palettes
The library defines two distinct color enumerations in include/fmt/color.h. The enum class color defines a 24-bit RGB palette where each enumerator stores a 0xRRGGBB hex value (e.g., fmt::color::steel_blue, fmt::color::red). For basic terminal compatibility, the enum class terminal_color provides 8-bit ANSI standard colors ranging from black to bright_white.
Text Emphasis Attributes
Text styling beyond color is handled by the enum class emphasis, a bit-mask enumeration defined at lines 79-86. This supports bold, faint, italic, underline, blink, reverse, conceal, and strikethrough attributes. These flags can be combined using bitwise operations to apply multiple emphasis styles simultaneously.
Internal Representation
The library uses a compact internal structure to store color data efficiently. The struct rgb decodes 24-bit color values into separate R, G, B components, while detail::color_type acts as a bit-packed discriminated union that can represent an unset value, an RGB color, or a terminal color index. This internal representation enables the type-safe composition mechanisms exposed by the public API.
Composing Styles with text_style
The text_style class serves as the primary container for formatting attributes, storing foreground color, background color, and emphasis flags in a single 64-bit integer where specific bit ranges encode each component.
Style Composition Operators
text_style provides an operator|= method (defined at lines 135-182) that safely merges style components. You can combine foreground colors, background colors, and emphasis attributes using the | operator. The implementation actively rejects illegal mixtures—attempting to combine a 24-bit RGB color with an 8-bit terminal color in incompatible ways will fail at compile time or runtime depending on the context.
Factory Functions
The header exposes two factory functions for creating text_style objects:
fg(detail::color_type): Sets the foreground color from either afmt::colororfmt::terminal_colorbg(detail::color_type): Sets the background color using the same color types
These functions return text_style instances that can be further modified or passed directly to output functions.
ANSI Escape Sequence Generation
When processing styled output, the library generates concrete ANSI escape codes through internal helper functions. The detail::make_foreground_color, detail::make_background_color, and detail::make_emphasis functions (located around lines 248-268) construct the appropriate escape sequences.
For RGB colors, the library emits the extended color code format \x1b[38;2;<r>;<g>;<b>m for foreground and \x1b[48;2;<r>;<g>;<b>m for background. Standard emphasis attributes generate codes like \x1b[1m for bold or \x1b[4m for underline. These sequences are automatically prepended to formatted output and terminated with the reset code \x1b[0m to prevent style bleeding.
Output Functions and Styled Arguments
The color API integrates seamlessly with {fmt}'s formatting pipeline through overloaded output functions and specialized formatters.
Global Print Overloads
The library provides overloads of print and println that accept a text_style as the first argument. These functions (defined around lines 278-340) prepend the generated ANSI escape codes, invoke the core formatting engine from include/fmt/format.h, then append the reset sequence. Similarly, vformat_to accepts a text_style parameter for writing to arbitrary output buffers.
Per-Argument Styling
For applying different styles to individual values within a single format string, the library provides the styled() wrapper function. This creates a detail::styled_arg<T> object that the formatter<detail::styled_arg<T>> specialization (lines 522-552) processes by injecting escape codes immediately around the formatted value. This allows mixing styled and unstyled content within one format call without manual string concatenation.
Complete Usage Examples
The following examples demonstrate practical applications of the color API using C++17 or later:
#include <fmt/color.h>
int main() {
// Simple colored output using RGB palette
fmt::print(fg(fmt::color::steel_blue), "Steel blue text\n");
// Combine foreground, background and emphasis attributes
fmt::println(
fmt::emphasis::bold | fmt::fg(fmt::color::red) | fmt::bg(fmt::color::yellow),
"Bold red on yellow");
// Per-argument styling inside a single format string
fmt::print(
"Normal {} {} {}\n",
fmt::styled("red", fmt::fg(fmt::color::red)),
fmt::styled("green", fmt::fg(fmt::color::green) | fmt::emphasis::underline),
fmt::styled("blue", fmt::bg(fmt::color::blue)));
// Using terminal colors (bright variants)
fmt::println(fmt::emphasis::italic | fmt::fg(fmt::terminal_color::bright_magenta),
"Italic bright magenta");
}
Each example compiles with the header-only configuration of {fmt} or when linking against the compiled library. The fg() and bg() functions accept both RGB color values and indexed terminal_color values, while the | operator safely composes multiple style attributes into a single text_style object.
Summary
include/fmt/color.hcontains the complete ANSI color API, includingenum class color,enum class terminal_color, andenum class emphasis.- The
text_styleclass composes foreground/background colors and emphasis flags using the|operator, storing data efficiently in a 64-bit packed format. - Factory functions
fg()andbg()create style objects, whilestyled()enables per-argument formatting within format strings. - Output functions
print,println, andvformat_toaccepttext_stylearguments and automatically manage ANSI escape sequences including reset codes. - The implementation prevents invalid color combinations at the type level, distinguishing between 24-bit RGB values and 8-bit terminal colors.
Frequently Asked Questions
Do I need to compile and link a separate library for color support?
No. All color functionality resides in include/fmt/color.h and works with the header-only configuration of {fmt}. If you prefer using the compiled library, the same headers work with libfmt without additional dependencies.
Can I mix RGB colors with terminal colors in the same style?
No. The text_style class implementation in include/fmt/color.h enforces type safety by rejecting illegal mixtures through its operator|= logic. You must use either 24-bit RGB colors (fmt::color) or 8-bit terminal colors (fmt::terminal_color) consistently within a single foreground or background specification.
How do I apply different styles to individual arguments in one format string?
Use the fmt::styled() wrapper function. It creates a detail::styled_arg<T> that the formatter processes individually, allowing you to write fmt::print("{}", fmt::styled("text", fmt::fg(fmt::color::red))) alongside other arguments with different or no styling.
Are these color operations available at compile time?
Yes. The color enums, text_style composition operations, and rgb struct are all marked constexpr where possible. However, actual output to terminals via fmt::print naturally requires runtime execution.
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 →