diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala index e60e5c1b5e..ff1e5797b7 100644 --- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala +++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScannerTokens.scala @@ -911,6 +911,16 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) { if (prevToken.is[Indentation]) _ => None else getOutdentIfNeeded(_).fold(getIndentIfNeeded, x => Some(Right(x))) + def maybeWithLF(regions: List[SepRegion]) = { + val res = getIfCanProduceLF(regions, nextIndent) + if (res.isEmpty) sepRegionsOrig match { + case (ri: SepRegionIndented) :: _ if ri.indent < nextIndent => + Some(Left(RegionLine(nextIndent) :: sepRegionsOrig)) + case _ => res + } + else res + } + @tailrec def iter(regions: List[SepRegion]): Option[Either[List[SepRegion], TokenRef]] = { val res = regionsToRes(regions).orElse { @@ -927,12 +937,12 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) { if (next.is[Dot]) None else rc.asBody() match { - case Some(body) => getIfCanProduceLF(body :: rs, nextIndent) + case Some(body) => maybeWithLF(body :: rs) case None => iter(rs) } case _ => iter(rs) } - case rs => getIfCanProduceLF(rs, nextIndent) + case rs => maybeWithLF(rs) } else res } diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/InfixSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/InfixSuite.scala index 3dac9c0880..2622e3a564 100644 --- a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/InfixSuite.scala +++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/InfixSuite.scala @@ -653,4 +653,107 @@ class InfixSuite extends BaseDottySuite { runTestAssert[Stat](code, Some(layout))(tree) } + test("scalafmt #3825 1") { + val code = + """|object a: + | foo + | .map: i => + | i + 1 + | *> bar + |""".stripMargin + val layout = + """|object a { + | foo.map { + | i => i + 1 + | } *> bar + |} + |""".stripMargin + val tree = Defn.Object( + Nil, + tname("a"), + tpl( + Term.ApplyInfix( + Term.Apply( + Term.Select(tname("foo"), tname("map")), + blk( + Term.Function( + List(tparam("i")), + Term.ApplyInfix(tname("i"), tname("+"), Nil, List(int(1))) + ) + ) :: Nil + ), + tname("*>"), + Nil, + List(tname("bar")) + ) + ) + ) + runTestAssert[Stat](code, layout)(tree) + } + + test("scalafmt #3825 2") { + val code = + """|object a: + | object b: + | foo + | .map: i => + | i + 1 + | + 2 + | + 3 + | *> bar + | baz + | qux + |""".stripMargin + val layout = + """|object a { + | object b { + | foo.map { + | i => i + 1 + 2 + 3 + | } *> bar + | baz + | } + | qux + |} + |""".stripMargin + val tree = Defn.Object( + Nil, + tname("a"), + tpl( + Defn.Object( + Nil, + tname("b"), + tpl( + Term.ApplyInfix( + Term.Apply( + Term.Select(tname("foo"), tname("map")), + blk( + Term.Function( + List(tparam("i")), + Term.ApplyInfix( + Term.ApplyInfix( + Term.ApplyInfix(tname("i"), tname("+"), Nil, List(int(1))), + tname("+"), + Nil, + List(int(2)) + ), + tname("+"), + Nil, + List(int(3)) + ) + ) + ) :: Nil + ), + tname("*>"), + Nil, + List(tname("bar")) + ), + tname("baz") + ) + ), + tname("qux") + ) + ) + runTestAssert[Stat](code, layout)(tree) + } + }