diff --git a/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/ExprFormatter.scala b/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/ExprFormatter.scala index 49bcb75c..313fff49 100755 --- a/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/ExprFormatter.scala +++ b/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/ExprFormatter.scala @@ -972,14 +972,24 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi } def formatParamClauses(paramClauses: ParamClauses, doubleIndentParams: Boolean = false)(implicit formatterState: FormatterState): FormatResult = { - val ParamClauses(initialNewlineOpt, paramClausesAndNewlines) = paramClauses + val ParamClauses(_, paramClausesAndNewlines) = paramClauses var formatResult: FormatResult = NoFormatResult var currentFormatterState = formatterState - for ((paramClause, newlineOption) ← paramClausesAndNewlines) { // TODO: Newlines. // maybe already done in some cases by format(tmplDef)? - val (paramClauseFormatResult, newFormatterState) = formatParamClause(paramClause, doubleIndentParams)(currentFormatterState) - formatResult ++= paramClauseFormatResult - } - formatResult + val breakLine = paramClauses.rangeOpt.map(_.length > formattingPreferences(BreakMultipleParameterGroups.BreakingThreshold)).getOrElse(false) + type Params = (ParamClause,Option[Token]) + type Result = (FormatResult, FormatterState, Option[IntertokenFormatInstruction]) + val start: Result = (FormatResult.EMPTY, formatterState, None) + paramClausesAndNewlines.foldLeft(start) { (accumulator: Result, current: Params) => + val (result, formatterState, previousLeftFormat) = accumulator + val paramClause = current._1 + val formatResult = formatParamClause(paramClause, doubleIndentParams)(formatterState) + val resultWithNewLines = previousLeftFormat.filter(_ => formattingPreferences(BreakMultipleParameterGroups) && breakLine).map{ p => + FormatResult.EMPTY.before(paramClause.lparen, p) + }.foldLeft(formatResult._1 ++ result) { _ ++ _ } + val currentLeftFormat = Some(EnsureNewlineAndIndent(0, paramClause.firstTokenOption)) + formattingPreferences.indentStyle + (resultWithNewLines, formatResult._2, currentLeftFormat) + }._1 } // TODO: Parts of this function might be useful in implementing other alignment features diff --git a/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/preferences/PreferenceDescriptor.scala b/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/preferences/PreferenceDescriptor.scala index dcd145c8..aacd617e 100755 --- a/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/preferences/PreferenceDescriptor.scala +++ b/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/preferences/PreferenceDescriptor.scala @@ -65,7 +65,8 @@ object AllPreferences { PreserveSpaceBeforeArguments, AlignParameters, AlignArguments, DoubleIndentClassDeclaration, FormatXml, IndentPackageBlocks, AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, IndentLocalDefs, PreserveDanglingCloseParenthesis, SpaceInsideParentheses, SpaceInsideBrackets, SpacesWithinPatternBinders, MultilineScaladocCommentsStartOnFirstLine, IndentWithTabs, - CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk, SpacesAroundMultiImports + CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk, SpacesAroundMultiImports, BreakMultipleParameterGroups, + BreakMultipleParameterGroups.BreakingThreshold ) val preferencesByKey: Map[String, PreferenceDescriptor[_]] = { @@ -213,4 +214,16 @@ case object SpacesAroundMultiImports extends BooleanPreferenceDescriptor { val defaultValue = true } +case object BreakMultipleParameterGroups extends BooleanPreferenceDescriptor { + val key = "breakMultipleParametersGroups" + val description = "Place newline after end of parameter group on multiple parameter group function definition" + val defaultValue = false + + case object BreakingThreshold extends IntegerPreferenceDescriptor { + val key = "breakMultipleParametersGroups.breakingThreshold" + val description = "Line length after multiple parameters list will break to new line" + val preferenceType = IntegerPreference(1, 100) + val defaultValue = 80 + } +} diff --git a/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/MultipleParameterListsFormatterTest.scala b/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/MultipleParameterListsFormatterTest.scala index d277b51e..f408d004 100644 --- a/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/MultipleParameterListsFormatterTest.scala +++ b/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/MultipleParameterListsFormatterTest.scala @@ -1,38 +1,61 @@ package com.danieltrinh.scalariform.formatter -import com.danieltrinh.scalariform.parser.{CompilationUnit, ScalaParser} +import com.danieltrinh.scalariform.formatter.preferences.{BreakMultipleParameterGroups, FormattingPreferences} class MultipleParameterListsFormatterTest extends AbstractExpressionFormatterTest { override def debug = false - """def f(x: Int)(y: Int): Int = { + { + + implicit val formatting = FormattingPreferences.setPreference(BreakMultipleParameterGroups, true) + + """def f(x: Int) + |(y: Int): Int = { + |} + |""" ==> """def f(x: Int)(y: Int): Int = { + |} + |""" + """def f(x: Int) + | (y: Int)(z: Int): Int = { + |}""" ==>"""def f(x: Int)(y: Int)(z: Int): Int = { + |} + |""" + + } + + { + + implicit val formatting = FormattingPreferences.setPreference(BreakMultipleParameterGroups, true) + .setPreference(BreakMultipleParameterGroups.BreakingThreshold, 4) + + """def f(x: Int)(y: Int): Int = { |} |""" ==> - """def f(x: Int) + """def f(x: Int) | (y: Int): Int = { |} |""" - """def f(x: Int) + """def f(x: Int) | (y: Int)(z: Int): Int = { |} """ ==> - """def f(x: Int) + """def f(x: Int) | (y: Int) | (z: Int): Int = { |} - |""" - - // See issue #73 - """def mergeMapsCombiningValueMaps[A, B, C](collisionFunc: (C, C) => C)(m1: Map[A, Map[Seq[B], C]], m2: Map[A, Map[Seq[B], C]]): Map[A, Map[Seq[B], C]] = { + |""" // See issue #73 + """def mergeMapsCombiningValueMaps[A, B, C](collisionFunc: (C, C) => C)(m1: Map[A, Map[Seq[B], C]], m2: Map[A, Map[Seq[B], C]]): Map[A, Map[Seq[B], C]] = { | mergeMaps(m1, m2)((m11, m22) => mergeMaps(m11, m22)(collisionFunc)) |}""" ==> - """def mergeMapsCombiningValueMaps[A, B, C](collisionFunc: (C, C) => C) + """def mergeMapsCombiningValueMaps[A, B, C](collisionFunc: (C, C) => C) | (m1: Map[A, Map[Seq[B], C]], m2: Map[A, Map[Seq[B], C]]): Map[A, Map[Seq[B], C]] = { | mergeMaps(m1, m2)((m11, m22) => mergeMaps(m11, m22)(collisionFunc)) |}""" + } + }