Repository: scalameta/scalameta (scala)

Issue:
Scalafmt 3.7.16 breaks my code
I have this piece of Scala 3 code in my codebase:

```scala
object Main extends ZIOAppDefault:
  override val bootstrap: ULayer[Environment] =
    (Runtime.removeDefaultLoggers >>> zio.logging.consoleJsonLogger:
      import zio.logging.LogFormat.*
      ConsoleLoggerConfig(
        label("timestamp", timestamp) |-|
          label("level", level) |-|
          label("logger", LogFormat.loggerName((_, _, annotations) => annotations.get("logger_name"))) |-|
          label("message", quoted(line)) |-|
          label("cause", cause).filter(LogFilter.causeNonEmpty) |-|
          logAnnotations,
        LogFilter.logLevel(_ >= LogLevel.Info))
    >>> Slf4jBridge.initialize) ++
      Runtime.setConfigProvider(TypesafeConfigProvider.fromResourcePath())

```
Given the following configuration…
```
version = "3.7.16"
maxColumn = 120
runner.dialect = scala3
runner.dialectOverride.allowSignificantIndentation = true
indent.main = 2
indent.significant = 2
```
…this is reformatted as follows:

```scala
object Main extends ZIOAppDefault:
  override val bootstrap: ULayer[Environment] =
    (Runtime.removeDefaultLoggers >>> zio.logging.consoleJsonLogger:
      import zio.logging.LogFormat.*
      ConsoleLoggerConfig(
        label("timestamp", timestamp) |-|
          label("level", level) |-|
          label("logger", LogFormat.loggerName((_, _, annotations) => annotations.get("logger_name"))) |-|
          label("message", quoted(line)) |-|
          label("cause", cause).filter(LogFilter.causeNonEmpty) |-|
          logAnnotations,
        LogFilter.logLevel(_ >= LogLevel.Info)
      )
        >>> Slf4jBridge.initialize
    ) ++
      Runtime.setConfigProvider(TypesafeConfigProvider.fromResourcePath())
```

This code no longer compiles because the `>>> Slf4jBridge.initialize` thing is applied to the `ConsoleLoggerConfig` object rather than the return value of `consoleJsonLogger`. Unindent the `>>> Slf4jBridge.initialize` line by 4 spaces and it compiles again.

Pull request:
Fixes #3390.

Patch:
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 f3f01a3931..78f3512671 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
@@ -748,20 +748,22 @@ final class ScannerTokens(val tokens: Tokens)(implicit dialect: Dialect) {
                     case _ => shouldOutdent(rs)
                   }) =>
                 (Right(true), rs)
-              case (r: RegionIndent) :: (rs @ (rc: RegionControl) :: xs) if nextIndent < r.indent =>
+              case regions @ (r: SepRegionIndented) :: _ if nextIndent >= r.indent =>
+                (Right(false), regions) // we stop here
+              case (r: RegionIndent) :: (rs @ (rc: RegionControl) :: xs) =>
                 (Left(r), if (rc.isNotTerminatingTokenIfOptional(next)) xs else rs)
-              case (r: RegionIndent) :: RegionTemplateBody :: xs if nextIndent < r.indent =>
+              case (r: RegionIndent) :: RegionTemplateBody :: xs =>
                 (Left(r), xs)
               case (r: SepRegionIndented) :: xs if (prev match {
                     // then  [else]  [do]  catch  [finally]  [yield]  match
                     case _: KwElse | _: KwDo | _: KwFinally | _: KwYield => false
                     // exclude leading infix op
-                    case _ => nextIndent < r.indent && (!isLeadingInfix() || shouldOutdent(xs))
+                    case _ => nextIndent == 0 || shouldOutdent(xs) || !isLeadingInfix()
                   }) =>
                 (Left(r), xs)
             }
           def shouldOutdent(rs: List[SepRegion]): Boolean =
-            rs.find(_.isIndented).exists(_.indent > nextIndent)
+            rs.find(_.isIndented).exists(_.indent >= nextIndent)
 
           /**
            * Indent is needed in the following cases:


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/FewerBracesSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/FewerBracesSuite.scala
index 53feab30b2..d8ec3744e1 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/FewerBracesSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/dotty/FewerBracesSuite.scala
@@ -905,4 +905,89 @@ class FewerBracesSuite extends BaseDottySuite {
     runTestAssert[Stat](code, Some(layout))(tree)
   }
 
+  test("#3390 within infix, within indented block") {
+    val code =
+      """object MyApp:
+        |  a >>> b.map:
+        |    foo
+        |    bar(
+        |      baz,
+        |      qux
+        |    )
+        |  >>> c
+        |""".stripMargin
+    val layout =
+      """|object MyApp {
+         |  a >>> b.map {
+         |    foo
+         |    bar(baz, qux)
+         |  } >>> c
+         |}
+         |""".stripMargin
+    val tree = Defn.Object(
+      Nil,
+      tname("MyApp"),
+      tpl(
+        Term.ApplyInfix(
+          Term.ApplyInfix(
+            tname("a"),
+            tname(">>>"),
+            Nil,
+            Term.Apply(
+              Term.Select(tname("b"), tname("map")),
+              Term.Block(
+                List(
+                  tname("foo"),
+                  Term.Apply(tname("bar"), List(tname("baz"), tname("qux")))
+                )
+              ) :: Nil
+            ) :: Nil
+          ),
+          tname(">>>"),
+          Nil,
+          List(tname("c"))
+        ) :: Nil
+      )
+    )
+    runTestAssert[Stat](code, Some(layout))(tree)
+  }
+
+  test("#3390 within infix, at top level") {
+    val code =
+      """a >>> b.map:
+        |  foo
+        |  bar(
+        |    baz,
+        |    qux
+        |  )
+        |>>> c
+        |""".stripMargin
+    val layout =
+      """|a >>> b.map {
+         |  foo
+         |  bar(baz, qux)
+         |} >>> c
+         |""".stripMargin
+    val tree = Term.ApplyInfix(
+      Term.ApplyInfix(
+        tname("a"),
+        tname(">>>"),
+        Nil,
+        Term.Apply(
+          Term.Select(tname("b"), tname("map")),
+          Term.Block(
+            List(
+              tname("foo"),
+              Term.Apply(tname("bar"), List(tname("baz"), tname("qux")))
+            )
+          ) :: Nil
+        ) :: Nil
+      ),
+      tname(">>>"),
+      Nil,
+      List(tname("c"))
+    )
+    runTestAssert[Stat](code, Some(layout))(tree)
+  }
+
 }