diff --git a/README.rst b/README.rst old mode 100644 new mode 100755 index 7b735c0f..0246c4cd --- a/README.rst +++ b/README.rst @@ -28,6 +28,31 @@ You can also configure formatting to be run as a save action (Window -> Preferen To set preferences, go to Window -> Preferences -> Scala -> Formatter +Integration with IntelliJ +------------------------- + +IntelliJ already has a built-in Scala code formatter (C-L). +I use the original settings plus `Wraping and Braces` -> `Align columns in case branches`. +In order to achieve exactly the same formatting use the following options:: + + + def formattingPreferences = { + import scalariform.formatter.preferences._ + FormattingPreferences() + .setPreference(AlignParameters, true) + .setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 120) + .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true) // IntelliJ compatible + .setPreference(CompactControlReadability, false) + .setPreference(NoSpacesAroundMultiImports, true) + .setPreference(FormatXml, false) + .setPreference(PreserveSpaceBeforeArguments, true) + .setPreference(IndentWithTabs, false) + .setPreference(SpacesWithinPatternBinders, false) // IntelliJ compatible + } + + Integration with Emacs/ENSIME ----------------------------- @@ -474,6 +499,22 @@ If ``false``,:: case elem@Multi(values@_*) => +chainedPackageClauses +~~~~~~~~~~~~~~~~~~~~~ + +Default: ``false`` + +Example:: +``` + package com.company.analytics.math.curves.interpolators +``` + +Will be reformatted to:: +``` + package com.company.analytics.math + package curves + package interpolators +``` Scala Style Guide ~~~~~~~~~~~~~~~~~ diff --git a/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala old mode 100644 new mode 100755 index 9255a4bc..fedb2ba8 --- a/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala +++ b/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala @@ -1,6 +1,6 @@ package scalariform.formatter -import scalariform.lexer.Token +import scalariform.lexer.{TokenType, Token} import scalariform.lexer.Tokens._ import scalariform.parser._ import scalariform.utils.Utils @@ -81,16 +81,18 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi val newlineBeforeClause = hiddenPredecessors(caseClause.firstToken).containsNewline || previousCaseClauseEndsWithNewline(caseClause, caseClausesAstNode) - // To evaluate whether a clause body is multiline, we ignore a trailing newline: + // To evaluate whether a clause body is multiline, we ignore a trailing newline: val prunedStatSeq = pruneTrailingNewline(statSeq) val clauseBodyIsMultiline = containsNewline(pruneTrailingNewline(statSeq)) || statSeq.firstTokenOption.exists(hiddenPredecessors(_).containsNewline) - if (formattedCasePattern.contains('\n') || (first && !clausesAreMultiline) || (!first && !newlineBeforeClause) || clauseBodyIsMultiline) + if (first && !clausesAreMultiline || !first && !newlineBeforeClause || + !formattingPreferences(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements) && clauseBodyIsMultiline) Right(caseClause) :: otherClausesGrouped else { val arrowAdjust = (if (formattingPreferences(RewriteArrowSymbols)) 1 else casePattern.arrow.length) + 1 - val casePatternLength = formattedCasePattern.length - arrowAdjust + val casePatternLengthConsideringNewLines = formattedCasePattern.split('\n').last.length + val casePatternLength = casePatternLengthConsideringNewLines - arrowAdjust otherClausesGrouped match { case Left(consecutiveSingleLineCaseClauses) :: otherGroups ⇒ Left(consecutiveSingleLineCaseClauses.prepend(caseClause, casePatternLength)) :: otherGroups @@ -99,7 +101,26 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi } } } - groupClauses(caseClausesAstNode.caseClauses, first = true) + + val caseClauses: List[CaseClause] = caseClausesAstNode.caseClauses + + val ranges: List[(Int, Int)] = if (formattingPreferences(AlignSingleLineCaseStatements.GroupByNewLine)) { + val newLinesAt = (caseClauses.zipWithIndex.collect { + case (c, i) if c.tokens.exists(_.isNewlines) => i + 1 + }) + + val newLinesWithBeginAndEnd = (if (newLinesAt.contains(0)) List() else List(0)) ++ newLinesAt ++ List(caseClauses.length) + + newLinesWithBeginAndEnd.zip(newLinesWithBeginAndEnd.tail) + } else { + List(0 -> caseClauses.length) + } + + ranges.foldLeft(List[Either[ConsecutiveSingleLineCaseClauses, CaseClause]]()) { + case (acc, (begin, end)) => + val slice = caseClauses.slice(begin, end) + acc ++ groupClauses(slice, first = true) + } } private case class ConsecutiveSingleLineCaseClauses(clauses: List[CaseClause], largestCasePatternLength: Int, smallestCasePatternLength: Int) { @@ -114,6 +135,21 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi val CasePattern(caseToken: Token, pattern: Expr, guardOption: Option[Guard], arrow: Token) = casePattern var formatResult: FormatResult = NoFormatResult formatResult ++= format(pattern) + + val beginTokensAfterPipe = List(casePattern.pattern.tokens.head) ++ casePattern.pattern.tokens.zip(casePattern.pattern.tokens.tail).collect { + case (Token(PIPE, _, _, _), b) if b.associatedWhitespaceAndComments.containsNewline => b + } + + val alignBeginTokens: Map[Token, IntertokenFormatInstruction] = beginTokensAfterPipe.zip(beginTokensAfterPipe.tail).flatMap { + case (a, b) => if (b.associatedWhitespaceAndComments.containsNewline) { + Map(b -> EnsureNewlineAndIndent(0, Some(a))) + } else { + Map.empty[Token, IntertokenFormatInstruction] + } + }.toMap + + formatResult ++= FormatResult(alignBeginTokens, Map(), Map()) + for (guard ← guardOption) formatResult ++= format(guard) arrowInstructionOpt foreach { instruction ⇒ formatResult = formatResult.before(arrow, instruction) } @@ -149,10 +185,14 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi if separator.isNewline } yield separator - private def previousCaseClauseTrailingNewlineOpt(caseClause: CaseClause, caseClauses: CaseClauses): Option[Token] = - Utils.pairWithPrevious(caseClauses.caseClauses).collect { + private def previousCaseClauseTrailingNewlineOpt(caseClause: CaseClause, caseClauses: CaseClauses): Option[Token] = { + val previousCaseClauseOpt = Utils.pairWithPrevious(caseClauses.caseClauses).collect { case (Some(previousClause), `caseClause`) ⇒ previousClause - }.headOption.flatMap(getTrailingNewline) + }.headOption + val hasNewLine = previousCaseClauseOpt.flatMap(getTrailingNewline) + val hasNewLineAtEnd = previousCaseClauseOpt.flatMap(_.statSeq.tokens.lastOption.filter(_.isNewline)) + hasNewLine.orElse(hasNewLineAtEnd) + } private def previousCaseClauseEndsWithNewline(caseClause: CaseClause, caseClauses: CaseClauses): Boolean = previousCaseClauseTrailingNewlineOpt(caseClause, caseClauses).isDefined diff --git a/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala old mode 100644 new mode 100755 index f06d6804..ef59659c --- a/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala +++ b/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala @@ -636,15 +636,22 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi (CompactEnsuringGap, indentedState) formatResult = formatResult.before(statSeq.firstToken, instruction) formatResult ++= format(params) + + val hasNewScopeAfterArrow = { + val arrowIndex = statSeq.tokens.indexWhere(_.tokenType == ARROW) + val tokenAfterArrow = statSeq.tokens.lift(arrowIndex + 1) + tokenAfterArrow.map(_.tokenType == lbrace.tokenType).getOrElse(false) + } for (firstToken ← subStatSeq.firstTokenOption) { val instruction = - if (hiddenPredecessors(firstToken).containsNewline || containsNewline(subStatSeq)) + if (!hasNewScopeAfterArrow && (hiddenPredecessors(firstToken).containsNewline || containsNewline(subStatSeq))) statFormatterState(subStatSeq.firstStatOpt)(subStatState).currentIndentLevelInstruction else CompactEnsuringGap formatResult = formatResult.before(firstToken, instruction) } - formatResult ++= format(subStatSeq)(subStatState) + val subStatStateAfterArrow = if(hasNewScopeAfterArrow) newFormatterState.indent else subStatState + formatResult ++= format(subStatSeq)(subStatStateAfterArrow) case _ ⇒ val instruction = statSeq.selfReferenceOpt match { case Some((selfReference, arrow)) if !hiddenPredecessors(selfReference.firstToken).containsNewline ⇒ @@ -683,7 +690,7 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi } for (stat ← firstStatOpt) - formatResult ++= format(stat)(firstStatFormatterState) + formatResult ++= format(stat, true)(firstStatFormatterState) for ((semi, otherStatOption) ← otherStats) { @@ -702,7 +709,7 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi CompactEnsuringGap formatResult = formatResult.before(firstToken, instruction) } - formatResult ++= format(otherStat)(otherStatFormatterState) + formatResult ++= format(otherStat, false)(otherStatFormatterState) } } @@ -710,15 +717,47 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi formatResult } - private def format(stat: Stat)(implicit formatterState: FormatterState): FormatResult = + private def format(stat: Stat, firstStat: Boolean)(implicit formatterState: FormatterState): FormatResult = stat match { case expr: Expr ⇒ format(expr) case fullDefOrDcl: FullDefOrDcl ⇒ format(fullDefOrDcl) case import_ : ImportClause ⇒ format(import_) case packageBlock: PackageBlock ⇒ format(packageBlock) + case packageStat: PackageStat ⇒ format(packageStat, firstStat) case _ ⇒ NoFormatResult // TODO } + def format(packageStat: PackageStat, firstPackage: Boolean)(implicit formatterState: FormatterState): FormatResult = { + var formatResult: FormatResult = NoFormatResult + + if (formattingPreferences(ChainedPackageClauses)) { + val PackageStat(packageToken: Token, name: CallExpr) = packageStat + + val packageDepth = if(firstPackage) formattingPreferences(ChainedPackageClauses.PackageDepth) else 1 + + def dotsForPackageNames(name: CallExpr): List[Token] = { + name.exprDotOpt match { + case Some((List(c@CallExpr(_, id, _, _, _)), dot)) => + dot :: dotsForPackageNames(c) + case _ => + Nil + } + } + + val dotsBetweenPackageNames = dotsForPackageNames(name) + + val lineBreaksAfter = dotsBetweenPackageNames.reverse.drop(packageDepth-1) + + for { + token <- lineBreaksAfter + } { + formatResult ++= FormatResult(Map(token -> EnsureNewlineAndIndent(0, Some(packageToken))), Map(), Map()) + } + } + + formatResult + } + def format(packageBlock: PackageBlock)(implicit formatterState: FormatterState): FormatResult = { val PackageBlock(packageToken: Token, name: CallExpr, newlineOpt: Option[Token], lbrace: Token, topStats: StatSeq, rbrace: Token) = packageBlock @@ -909,9 +948,13 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi val newFormatterState = formatterState.copy(inSingleLineBlock = singleLineBlock) if (singleLineBlock) { + if (formattingPreferences(NoSpacesAroundMultiImports)) + formatResult = formatResult.before(firstImportSelector.firstToken, Compact) formatResult ++= format(firstImportSelector) for ((comma, otherImportSelector) ← otherImportSelectors) formatResult ++= format(otherImportSelector) + if (formattingPreferences(NoSpacesAroundMultiImports)) + formatResult = formatResult.before(rbrace, Compact) } else { formatResult = formatResult.before(firstImportSelector.firstToken, formatterState.nextIndentLevelInstruction) formatResult ++= format(firstImportSelector) diff --git a/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala old mode 100644 new mode 100755 index 29cb2e0b..e6c1792e --- a/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala +++ b/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala @@ -221,7 +221,12 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte val replacement = builder.substring(startPos) positionHintOption match { case Some(positionHint) if hiddenTokens.isEmpty ⇒ - Some(TextEdit(positionHint, length = 0, replacement = replacement)) + instruction match { + case EnsureNewlineAndIndent(indentLevel, Some(Token(PACKAGE, _, _, _))) => + Some(TextEdit(positionHint, length = 1, replacement = replacement + "package ")) + case _ => + Some(TextEdit(positionHint, length = 0, replacement = replacement)) + } case _ ⇒ for { firstToken ← hiddenTokens.firstTokenOption @@ -348,7 +353,7 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte return CompactEnsuringGap if (type1 == MINUS && (type2 == INTEGER_LITERAL || type2 == FLOATING_POINT_LITERAL)) return Compact - if (Set(IMPLICIT, VAL, VAR, PRIVATE, PROTECTED, OVERRIDE).contains(type2) && type1 == LPAREN) + if (Set(IMPLICIT, VAL, VAR, PRIVATE, PROTECTED, OVERRIDE, FINAL).contains(type2) && type1 == LPAREN) return Compact if ((type1 == PROTECTED || type1 == PRIVATE) && type2 == LBRACKET) return Compact diff --git a/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala b/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala old mode 100644 new mode 100755 index 48975161..ed73714d --- a/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala +++ b/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala @@ -62,9 +62,9 @@ trait IntegerPreferenceDescriptor extends PreferenceDescriptor[Int] { object AllPreferences { val preferences: List[PreferenceDescriptor[_]] = List(RewriteArrowSymbols, IndentSpaces, SpaceBeforeColon, CompactStringConcatenation, PreserveSpaceBeforeArguments, AlignParameters, DoubleIndentClassDeclaration, FormatXml, IndentPackageBlocks, - AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, IndentLocalDefs, PreserveDanglingCloseParenthesis, + AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, IndentLocalDefs, PreserveDanglingCloseParenthesis, SpaceInsideParentheses, SpaceInsideBrackets, SpacesWithinPatternBinders, MultilineScaladocCommentsStartOnFirstLine, IndentWithTabs, - CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk) + CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk, NoSpacesAroundMultiImports, ChainedPackageClauses, ChainedPackageClauses.PackageDepth) val preferencesByKey: Map[String, PreferenceDescriptor[_]] = { var map: Map[String, PreferenceDescriptor[_]] = Map() @@ -142,6 +142,18 @@ case object AlignSingleLineCaseStatements extends BooleanPreferenceDescriptor { val defaultValue = 40 } + case object AlignMultiLineCaseStatements extends BooleanPreferenceDescriptor { + val key = "alignSingleLineCaseStatements.alignMultiLineCaseStatements" + val description = "Align the arrows of consecutive multi-line case statements" + val defaultValue = false + } + + case object GroupByNewLine extends BooleanPreferenceDescriptor { + val key = "alignSingleLineCaseStatements.groupByNewLine" + val description = "Treat blocks that are separated by newlines independently" + val defaultValue = false + } + } case object IndentLocalDefs extends BooleanPreferenceDescriptor { @@ -196,4 +208,23 @@ case object PlaceScaladocAsterisksBeneathSecondAsterisk extends BooleanPreferenc val key = "placeScaladocAsterisksBeneathSecondAsterisk" val description = "Place Scaladoc asterisks beneath the second asterisk in the opening '/**', as opposed to the first" val defaultValue = false -} \ No newline at end of file +} + +case object NoSpacesAroundMultiImports extends BooleanPreferenceDescriptor { + val key = "noSpacesAroundMultiImports" + val description = "Don't place spaces around multi imports (Java-style)" + val defaultValue = false +} + +case object ChainedPackageClauses extends BooleanPreferenceDescriptor { + val key = "chainedPackageClauses" + val description = "Break up chained package clauses" + val defaultValue = false + + case object PackageDepth extends IntegerPreferenceDescriptor { + val key = "chainedPackageClauses.packageDepth" + val description = "Depth of package nesting" + val preferenceType = IntegerPreference(1, 100) + val defaultValue = 4 + } +} diff --git a/scalariform/src/main/scala/scalariform/lexer/Token.scala b/scalariform/src/main/scala/scalariform/lexer/Token.scala index 365122eb..6e5cb72b 100644 --- a/scalariform/src/main/scala/scalariform/lexer/Token.scala +++ b/scalariform/src/main/scala/scalariform/lexer/Token.scala @@ -27,6 +27,8 @@ case class Token(tokenType: TokenType, text: String, offset: Int, rawText: Strin def isNewline = tokenType.isNewline + def isNewlines = tokenType.isNewlines + @deprecated(message = "Use text instead" /*, since = "0.1.2"*/ ) def getText = text diff --git a/scalariform/src/main/scala/scalariform/lexer/TokenType.scala b/scalariform/src/main/scala/scalariform/lexer/TokenType.scala index 2f51e561..fb64f3ba 100644 --- a/scalariform/src/main/scala/scalariform/lexer/TokenType.scala +++ b/scalariform/src/main/scala/scalariform/lexer/TokenType.scala @@ -2,7 +2,9 @@ package scalariform.lexer case class TokenType(name: String, isXml: Boolean = false) { - def isNewline = this == Tokens.NEWLINE || this == Tokens.NEWLINES + def isNewline = this == Tokens.NEWLINE || isNewlines + + def isNewlines = this == Tokens.NEWLINES def isKeyword = Tokens.KEYWORDS contains this diff --git a/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala old mode 100644 new mode 100755 index a2e106a6..06b20136 --- a/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala +++ b/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala @@ -306,4 +306,218 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest { | case elem @ Multi(values @ _*) => |}""" + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + + """a match { + |case "once" => + |println("einmal") + |println("nochmal") + |case "many times" => + |println("again") + |println("multiline") + |case _ => + |println("again") + |println("multiline") + |}""" ==> + """a match { + | case "once" => + | println("einmal") + | println("nochmal") + | case "many times" => + | println("again") + | println("multiline") + | case _ => + | println("again") + | println("multiline") + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, false) + + """a match { + |case "once" => + |println("einmal") + |println("nochmal") + |case "many times" => + |println("again") + |println("multiline") + |case _ => + |println("again") + |println("multiline") + | + |case "after a newline" => + |println("IntelliJ") + |println("formats") + |case "next lines" => + |println("separately") + |}""" ==> + """a match { + | case "once" => + | println("einmal") + | println("nochmal") + | case "many times" => + | println("again") + | println("multiline") + | case _ => + | println("again") + | println("multiline") + | + | case "after a newline" => + | println("IntelliJ") + | println("formats") + | case "next lines" => + | println("separately") + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true) + + """a match { + |case "once" => + |println("einmal") + |println("nochmal") + |case "many times" => + |println("again") + |println("multiline") + |case _ => + |println("again") + |println("multiline") + | + |case "after a newline" => + |println("IntelliJ") + |println("formats") + |case "next lines" => + |println("separately") + |}""" ==> + """a match { + | case "once" => + | println("einmal") + | println("nochmal") + | case "many times" => + | println("again") + | println("multiline") + | case _ => + | println("again") + | println("multiline") + | + | case "after a newline" => + | println("IntelliJ") + | println("formats") + | case "next lines" => + | println("separately") + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 200) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true) + + """x match { + |case 1 | 2 | + |3 | 4 | + |5 | 6 => 1 + |case 7 | 8 => 1 + |}""" ==> + """x match { + | case 1 | 2 | + | 3 | 4 | + | 5 | 6 => 1 + | case 7 | 8 => 1 + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + + """x match { case _: X => Y }""" ==> + """x match { case _: X => Y }""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 200) + .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true) + + """|x match { + | case 1 => A + | case 1234 | + | 5678 => A + | case 5 => A + | case 12345678 => A + |}""" ==> + """|x match { + | case 1 => A + | case 1234 | + | 5678 => A + | case 5 => A + | case 12345678 => A + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 200) + + """|x match { + |case AA => a + |case B => b + |}""" ==> + """|x match { + | case AA => a + | case B => b + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + + """|x match { + |case AA => (s: Int) => 1 + |case B => (s: Int) => 2 + |}""" ==> + """|x match { + | case AA => (s: Int) => 1 + | case B => (s: Int) => 2 + |}""" + } + + { + implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true) + .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 160) + .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true) + .setPreference(SpacesWithinPatternBinders, false) + + """|pairs.flatMap { + | case (p1@(t1, MandatoryGridPoint(true) | ExtremalGridPoint), + | (t2, MandatoryGridPoint(true) | ExtremalGridPoint)) => + | val fillPointTime = (t1 + t2) / 2 + | val fillPoint = (fillPointTime, FillingGridPoint) + | Seq(p1, fillPoint) + | case (p1, p2) => Seq(p1) + |}""" ==> + """|pairs.flatMap { + | case (p1@(t1, MandatoryGridPoint(true) | ExtremalGridPoint), + | (t2, MandatoryGridPoint(true) | ExtremalGridPoint)) => + | val fillPointTime = (t1 + t2) / 2 + | val fillPoint = (fillPointTime, FillingGridPoint) + | Seq(p1, fillPoint) + | case (p1, p2) => Seq(p1) + |}""" + } + } diff --git a/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala old mode 100644 new mode 100755 index bb85f5a3..8b3427ad --- a/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala +++ b/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala @@ -771,6 +771,29 @@ class MiscExpressionFormatterTest extends AbstractExpressionFormatterTest { | b => c |}""" + """|a map { + |q => { + |2 * q + |} + |}""" ==> + """|a map { + | q => { + | 2 * q + | } + |}""" + + """|a map { + |q => + |{ + |2 * q + |} + |}""" ==> + """|a map { + | q => { + | 2 * q + | } + |}""" + "f()[Foo]" ==> "f()[Foo]" "a [ b . C ] [ d . E ] [ f . G ] " ==> "a[b.C][d.E][f.G]" diff --git a/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala old mode 100644 new mode 100755 index 4634e8d5..6301657d --- a/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala +++ b/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala @@ -63,5 +63,32 @@ class PackageFormatterTest extends AbstractFormatterTest { } + { + implicit val formattingPreferences = FormattingPreferences.setPreference(ChainedPackageClauses, true) + + """package a.b.c.d.e.f + |""" ==> + """package a.b.c.d + |package e + |package f + |""" + + """package com.company.analytics.math.curves.interpolators + |""" ==> + """package com.company.analytics.math + |package curves + |package interpolators + |""" + + """package a.b.c.d.e.f + |package g.h + |""" ==> + """package a.b.c.d + |package e + |package f + |package g + |package h + |""" + } } diff --git a/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala index 972bfbef..cc0a2783 100644 --- a/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala +++ b/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala @@ -195,6 +195,7 @@ class TemplateFormatterTest extends AbstractFormatterTest { "class A(private val b: C)" ==> "class A(private val b: C)" "class A(protected val b: C)" ==> "class A(protected val b: C)" "class A(override val b: C)" ==> "class A(override val b: C)" + "class A(final val b: C)" ==> "class A(final val b: C)" """class C[T <: A {val n: Int |val m :Int}]""" ==>