diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala index f528591b88..c59e0c6a99 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala @@ -1,7 +1,7 @@ package org.scalafmt.internal import org.scalafmt.Error.UnexpectedTree -import org.scalafmt.config.BinPack +import org.scalafmt.config.{Align, BinPack} import org.scalafmt.config.{ImportSelectors, Newlines, ScalafmtConfig, Spaces} import org.scalafmt.internal.ExpiresOn.{After, Before} import org.scalafmt.internal.Length.{Num, StateColumn} @@ -622,11 +622,17 @@ class Router(formatOps: FormatOps) { val beforeDefRhs = defRhs.flatMap(tokens.tokenJustBeforeOpt) def getSplitsBeforeOpenParen( src: Newlines.SourceHints, - indentLen: Int - ) = { + indentLen: Int, + shouldAlignBefore: Align => Boolean + )(getArgsOpt: => Option[Seq[Tree]]) = { val close = matching(open) val indent = Indent(indentLen, close, ExpiresOn.After) - src match { + val isAlignFirstParen = shouldAlignBefore(style.align) && + !prevNonComment(ft).left.is[T.RightParen] + def noSplitSplit(implicit fileLine: FileLine) = + if (isAlignFirstParen) Split(NoSplit, 0) + else Split(NoSplit, 0).withSingleLine(close) + val splits = src match { case Newlines.unfold => val slbEnd = if (defn) beforeDefRhs.fold(getLastToken(rightOwner))(_.left) @@ -657,7 +663,7 @@ class Router(formatOps: FormatOps) { Seq(Split(Newline, 0).withIndent(indent)) else Seq( - Split(NoSplit, 0).withSingleLine(close), + noSplitSplit, Split(Newline, 1).withIndent(indent) ) case _ => @@ -672,12 +678,22 @@ class Router(formatOps: FormatOps) { } } Seq( - Split(NoSplit, 0).withSingleLine(close), + noSplitSplit, Split(Newline, 1) .withIndent(indent) .withPolicyOpt(nlColonPolicy) ) } + val argsOpt = if (isAlignFirstParen) getArgsOpt else None + argsOpt.map(x => tokens.tokenAfter(x).right).fold(splits) { x => + val noSplitIndents = Seq( + Indent(StateColumn, x, ExpiresOn.Before), + Indent(-indentLen, x, ExpiresOn.Before) + ) + splits.map { s => + if (s.isNL) s else s.withIndents(noSplitIndents) + } + } } val beforeOpenParenSplits = if (!open.is[T.LeftParen]) None @@ -692,12 +708,31 @@ class Router(formatOps: FormatOps) { style.indent.extraBeforeOpenParenDefnSite + (if (ob) style.indent.getSignificant else style.indent.main) } - getSplitsBeforeOpenParen(x, indent) + getSplitsBeforeOpenParen(x, indent, _.beforeOpenParenDefnSite) { + rightOwner match { + case SplitDefnIntoParts(_, _, _, args) => Some(args.last) + case _ => None + } + } } else if (style.dialect.allowSignificantIndentation) - style.newlines.getBeforeOpenParenCallSite.map( - getSplitsBeforeOpenParen(_, style.indent.getSignificant) - ) + style.newlines.getBeforeOpenParenCallSite.map { x => + val indent = style.indent.getSignificant + @tailrec + def findLastCallArgs(tree: Tree, ca: CallArgs): CallArgs = + tree match { + case SplitCallIntoParts(_, pca) => + tree.parent match { + case Some(p) => findLastCallArgs(p, pca) + case _ => pca + } + case _ => ca + } + getSplitsBeforeOpenParen(x, indent, _.beforeOpenParenCallSite) { + Option(findLastCallArgs(rightOwner, null)) + .map(_.fold(identity, _.last)) + } + } else None beforeOpenParenSplits.getOrElse(Seq(Split(modification, 0))) diff --git a/scalafmt-tests/src/test/resources/newlines/source_classic.stat b/scalafmt-tests/src/test/resources/newlines/source_classic.stat index d2e93caaa2..4ef70977f2 100644 --- a/scalafmt-tests/src/test/resources/newlines/source_classic.stat +++ b/scalafmt-tests/src/test/resources/newlines/source_classic.stat @@ -5691,7 +5691,7 @@ def allMatching(versionString: String) } >>> def allMatching(versionString: String) - (partialFunctions: PartialFunction[options.Common, List[String]]*) + (partialFunctions: PartialFunction[options.Common, List[String]]*) : List[String] = {} <<< align.beforeOpenParenDefnSite + align.openParenDefnSite maxColumn = 85 @@ -5706,8 +5706,7 @@ def allMatching(versionString: String, partialFunctions: PartialFunction[options } >>> -def allMatching - (versionString: String, - partialFunctions: PartialFunction[options.Common, List[String]]*) - (partialFunctions: PartialFunction[options.Common, List[String]]*) +def allMatching(versionString: String, + partialFunctions: PartialFunction[options.Common, List[String]]*) + (partialFunctions: PartialFunction[options.Common, List[String]]*) : List[String] = {} diff --git a/scalafmt-tests/src/test/resources/newlines/source_fold.stat b/scalafmt-tests/src/test/resources/newlines/source_fold.stat index 37dc1ccd92..0368976b2a 100644 --- a/scalafmt-tests/src/test/resources/newlines/source_fold.stat +++ b/scalafmt-tests/src/test/resources/newlines/source_fold.stat @@ -5450,7 +5450,7 @@ def allMatching(versionString: String) } >>> def allMatching(versionString: String) - (partialFunctions: PartialFunction[options.Common, List[String]]*) + (partialFunctions: PartialFunction[options.Common, List[String]]*) : List[String] = {} <<< align.beforeOpenParenDefnSite + align.openParenDefnSite maxColumn = 85 @@ -5465,8 +5465,7 @@ def allMatching(versionString: String, partialFunctions: PartialFunction[options } >>> -def allMatching - (versionString: String, - partialFunctions: PartialFunction[options.Common, List[String]]*) - (partialFunctions: PartialFunction[options.Common, List[String]]*) +def allMatching(versionString: String, + partialFunctions: PartialFunction[options.Common, List[String]]*) + (partialFunctions: PartialFunction[options.Common, List[String]]*) : List[String] = {} diff --git a/scalafmt-tests/src/test/resources/newlines/source_keep.stat b/scalafmt-tests/src/test/resources/newlines/source_keep.stat index e4cc10b2a8..6ae5267e71 100644 --- a/scalafmt-tests/src/test/resources/newlines/source_keep.stat +++ b/scalafmt-tests/src/test/resources/newlines/source_keep.stat @@ -5710,7 +5710,7 @@ def allMatching(versionString: String) } >>> def allMatching(versionString: String) - (partialFunctions: PartialFunction[options.Common, List[String]]*): List[String] = {} + (partialFunctions: PartialFunction[options.Common, List[String]]*): List[String] = {} <<< align.beforeOpenParenDefnSite + align.openParenDefnSite maxColumn = 85 danglingParentheses.defnSite = false @@ -5724,8 +5724,7 @@ def allMatching(versionString: String, partialFunctions: PartialFunction[options } >>> -def allMatching - (versionString: String, - partialFunctions: PartialFunction[options.Common, List[String]]*) - (partialFunctions: PartialFunction[options.Common, List[String]]*) +def allMatching(versionString: String, + partialFunctions: PartialFunction[options.Common, List[String]]*) + (partialFunctions: PartialFunction[options.Common, List[String]]*) : List[String] = {} diff --git a/scalafmt-tests/src/test/resources/scala3/OptionalBraces.stat b/scalafmt-tests/src/test/resources/scala3/OptionalBraces.stat index ad08ff4d5f..29a28f266a 100644 --- a/scalafmt-tests/src/test/resources/scala3/OptionalBraces.stat +++ b/scalafmt-tests/src/test/resources/scala3/OptionalBraces.stat @@ -3298,7 +3298,7 @@ allMatching(versionString) (partialFunctions) >>> allMatching(versionString) - (partialFunctions) + (partialFunctions) <<< align.beforeOpenParenCallSite + align.openParenCallSite maxColumn = 30 align.closeParenSite = true @@ -3309,7 +3309,6 @@ newlines.beforeOpenParenCallSite = source allMatching(versionString, partialFunctions) (partialFunctions) >>> -allMatching - (versionString, - partialFunctions - )(partialFunctions) +allMatching(versionString, + partialFunctions + )(partialFunctions) diff --git a/scalafmt-tests/src/test/resources/scala3/OptionalBraces_fold.stat b/scalafmt-tests/src/test/resources/scala3/OptionalBraces_fold.stat index d2b7748a99..e8c7eec695 100644 --- a/scalafmt-tests/src/test/resources/scala3/OptionalBraces_fold.stat +++ b/scalafmt-tests/src/test/resources/scala3/OptionalBraces_fold.stat @@ -3141,7 +3141,7 @@ allMatching(versionString) (partialFunctions) >>> allMatching(versionString) - (partialFunctions) + (partialFunctions) <<< align.beforeOpenParenCallSite + align.openParenCallSite maxColumn = 30 align.closeParenSite = true @@ -3152,7 +3152,6 @@ newlines.beforeOpenParenCallSite = source allMatching(versionString, partialFunctions) (partialFunctions) >>> -allMatching - (versionString, - partialFunctions - )(partialFunctions) +allMatching(versionString, + partialFunctions + )(partialFunctions) diff --git a/scalafmt-tests/src/test/resources/scala3/OptionalBraces_keep.stat b/scalafmt-tests/src/test/resources/scala3/OptionalBraces_keep.stat index abcede594a..89696e19ca 100644 --- a/scalafmt-tests/src/test/resources/scala3/OptionalBraces_keep.stat +++ b/scalafmt-tests/src/test/resources/scala3/OptionalBraces_keep.stat @@ -3286,7 +3286,7 @@ allMatching(versionString) (partialFunctions) >>> allMatching(versionString) - (partialFunctions) + (partialFunctions) <<< align.beforeOpenParenCallSite + align.openParenCallSite maxColumn = 30 align.closeParenSite = true @@ -3297,8 +3297,7 @@ newlines.beforeOpenParenCallSite = source allMatching(versionString, partialFunctions) (partialFunctions) >>> -allMatching - (versionString, - partialFunctions - ) - (partialFunctions) +allMatching(versionString, + partialFunctions + ) + (partialFunctions)