Format string width parameter having no effect

Hi everyone. I'm writing a toy compiler and trying to make my error messages print the position of the problem in the source file. In order to keep the error messages easy to read, I'm trying to left-align the beginning of the messages by specifying a format string width for the line and column numbers.

// I want errors prefixed by line:col-line:col, but aligned messages.
1:1-1:10     Some error: ...
10:10-10:15  Some other error: ...

Here's a playground link showing approximately what I'm trying to do. I have a Point type whose display implementation is write!(f, "{}:{}", self.x, self,y), and a Span type whose display implementation is write!(f, "{}-{}", self.start, self.end), where self.start and self.end are both Points.

However, when I try to print a Span using a width option in the format string like println!("{:20}END", my_span), I would expect that it would print whitespace to pad up to 20 characters wide, then print "END" after. However, it prints "END" directly after the span.

// The output I want:
0:0-5:10           END

// The output produced:
0:0-5:10END

Is the expected behavior? It seems to me like this is a bug in the fmt macros (format_args!?). How might I go about getting the aligned printing I want with this setup? Any help would be appreciated! :slight_smile:

I believe the way this works is that the Formatter provided to Span's Display impl will tell you if the requested format specifies a width - it's then your responsibility to apply it. That is:

impl Display for Span {
    fn fmt(&self, f: &mut Formatter) -> fmtResult {
        let width = f.width(); // this will be Some(20) when println! below is called
        write!(f, "{}-{}", self.start, self.end)
    }
}

println!("{:20}X", span);

If you don't want to handle this in Span's fmt, you can do the following:

println!("{:20}X", format!("{}", span));

That is, turn your span into a String, and then apply the format to it since its impl respects the formatting options.

3 Likes

Ah, thanks. I was under the impression that the formatting options would automatically propagate somehow, but it makes sense that it gets delegated one layer down. I wound up implementing this using Formatter's pad method:

impl Display for Span {
    fn fmt(&self, f: &mut Formatter) -> fmtResult {
        f.pad(&format!("{}-{}", self.start, self.end))
    }
}

That way I can just use the println! macro's width option:

println!("{:20}X", span);
1 Like