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..7675c4c0 100755 --- a/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/ExprFormatter.scala +++ b/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/ExprFormatter.scala @@ -971,15 +971,34 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi formatResult } - def formatParamClauses(paramClauses: ParamClauses, doubleIndentParams: Boolean = false)(implicit formatterState: FormatterState): FormatResult = { - val ParamClauses(initialNewlineOpt, paramClausesAndNewlines) = paramClauses + def formatParamClauses(paramClauses: ParamClauses, doubleIndentParams: Boolean = false)(implicit envFormatterState: FormatterState): FormatResult = { + 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 + var currentFormatterState = envFormatterState + 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, envFormatterState, None) + paramClausesAndNewlines.foldLeft(start) { (accumulator: Result, current: Params) => + val (result, formatterState, previousLeftFormat) = accumulator + val paramClause = current._1 + + val formatResult = if(paramClause.tokens.exists(hiddenPredecessors(_).containsNewline)){ + formatParamClause(paramClause, doubleIndentParams)(currentFormatterState) + } else { + formatParamClause(paramClause, doubleIndentParams)(formatterState) + } + val resultWithNewLines = previousLeftFormat.filter(_ => formattingPreferences(BreakMultipleParameterGroups) && breakLine).map{ p => + FormatResult.EMPTY.before(paramClause.lparen, p) + }.foldLeft(formatResult._1 ++ result) { _ ++ _ } + + if(formattingPreferences(AlignParameters)){ + (resultWithNewLines, formatterState, previousLeftFormat) + } else { + (resultWithNewLines, formatResult._2, Some(EnsureNewlineAndIndent(0, paramClause.firstTokenOption))) + } + + }._1 } // TODO: Parts of this function might be useful in implementing other alignment features @@ -1237,8 +1256,9 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi if (hiddenPredecessors(implicitOrFirstToken).containsNewline) { formatResult = formatResult.before(firstToken, formatterState.indent(paramIndent).currentIndentLevelInstruction) - if (!alignParameters) + if (!alignParameters) { paramFormatterState = formatterState.indent(paramIndent) + } } else if (containsNewline(firstParam) && alignParameters) { paramFormatterState = formatterState.alignWithToken(relativeToken) } 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 d8628840..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[_]] = { @@ -212,3 +213,17 @@ case object SpacesAroundMultiImports extends BooleanPreferenceDescriptor { val description = "Place spaces around multi imports (import a.{ b, c, d }" 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 new file mode 100644 index 00000000..88143383 --- /dev/null +++ b/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/MultipleParameterListsFormatterTest.scala @@ -0,0 +1,74 @@ +package com.danieltrinh.scalariform.formatter + +import com.danieltrinh.scalariform.formatter.preferences.{BreakMultipleParameterGroups, FormattingPreferences} +import com.danieltrinh.scalariform.parser.{CompilationUnit, FullDefOrDcl, ScalaParser} + +class MultipleParameterListsFormatterTest extends AbstractFormatterTest { + + override def debug = false + + def parse(parser: ScalaParser) = parser.compilationUnitOrScript() + + type Result = CompilationUnit + + def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0)) + + + { + + implicit val formatting = FormattingPreferences.setPreference(BreakMultipleParameterGroups, true) + + """def f(x: Int) + |(y: Int): Int = { + |} + |""".stripMargin ==> + """def f(x: Int)(y: Int): Int = { + |} + |""".stripMargin + """def f(x: Int) + | (y: Int)(z: Int): Int = { + |} + |""".stripMargin ==> + """def f(x: Int)(y: Int)(z: Int): Int = { + |} + |""".stripMargin + + } + + { + + implicit val formatting = FormattingPreferences.setPreference(BreakMultipleParameterGroups, true) + .setPreference(BreakMultipleParameterGroups.BreakingThreshold, 4) + + """def f(x: Int)(y: Int): Int = { + |} + |""".stripMargin ==> + """def f(x: Int) + | (y: Int): Int = { + |} + |""".stripMargin + + """def f(x: Int) + | (y: Int)(z: Int): Int = { + |} + """.stripMargin ==> + """def f(x: Int) + | (y: Int) + | (z: Int): Int = { + |} + |""".stripMargin + + // 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)) + |}""".stripMargin ==> + """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)) + |}""".stripMargin + + } + + + +}