Add parsing of fill and alignment in std.format
These options are now available to use when printing, however nothing currently makes use of these.master
parent
948dc7b304
commit
08e8d30dd6
47
std/fmt.zig
47
std/fmt.zig
|
@ -10,9 +10,17 @@ const lossyCast = std.math.lossyCast;
|
|||
|
||||
pub const default_max_depth = 3;
|
||||
|
||||
pub const Alignment = enum {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
};
|
||||
|
||||
pub const FormatOptions = struct {
|
||||
precision: ?usize = null,
|
||||
width: ?usize = null,
|
||||
alignment: ?Alignment = null,
|
||||
fill: u8 = ' ',
|
||||
};
|
||||
|
||||
fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int, comptime next_arg: *comptime_int) comptime_int {
|
||||
|
@ -26,6 +34,18 @@ fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int,
|
|||
}
|
||||
}
|
||||
|
||||
fn peekIsAlign(comptime fmt: []const u8) bool {
|
||||
// Should only be called during a state transition to the format segment.
|
||||
std.debug.assert(fmt[0] == ':');
|
||||
|
||||
inline for (([_]u8{ 1, 2 })[0..]) |i| {
|
||||
if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Renders fmt string with args, calling output with slices of bytes.
|
||||
/// If `output` returns an error, the error is returned from `format` and
|
||||
/// `output` is not called again.
|
||||
|
@ -46,6 +66,7 @@ pub fn format(
|
|||
Positional,
|
||||
CloseBrace,
|
||||
Specifier,
|
||||
FormatFillAndAlign,
|
||||
FormatWidth,
|
||||
FormatPrecision,
|
||||
Pointer,
|
||||
|
@ -92,7 +113,7 @@ pub fn format(
|
|||
state = .Pointer;
|
||||
},
|
||||
':' => {
|
||||
state = .FormatWidth;
|
||||
state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
|
||||
specifier_end = i;
|
||||
},
|
||||
'0'...'9' => {
|
||||
|
@ -139,7 +160,7 @@ pub fn format(
|
|||
.Specifier => switch (c) {
|
||||
':' => {
|
||||
specifier_end = i;
|
||||
state = .FormatWidth;
|
||||
state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
|
||||
},
|
||||
'}' => {
|
||||
const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
|
||||
|
@ -158,6 +179,24 @@ pub fn format(
|
|||
},
|
||||
else => {},
|
||||
},
|
||||
// Only entered if the format string contains a fill/align segment.
|
||||
.FormatFillAndAlign => switch (c) {
|
||||
'<' => {
|
||||
options.alignment = Alignment.Left;
|
||||
state = .FormatWidth;
|
||||
},
|
||||
'^' => {
|
||||
options.alignment = Alignment.Center;
|
||||
state = .FormatWidth;
|
||||
},
|
||||
'>' => {
|
||||
options.alignment = Alignment.Right;
|
||||
state = .FormatWidth;
|
||||
},
|
||||
else => {
|
||||
options.fill = c;
|
||||
},
|
||||
},
|
||||
.FormatWidth => switch (c) {
|
||||
'0'...'9' => {
|
||||
if (options.width == null) {
|
||||
|
@ -1571,3 +1610,7 @@ test "positional" {
|
|||
test "positional with specifier" {
|
||||
try testFmt("10.0", "{0d:.1}", f64(9.999));
|
||||
}
|
||||
|
||||
test "positional/alignment/width/precision" {
|
||||
try testFmt("10.0", "{0d: >3.1}", f64(9.999));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue