mirror of
https://github.com/ziglang/zig.git
synced 2024-11-26 23:22:44 +00:00
format: do not force user to provide an alignment field when it's not necessary (#19049)
* format: fix default character when no alignment When no alignment is specified, the character that should be used is the fill character that is otherwise provided, not space. This is closer to the default that C programmers (and other languages) use: "04x" fills with zeroes (in zig as of today x:04 fills with spaces) Test: const std = @import("std"); const expectFmt = std.testing.expectFmt; test "fmt.defaultchar.no-alignment" { // as of today the following test passes: try expectFmt("0x00ff", "0x{x:0>4}", .{255}); // as of today the following test fails (returns "0x ff" instead) try expectFmt("0x00ff", "0x{x:04}", .{255}); } * non breaking improvement of string formatting * improved comment * simplify the code a little * small improvement around how characters identified as valid are consumed
This commit is contained in:
parent
9d9b5a11e8
commit
c3faae6bf1
@ -20,11 +20,14 @@ pub const Alignment = enum {
|
|||||||
right,
|
right,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const default_alignment = .right;
|
||||||
|
const default_fill_char = ' ';
|
||||||
|
|
||||||
pub const FormatOptions = struct {
|
pub const FormatOptions = struct {
|
||||||
precision: ?usize = null,
|
precision: ?usize = null,
|
||||||
width: ?usize = null,
|
width: ?usize = null,
|
||||||
alignment: Alignment = .right,
|
alignment: Alignment = default_alignment,
|
||||||
fill: u21 = ' ',
|
fill: u21 = default_fill_char,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Renders fmt string with args, calling `writer` with slices of bytes.
|
/// 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
|
/// 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.
|
/// 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
|
/// Only exception is the *fill* parameter. If a non-zero *fill* character is required at the same time as *width* is specified,
|
||||||
/// the digits after `:` is interpreted as *width*, not *fill*.
|
/// 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:
|
/// The *specifier* has several options for types:
|
||||||
/// - `x` and `X`: output numeric value in hexadecimal notation
|
/// - `x` and `X`: output numeric value in hexadecimal notation
|
||||||
@ -239,29 +242,38 @@ pub const Placeholder = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the fill character
|
// Parse the fill character, if present.
|
||||||
// The fill parameter requires the alignment parameter to be specified
|
// When the width field is also specified, the fill character must
|
||||||
// too
|
// be followed by an alignment specifier, unless it's '0' (zero)
|
||||||
const fill = comptime if (parser.peek(1)) |ch|
|
// (in which case it's handled as part of the width specifier)
|
||||||
|
var fill: ?u21 = comptime if (parser.peek(1)) |ch|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
'<', '^', '>' => parser.char().?,
|
'<', '^', '>' => parser.char(),
|
||||||
else => ' ',
|
else => null,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
' ';
|
null;
|
||||||
|
|
||||||
// Parse the alignment parameter
|
// 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) {
|
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) {
|
} else null;
|
||||||
'<' => .left,
|
|
||||||
'^' => .center,
|
// When none of the fill character and the alignment specifier have
|
||||||
else => .right,
|
// been provided, check whether the width starts with a zero.
|
||||||
};
|
if (fill == null and alignment == null) {
|
||||||
} else .right;
|
fill = comptime if (parser.peek(0) == '0') '0' else null;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the width parameter
|
// Parse the width parameter
|
||||||
const width = comptime parser.specifier() catch |err|
|
const width = comptime parser.specifier() catch |err|
|
||||||
@ -284,8 +296,8 @@ pub const Placeholder = struct {
|
|||||||
|
|
||||||
return Placeholder{
|
return Placeholder{
|
||||||
.specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
|
.specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
|
||||||
.fill = fill,
|
.fill = fill orelse default_fill_char,
|
||||||
.alignment = alignment,
|
.alignment = alignment orelse default_alignment,
|
||||||
.arg = arg,
|
.arg = arg,
|
||||||
.width = width,
|
.width = width,
|
||||||
.precision = precision,
|
.precision = precision,
|
||||||
@ -2648,6 +2660,15 @@ test "sci float padding" {
|
|||||||
try expectFmt("right-pad: 3.142e0****\n", "right-pad: {e:*<11.3}\n", .{number});
|
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" {
|
test "null" {
|
||||||
const inst = null;
|
const inst = null;
|
||||||
try expectFmt("null", "{}", .{inst});
|
try expectFmt("null", "{}", .{inst});
|
||||||
|
Loading…
Reference in New Issue
Block a user