Force a line break in rustfmt

I format my source with rustfmt because it is convenient and usually works very well.

However, this XML writing code is a bit confusing:

xmlwriter.write(XmlEvent::start_element("Default").attr("Extension", "rels").attr(
	"ContentType",
	"application/vnd.openxmlformats-package.relationships+xml",
))?;
xmlwriter.write(XmlEvent::end_element())?;

The .attr("Extension", "rels") on the first line is very easy to miss.

Is there a way I can give rustfmt a hint that for example starting each .attr() on a new line would be better?

2 Likes

That code does look odd to me, and it's not how I see it being formatted today. Perhaps you (have to) develop in an environment with custom formatting rules?

1 Like

Indeed I have one custom rule, I increased max_width to 120. That's why the formatting didn't match in the Playground, but you can observe the same behavior in the Playground by tweaking the string lengths.

1 Like

The place I remember seeing such constructs is implementations of Debug. But there the chain of calls ends with a short .finish(). Typical streaming too ends with .collect() or .sum(). If you add something like that to your example, the formatter behaves again. I'm not sure what the rules are, but somehow I never ran into this embarrassment.

Note that you can opt-out of rusftmt for this kind of situations:

#[cfg_attr(rustfmt, rustfmt::skip)]
xmlwriter.write(
    XmlEvent::start_element("Default")
        .attr("Extension", "rels")
        .attr(
	        "ContentType",
	        "application/vnd.openxmlformats-package.relationships+xml",
        )
)?;
xmlwriter.write(XmlEvent::end_element())?;
2 Likes

Apparently that is #[rustfmt::skip] now? rustfmt Tips

I also found that putting an empty comment can help, as rustfmt of course wouldn't move the comment away.

fn main() {
    xmlwriter.write(
        XmlEvent::start_element("Default") //
            .attr("xx", "xx")
            .attr(
                "ContentType",
                "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            ),
    )?;
    xmlwriter.write(XmlEvent::end_element())?;
}
3 Likes

Saldy Rust may sometimes attempt to intepret #[rustfmt::skip] as no-op attribute macro, but an attribute macro nonetheless. And those cannot be used in some places, such as an inner attribute for a module. By using the cfg_attr(rusftmt..., Rust will simply dismiss that attribute which lets us use it almost everywhere :upside_down_face: