dart_style icon indicating copy to clipboard operation
dart_style copied to clipboard

wrong indent for lambda inside a method chain

Open passsy opened this issue 7 years ago • 3 comments
trafficstars

dartfmt makes method chains hard to read when a list operator receives a multi line lambda. Mixin multi and single line lambdas feels inconsistent.

// original input (well formatted in my opinion)
void testFormatting(List<String> list) {
  list.reversed
      .map((it) {
        if (it.contains("a")) {
          return it.toUpperCase();
        } else {
          return it.toLowerCase();
        }
      })
      .expand((it) => it.runes)
      .firstWhere((it) => it < "T".runes.first);
}
// dartfmt output
void testFormatting(List<String> list) {
  list.reversed
      .map((it) {
    if (it.contains("a")) {
      return it.toUpperCase();
    } else {
      return it.toLowerCase();
    }
  })
      .expand((it) => it.runes)
      .firstWhere((it) => it < "T".runes.first);
}

passsy avatar Nov 20 '18 22:11 passsy

This is similar to the conversation in #731, especially @munificent's last example.

(Not that it's a duplicate, necessarily; just linking similar issues.)

srawlins avatar Nov 20 '18 22:11 srawlins

#731 is similar but I don't request the chain to be indented even further down the chain. As @munificent pointed out it would march farther and farther to the right.

// requested solution in #731 (behaves poorly on long chains)
void testFormatting(List<String> list) {
  list.reversed
      .map((it) {
        if (it.contains("a")) {
          return it.toUpperCase();
        } else {
          return it.toLowerCase();
        }
      })
        .map((it) => it.toString())
          .map((it) => it.toString())
            .map((it) => it.toString())
        	  .map((it) => it.toString());
}

I only request the multi-line lamda to be indented based on the receiving function rather than the outer function.

passsy avatar Nov 20 '18 22:11 passsy

The output here is deliberate, but not great. Formatting function literals inside method chains well is really hard. For any given set of rules I've come up with, there seem to be real examples in the wild that look bad. The current set of rules — which are quite complex — are a compromise between a lot of different needs.

I'd like to do something better, but so far I haven't been able to come up with anything.

munificent avatar Nov 28 '18 20:11 munificent

The forthcoming tall style does what you want and gives the same formatting as the original input code:

void testFormatting(List<String> list) {
  list.reversed
      .map((it) {
        if (it.contains("a")) {
          return it.toUpperCase();
        } else {
          return it.toLowerCase();
        }
      })
      .expand((it) => it.runes)
      .firstWhere((it) => it < "T".runes.first);
}

munificent avatar Aug 02 '24 16:08 munificent