Commit c3faae6bf1
Changed files (1)
lib
std
lib/std/fmt.zig
@@ -20,11 +20,14 @@ pub const Alignment = enum {
right,
};
+const default_alignment = .right;
+const default_fill_char = ' ';
+
pub const FormatOptions = struct {
precision: ?usize = null,
width: ?usize = null,
- alignment: Alignment = .right,
- fill: u21 = ' ',
+ alignment: Alignment = default_alignment,
+ fill: u21 = default_fill_char,
};
/// Renders fmt string with args, calling `writer` with slices of bytes.
@@ -48,8 +51,8 @@ pub const FormatOptions = struct {
///
/// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when
/// all parameters after the separator are omitted.
-/// Only exception is the *fill* parameter. If *fill* is required, one has to specify *alignment* as well, as otherwise
-/// the digits after `:` is interpreted as *width*, not *fill*.
+/// Only exception is the *fill* parameter. If a non-zero *fill* character is required at the same time as *width* is specified,
+/// one has to specify *alignment* as well, as otherwise the digit following `:` is interpreted as *width*, not *fill*.
///
/// The *specifier* has several options for types:
/// - `x` and `X`: output numeric value in hexadecimal notation
@@ -239,29 +242,38 @@ pub const Placeholder = struct {
}
}
- // Parse the fill character
- // The fill parameter requires the alignment parameter to be specified
- // too
- const fill = comptime if (parser.peek(1)) |ch|
+ // Parse the fill character, if present.
+ // When the width field is also specified, the fill character must
+ // be followed by an alignment specifier, unless it's '0' (zero)
+ // (in which case it's handled as part of the width specifier)
+ var fill: ?u21 = comptime if (parser.peek(1)) |ch|
switch (ch) {
- '<', '^', '>' => parser.char().?,
- else => ' ',
+ '<', '^', '>' => parser.char(),
+ else => null,
}
else
- ' ';
+ null;
// Parse the alignment parameter
- const alignment: Alignment = comptime if (parser.peek(0)) |ch| init: {
+ const alignment: ?Alignment = comptime if (parser.peek(0)) |ch| init: {
switch (ch) {
- '<', '^', '>' => _ = parser.char(),
- else => {},
+ '<', '^', '>' => {
+ // consume the character
+ break :init switch (parser.char().?) {
+ '<' => .left,
+ '^' => .center,
+ else => .right,
+ };
+ },
+ else => break :init null,
}
- break :init switch (ch) {
- '<' => .left,
- '^' => .center,
- else => .right,
- };
- } else .right;
+ } else null;
+
+ // When none of the fill character and the alignment specifier have
+ // been provided, check whether the width starts with a zero.
+ if (fill == null and alignment == null) {
+ fill = comptime if (parser.peek(0) == '0') '0' else null;
+ }
// Parse the width parameter
const width = comptime parser.specifier() catch |err|
@@ -284,8 +296,8 @@ pub const Placeholder = struct {
return Placeholder{
.specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
- .fill = fill,
- .alignment = alignment,
+ .fill = fill orelse default_fill_char,
+ .alignment = alignment orelse default_alignment,
.arg = arg,
.width = width,
.precision = precision,
@@ -2648,6 +2660,15 @@ test "sci float padding" {
try expectFmt("right-pad: 3.142e0****\n", "right-pad: {e:*<11.3}\n", .{number});
}
+test "padding.zero" {
+ try expectFmt("zero-pad: '0042'", "zero-pad: '{:04}'", .{42});
+ try expectFmt("std-pad: ' 42'", "std-pad: '{:10}'", .{42});
+ try expectFmt("std-pad-1: '001'", "std-pad-1: '{:0>3}'", .{1});
+ try expectFmt("std-pad-2: '911'", "std-pad-2: '{:1<03}'", .{9});
+ try expectFmt("std-pad-3: ' 1'", "std-pad-3: '{:>03}'", .{1});
+ try expectFmt("center-pad: '515'", "center-pad: '{:5^03}'", .{1});
+}
+
test "null" {
const inst = null;
try expectFmt("null", "{}", .{inst});