Serenity Operating System
1# String Formatting
2
3Many places in Serenity allow you to format strings, similar to `printf()`, for example `DeprecatedString::formatted()`
4, `StringBuilder::appendff()`, or `dbgln()`. These are checked at compile time to ensure the format string matches the
5number of parameters. The syntax is largely based on
6the [C++ `std::formatter` syntax](https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification)
7but there are some differences.
8
9For basic usage, any occurrences of `{}` in the format string are replaced with the other arguments, converted to string
10form, in order:
11
12```c++
13DeprecatedString::formatted("Well, {} my {} friends!", "hello", 42) == "Well, hello my 42 friends!";
14```
15
16If you want to include a literal `{` in the output, use `{{`:
17
18```c++
19DeprecatedString::formatted("{{ {}", "hello") == "{ hello";
20```
21
22You can refer to the arguments by index, if you want to repeat one or change the order:
23
24```c++
25DeprecatedString::formatted("{2}{0}{1}", "a", "b", "c") == "cab";
26```
27
28To control how the arguments are formatted, add colon after the optional index, and then add format specifier
29characters:
30
31```c++
32DeprecatedString::formatted("{:.4}", "cool dude") == "cool";
33DeprecatedString::formatted("{0:.4}", "cool dude") == "cool";
34```
35
36## Format specifiers
37
38In order, the format can contain:
39
40- Fill character and alignment
41- Sign
42- `#` Hash
43- `0` Zero
44- Width
45- Precision
46- Type specifier
47
48Each of these is optional. You can include any combination of them, but they must be in this order.
49
50### Fill and alignment
51
52This is an optional fill character, followed by an alignment. The fill character can be anything apart from `{` or `}`,
53and is used to fill any space left when the input has fewer characters than the format requests. By default, it is a
54space. (` `)
55
56The alignment characters are:
57
58- `<`: Align left.
59- `>`: Align right.
60- `^`: Align centered.
61
62### Sign
63
64- `+`: Always display a sign before the number.
65- `-`: Display a sign for negative numbers only.
66- (space): Display a sign for negative numbers, and a leading space for other numbers.
67
68### Hash
69
70`#` causes an "alternate form" to be used.
71
72For integer types, this adds the number-base prefix after the sign:
73
74- `0b` for binary.
75- `0` for octal.
76- `0x` for hexadecimal.
77
78### Zero
79
80`0` pads the number with leading zeros.
81
82### Width and Precision
83
84The width defines the minimum number of characters in the output. The precision is a `.` followed by a precision number,
85which is used as the precision of floating-point numbers, or a maximum-width for string values.
86
87Both the width and precision can be provided as a replacement field (`{}`, optionally including an argument index) which
88allows you to use an integer argument instead of a hard-coded number.
89
90### Type specifiers
91
92| Type | Effect | Example output |
93|-----------|-----------------------|--------------------------|
94| *nothing* | default format | Anything! :^) |
95| b | binary | `110`, `0b000110` |
96| B | binary uppercase | `110`, `0B000110` |
97| d | decimal | `42`, `+0000042` |
98| o | octal | `043` |
99| x | hexadecimal | `ff0`, `0x00000ff0` |
100| X | hexadecimal uppercase | `FF0`, `0X00000FF0` |
101| c | character | `a` |
102| s | string | `well, hello friends!` |
103| p | pointer | `0xdeadc0de` |
104| f | float | `1.234`, `-inf` |
105| a | hex float | |
106| A | hex float uppercase | |
107| hex-dump | hexadecimal dump | `fdfdfdfd`, `3030 00` |
108
109Not all type specifiers are compatible with all input types, of course.
110
111## Formatting custom types
112
113You can provide a custom `AK::Formatter<Foo>` class to format `Foo` values. For the simplest case where you already have
114a function that produces a string from your type, that would look like this:
115
116```c++
117template<>
118struct AK::Formatter<Web::CSS::Selector> : Formatter<StringView> {
119 ErrorOr<void> format(FormatBuilder& builder, Web::CSS::Selector const& selector)
120 {
121 return Formatter<StringView>::format(builder, selector.serialize());
122 }
123};
124```
125
126More advanced formatters that make check for format-specifier flags can be written by referring to the fields
127in `StandardFormatter` (which most `Formatter` classes extend).
128
129## Detecting if a type can be formatted
130
131The `AK::HasFormatter<T>` template has a boolean value representing whether `T` can be formatted.
132
133The `FormatIfSupported<T>` makes use of this to return either the formatted value of `T`, or a series of `?`s if the
134type cannot be formatted. For example:
135
136```c++
137// B has a Formatter defined, but A does not.
138DeprecatedString::formatted("{}", FormatIfSupported { A {} }) == "?";
139DeprecatedString::formatted("{}", FormatIfSupported { B {} }) == "B";
140```