Format code broken with println having line breaks?

One of my crates did not format anymore with Shift + Alt + F.
Before raising an issue I wanted to confirm that this is indeed a bug. Or I am doing something wrong.
Rust Analyzer: v0.3.1823
Code for a lib.rs crate.

const MAX_LEN: usize = 20;

pub fn so_something(n: usize) {
let counter = 0;
let result = 0;

println!("something {} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{} jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{}", 
n, 
counter, 
result);

let other = 124;
}

When commenting out the println then it works

const MAX_LEN: usize = 20;

pub fn so_something(n: usize) {
    let counter = 0;
    let result = 0;

    // println!("something {} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{} jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{}",
    // n,
    // counter,
    // result);

    let other = 124;
}

Expected behavior:

const MAX_LEN: usize = 20;

pub fn so_something(n: usize) {
    let counter = 0;
    let result = 0;

    println!("something {} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{} jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{}",
        n,
        counter,
        result
    );

    let other = 124;
}

This is one of the current limitations of rustfmt. If it is not possible to format a block so that it fits within the target line width (in this case, due to a long string literal), that block will not be formatted at all.

The workaround is to break up the string literal so that it fits:

    println!(
        "something {} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{} \
         jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{}",
        n,
        counter,
        result
    );

The \ at the end of the line inside the string literal will discard the newline and all following whitespace, so the contents of the string literal stay the same but it fits on two lines.

1 Like

One more thing that can be done is using concat! for the literal format string.
I believe there are some limitations to it though.

    println!(
        concat!(
            "something {} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{} ",
            "jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{}"
        ),
        n, counter, result
    );

One disadvantage of concat! for formatting strings is that it doesn’t work together with the newer {variable_name} style formatting placeholders.

    println!(
        "something {n} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{counter} \
         jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{result}"
    );

(works :white_check_mark:)

    println!(
        concat!(
            "something {n} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{counter} ",
            "jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{result}",
        )
    );

(error :x:)

error: there is no argument named `n`
  --> src/lib.rs:8:9
   |
8  | /         concat!(
9  | |             "something {n} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{counter} ",
10 | |             "jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{result}",
11 | |         )
   | |_________^
   |
   = note: did you intend to capture a variable `n` from the surrounding scope?
   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: there is no argument named `counter`
  --> src/lib.rs:8:9
   |
8  | /         concat!(
9  | |             "something {n} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{counter} ",
10 | |             "jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{result}",
11 | |         )
   | |_________^
   |
   = note: did you intend to capture a variable `counter` from the surrounding scope?
   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: there is no argument named `result`
  --> src/lib.rs:8:9
   |
8  | /         concat!(
9  | |             "something {n} jfls fjsdklf sdjf ksdjfkl sdfkljsd lfsdj flks{counter} ",
10 | |             "jf sldfjsdfkl jfj sdlkf lkssdjkf sdlkjfsdklf{result}",
11 | |         )
   | |_________^
   |
   = note: did you intend to capture a variable `result` from the surrounding scope?
   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)

error: could not compile `playground` (lib) due to 3 previous errors

This is a nice workaround and adds to readability. But I believe there is still a more serious bug.

a) that block will not be formatted at all: That would be nice, in my case the whole crate is not formatted at all.
b) when I comment the block, format the crate then uncomment the block, only after that it works as you explained. Future changes around the block will be formatted correctly.

Interestingly a) and b) even remain after saving, closing and reopening the project. Means either it formats the crate or not.