authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-06-25 17:11:04+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2019-06-25 17:11:18+12:00
log08e8d30dd642e42d8b8b16f43b487dbf42adb5ba
treea024bb348559c788de481975b17a378930772ecd
parent948dc7b304f966d8402f63261a8b8dd43691647a

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.

1 files changed, 45 insertions(+), 2 deletions(-)

std/fmt.zig+45-2
...@@ -10,9 +10,17 @@ const lossyCast = std.math.lossyCast;...@@ -10,9 +10,17 @@ const lossyCast = std.math.lossyCast;
1010
11pub const default_max_depth = 3;11pub const default_max_depth = 3;
1212
13pub const Alignment = enum {
14 Left,
15 Center,
16 Right,
17};
18
13pub const FormatOptions = struct {19pub const FormatOptions = struct {
14 precision: ?usize = null,20 precision: ?usize = null,
15 width: ?usize = null,21 width: ?usize = null,
22 alignment: ?Alignment = null,
23 fill: u8 = ' ',
16};24};
1725
18fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int, comptime next_arg: *comptime_int) comptime_int {26fn 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,...@@ -26,6 +34,18 @@ fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int,
26 }34 }
27}35}
2836
37fn peekIsAlign(comptime fmt: []const u8) bool {
38 // Should only be called during a state transition to the format segment.
39 std.debug.assert(fmt[0] == ':');
40
41 inline for (([_]u8{ 1, 2 })[0..]) |i| {
42 if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
43 return true;
44 }
45 }
46 return false;
47}
48
29/// Renders fmt string with args, calling output with slices of bytes.49/// Renders fmt string with args, calling output with slices of bytes.
30/// If `output` returns an error, the error is returned from `format` and50/// If `output` returns an error, the error is returned from `format` and
31/// `output` is not called again.51/// `output` is not called again.
...@@ -46,6 +66,7 @@ pub fn format(...@@ -46,6 +66,7 @@ pub fn format(
46 Positional,66 Positional,
47 CloseBrace,67 CloseBrace,
48 Specifier,68 Specifier,
69 FormatFillAndAlign,
49 FormatWidth,70 FormatWidth,
50 FormatPrecision,71 FormatPrecision,
51 Pointer,72 Pointer,
...@@ -92,7 +113,7 @@ pub fn format(...@@ -92,7 +113,7 @@ pub fn format(
92 state = .Pointer;113 state = .Pointer;
93 },114 },
94 ':' => {115 ':' => {
95 state = .FormatWidth;116 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
96 specifier_end = i;117 specifier_end = i;
97 },118 },
98 '0'...'9' => {119 '0'...'9' => {
...@@ -139,7 +160,7 @@ pub fn format(...@@ -139,7 +160,7 @@ pub fn format(
139 .Specifier => switch (c) {160 .Specifier => switch (c) {
140 ':' => {161 ':' => {
141 specifier_end = i;162 specifier_end = i;
142 state = .FormatWidth;163 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
143 },164 },
144 '}' => {165 '}' => {
145 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);166 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
...@@ -158,6 +179,24 @@ pub fn format(...@@ -158,6 +179,24 @@ pub fn format(
158 },179 },
159 else => {},180 else => {},
160 },181 },
182 // Only entered if the format string contains a fill/align segment.
183 .FormatFillAndAlign => switch (c) {
184 '<' => {
185 options.alignment = Alignment.Left;
186 state = .FormatWidth;
187 },
188 '^' => {
189 options.alignment = Alignment.Center;
190 state = .FormatWidth;
191 },
192 '>' => {
193 options.alignment = Alignment.Right;
194 state = .FormatWidth;
195 },
196 else => {
197 options.fill = c;
198 },
199 },
161 .FormatWidth => switch (c) {200 .FormatWidth => switch (c) {
162 '0'...'9' => {201 '0'...'9' => {
163 if (options.width == null) {202 if (options.width == null) {
...@@ -1571,3 +1610,7 @@ test "positional" {...@@ -1571,3 +1610,7 @@ test "positional" {
1571test "positional with specifier" {1610test "positional with specifier" {
1572 try testFmt("10.0", "{0d:.1}", f64(9.999));1611 try testFmt("10.0", "{0d:.1}", f64(9.999));
1573}1612}
1613
1614test "positional/alignment/width/precision" {
1615 try testFmt("10.0", "{0d: >3.1}", f64(9.999));
1616}