diff --git a/.gitignore b/.gitignore
index e9269c4c..b02ca0f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,4 @@ docs/build
nohup.out
.history
.cache
+.idea/
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..0b421590
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,7 @@
+language: scala
+scala:
+ - 2.10.3
+ - 2.9.3
+jdk:
+ - oraclejdk7
+ - openjdk7
\ No newline at end of file
diff --git a/README.rst b/README.rst
index 7b735c0f..28989499 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,9 @@
Scalariform
===========
+.. image:: https://travis-ci.org/daniel-trinh/scalariform.png?branch=master
+ :target: https://travis-ci.org/daniel-trinh/scalariform
+
Scalariform is a code formatter for Scala. It's available as a
library, a stand-alone command line tool, or via integrations with
various editors and build tools (listed below).
@@ -14,6 +17,13 @@ Scalariform is licenced under `The MIT Licence`_.
.. _Scala Style Guide: http://davetron5000.github.com/scala-style/
.. _The MIT Licence: http://www.opensource.org/licenses/mit-license.php
+Integration with sbt
+--------------------
+
+A version for sbt >= 0.13.x has been written by Peter Vlugter: https://github.com/daniel-trinh/sbt-scalariform
+
+Please see https://github.com/sbt/sbt-scalariform for older versions of sbt.
+
Integration with Eclipse
------------------------
@@ -22,7 +32,7 @@ Scala IDE for Eclipse uses Scalariform for code formatting:
- Right click in the editor -> Source -> Format
- Press Ctrl-Shift-F
-If you select some lines, only those will be formatted.
+If you select some lines, only those will be formatted.
You can also configure formatting to be run as a save action (Window -> Preferences -> Java -> Editor -> Save Actions).
@@ -31,7 +41,7 @@ To set preferences, go to Window -> Preferences -> Scala -> Formatter
Integration with Emacs/ENSIME
-----------------------------
-"`ENSIME`_ uses the Scalariform library to format Scala sources. Type C-c C-v f to format the current buffer."
+"`ENSIME`_ uses the Scalariform library to format Scala sources. Type C-c C-v f to format the current buffer."
http://aemon.com/file_dump/ensime_manual.html#tth_sEc4.8
@@ -73,16 +83,6 @@ Usage::
-Integration with sbt
---------------------
-
-`sbt-scalariform`_, written by Olivier Michallat, provides an sbt plugin contributing formatting actions for sbt 0.7.x.
-
-A version for sbt 0.10.x has been written by Peter Vlugter: https://github.com/typesafehub/sbt-scalariform
-
-.. _sbt-scalariform: http://github.com/olim7t/sbt-scalariform
-
-
Integration with TextMate
-------------------------
@@ -123,26 +123,72 @@ alignParameters
Default: ``false``
-Align class/function parameters in the same column. For example, if ``false``, then::
+Align class/function parameters (modifiers and name, type, and defaults) in three columns.
+
+For example, if ``false``, then::
class Person(name: String,
- age: Int,
+ age: Int = 24,
birthdate: Date,
- astrologicalSign: String,
+ astrologicalSign: String = "libra",
shoeSize: Int,
favoriteColor: java.awt.Color)
If ``true``, then::
- class Person(name: String,
- age: Int,
- birthdate: Date,
- astrologicalSign: String,
- shoeSize: Int,
- favoriteColor: java.awt.Color)
+ class Person(name: String,
+ age: Int = 24,
+ birthdate: Date,
+ astrologicalSign: String = "libra",
+ shoeSize: Int,
+ favoriteColor: java.awt.Color)
+
+This will also place the "implicit" keyword in parameters on it's own line, whenever
+the parameter being formatted contains a newline::
+
+For example, if ``false``, then::
+
+ def formatBirthDate(
+ implicit birthdate: Date = Date("11/11/11"),
+ birthtime: Time): DateTime
+
+If ``true``, then::
+
+ def formatBirthDate(
+ implicit
+ birthdate: Date = Date("11/11/11"),
+ birthtime: Time): DateTime
This option is disabled if ``indentWithTabs`` is ``true``.
+
+alignArguments
+~~~~~~~~~~~~~~
+
+Default: ``false``
+
+Aligns mult-line arguments
+
+For example, if ``false``, then::
+
+ Cake(candles = 10,
+ frostingFlavor = Vanilla,
+ layerFlavor = Chocolate,
+ icecream = true
+ )
+
+If ``true``, then::
+
+ Cake(
+ candles = 10,
+ frostingFlavor = Vanilla,
+ layerFlavor = Chocolate,
+ icecream = true
+ )
+
+This option is disabled if ``indentWithTabs`` is ``true``.
+
+
alignSingleLineCaseStatements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -204,7 +250,7 @@ using `Compact Control Readability`_ style:
try {
foo()
- }
+ }
catch {
case _ => bar()
}
@@ -319,7 +365,7 @@ indentSpaces
Default: ``2``
-The number of spaces to use for each level of indentation.
+The number of spaces to use for each level of indentation.
This option is ignored if ``indentWithTabs`` is ``true``.
@@ -330,7 +376,7 @@ Default: ``false``
Use a tab for each level of indentation. When set to ``true``, this
ignores any setting given for ``indentSpaces``. In addition, for the
-moment, ``alignSingleLineCaseStatements`` and ``alignParameters``
+moment, ``alignSingleLineCaseStatements``, ``alignArguments``, and ``alignParameters``
options are not supported when indenting with tabs, and XML
indentation is handled differently.
@@ -341,14 +387,14 @@ Default: ``false``
If ``true``, start a multi-line Scaladoc comment body on same line as the opening comment delimiter::
- /** This method applies f to each
+ /** This method applies f to each
* element of the given list.
*/
If ``false``, start the comment body on a separate line below the opening delimiter::
- /**
- * This method applies f to each
+ /**
+ * This method applies f to each
* element of the given list.
*/
@@ -358,7 +404,7 @@ preserveDanglingCloseParenthesis
Default: ``false``
If ``true``, it will keep a newline before a close parenthesis ')' in an
-argument expression. For example::
+argument expression or parameter clause. For example::
val book = Book(
name = "Name",
@@ -373,6 +419,21 @@ If ``false``, the parenthesis will be joined to the end of the argument list::
author = "Author",
rating = 5)
+
+Or with parameters, if ``true``::
+
+ def findBooks(
+ author: Option[String] = None,
+ title: Option[String] = None
+ ): List[Book]
+
+If ``false``::
+
+ def findBooks(
+ author: Option[String] = None,
+ title: Option[String] = None): List[Book]
+
+
placeScaladocAsterisksBeneathSecondAsterisk
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -381,14 +442,14 @@ Default: ``false``
If ``true``, Scaladoc asterisks will be placed beneath the second asterisk::
/** Wibble
- * wobble
+ * wobble
*/
class A
Otherwise, if ``false``, beneath the first asterisk::
/** Wibble
- * wobble
+ * wobble
*/
class A
@@ -474,6 +535,18 @@ If ``false``,::
case elem@Multi(values@_*) =>
+spacesAroundMultiImports
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Default: ``true``
+
+Whether or not to add spaces around mutli-imports. For example, If ``true``, then::
+
+ import a.{ b, c, d }
+
+If ``false``, then::
+
+ import a.{b,c,d}
Scala Style Guide
~~~~~~~~~~~~~~~~~
@@ -487,14 +560,14 @@ make uncompliant source more compliant.
============================ ========= =========
Preference Value Default?
============================ ========= =========
-alignParameters ``false``
-compactStringConcatenation ``false``
+alignParameters ``false``
+compactStringConcatenation ``false``
doubleIndentClassDeclaration ``true`` No
-indentSpaces ``2``
+indentSpaces ``2``
placeScaladocAsterisksBeneathSecondAsterisk ``true`` No
-preserveSpaceBeforeArguments ``false``
-rewriteArrowSymbols ``false``
-spaceBeforeColon ``false``
+preserveSpaceBeforeArguments ``false``
+rewriteArrowSymbols ``false``
+spaceBeforeColon ``false``
spaceInsideBrackets ``false``
spaceInsideParentheses ``false``
============================ ========= =========
@@ -510,24 +583,24 @@ format: [ON|OFF]
Disables the formatter for selective portions of a source file::
// format: OFF <-- this directive disables formatting from this point
- class AsciiDSL {
+ class AsciiDSL {
n ¦- "1" -+ { n: Node =>
- n ¦- "i"
- n ¦- "ii"
- n ¦- "iii"
- n ¦- "iv"
+ n ¦- "i"
+ n ¦- "ii"
+ n ¦- "iii"
+ n ¦- "iv"
n ¦- "v"
}
n ¦- "2"
n ¦- "3" -+ { n: Node =>
- n ¦- "i"
+ n ¦- "i"
n ¦- "ii" -+ { n: Node =>
n ¦- "a"
n ¦- "b"
n ¦- "c"
}
- n ¦- "iii"
- n ¦- "iv"
+ n ¦- "iii"
+ n ¦- "iv"
n ¦- "v"
}
// format: ON <-- formatter resumes from this point
diff --git a/cli/src/main/scala/scalariform/commandline/Main.scala b/cli/src/main/scala/scalariform/commandline/Main.scala
index 3cd343b6..9dea118d 100644
--- a/cli/src/main/scala/scalariform/commandline/Main.scala
+++ b/cli/src/main/scala/scalariform/commandline/Main.scala
@@ -13,7 +13,7 @@ import scalariform.ScalaVersions
object Main {
def main(args: Array[String]) {
- exit(if (process(args)) 1 else 0)
+ sys.exit(if (process(args)) 1 else 0)
}
def process(args: Array[String]): Boolean = {
diff --git a/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala b/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala
index 143b3deb..bd0e8045 100644
--- a/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala
+++ b/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala
@@ -67,11 +67,15 @@ object CorpusScanner extends SpecificFormatter {
}
-object Runner extends App {
+object Runner {
val corpusDir = "/home/matthew/coding/scala-corpus/repos2"
// val corpusDir = "/home/matt/scala-corpus"
+ def main(args: Array[String]) {
+ formatInPlace()
+ }
+
def checkParser() {
val files = ScalaFileWalker.findScalaFiles(corpusDir)
var count = 0
@@ -101,7 +105,4 @@ object Runner extends App {
}
println(count + " files formatted.")
}
-
- formatInPlace()
-
-}
+}
\ No newline at end of file
diff --git a/misc/src/main/scala/scalariform/gui/FormatterFrame.scala b/misc/src/main/scala/scalariform/gui/FormatterFrame.scala
index f12d1c27..c5a760a9 100644
--- a/misc/src/main/scala/scalariform/gui/FormatterFrame.scala
+++ b/misc/src/main/scala/scalariform/gui/FormatterFrame.scala
@@ -426,4 +426,3 @@ object Samples {
|}""".stripMargin
} // format: ON
-
diff --git a/misc/src/main/scala/scalariform/gui/Main.scala b/misc/src/main/scala/scalariform/gui/Main.scala
index 35599e9c..1da7b728 100644
--- a/misc/src/main/scala/scalariform/gui/Main.scala
+++ b/misc/src/main/scala/scalariform/gui/Main.scala
@@ -3,14 +3,14 @@ package scalariform.gui
import scalariform.utils.Utils._
import javax.swing.JFrame
-object Main extends App {
+object Main {
- onSwingThread {
- val frame = new FormatterFrame
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
- frame.setSize(1280, 600)
- frame.setVisible(true)
+ def main(args: Array[String]) {
+ onSwingThread {
+ val frame = new FormatterFrame
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
+ frame.setSize(1280, 600)
+ frame.setVisible(true)
+ }
}
-
-}
-
+}
\ No newline at end of file
diff --git a/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala b/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala
index edc26d7d..5fad7939 100644
--- a/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala
+++ b/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala
@@ -31,7 +31,7 @@ class ParseTreeModel(rootAstNode: AstNode) extends TreeModel {
val fields = astNode.getFields
lazy val children = fields flatMap {
- case (_, None) | (_, Nil) ⇒ None
+ case (_, None) | (_, Nil) ⇒ None
case (fieldName, value) ⇒ Some(makeTreeNode(value.asInstanceOf[AnyRef], fieldName))
}
diff --git a/misc/src/main/scala/scalariform/gui/SwingUtils.scala b/misc/src/main/scala/scalariform/gui/SwingUtils.scala
index 7b5180d2..37a6d2db 100644
--- a/misc/src/main/scala/scalariform/gui/SwingUtils.scala
+++ b/misc/src/main/scala/scalariform/gui/SwingUtils.scala
@@ -4,10 +4,9 @@ import javax.swing.event.ListSelectionListener
import javax.swing.event.ListSelectionEvent
object SwingUtils {
-
+
implicit def fn2ListSelectionListener(handler: ListSelectionEvent ⇒ Unit): ListSelectionListener = new ListSelectionListener() {
def valueChanged(e: ListSelectionEvent) = handler(e)
}
-
}
\ No newline at end of file
diff --git a/project/Build.scala b/project/Build.scala
index b84ef8d1..adef0880 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -8,16 +8,30 @@ import com.typesafe.sbt.SbtScalariform.ScalariformKeys
import scalariform.formatter.preferences._
object ScalariformBuild extends Build {
+
+ // This is to make sure nobody tries to compile with 1.6 as the target JDK.
+ // Not clear if this will actually work on 1.8, needs to be tested when that is out.
+ val specVersion = sys.props("java.specification.version")
+ val mismatchedSpecificationMessage =
+ """|Java 1.7 is required for building Scalariform.
+ |
+ |This is due to a dependency on the javax.swing library, which
+ |had an API change from 1.6 to 1.7.
+ |
+ |Using 1.7 to build requires setting SBT to use JDK 1.7 or higher -- if SBT is
+ |booting on JDK 1.6, you will get a javax.swing related compilation error.""".stripMargin
+ assert(specVersion == "1.7", mismatchedSpecificationMessage)
lazy val commonSettings = Defaults.defaultSettings ++ SbtScalariform.defaultScalariformSettings ++ Seq(
- organization := "org.scalariform",
+ organization := "com.danieltrinh",
version := "0.1.5-SNAPSHOT",
- scalaVersion := "2.10.0",
+ scalaVersion := "2.10.3",
crossScalaVersions := Seq(
- // "2.11.0-M2",
+ "2.11.0-M8",
+ "2.11.0-M7",
"2.10.0", "2.10.1",
- "2.9.3", "2.9.2", "2.9.1-1", "2.9.1", "2.9.0-1", "2.9.0",
- "2.8.2", "2.8.1", "2.8.0"),
+ "2.9.3", "2.9.2", "2.9.1-1", "2.9.1", "2.9.0-1", "2.9.0"
+ ),
exportJars := true, // Needed for cli oneJar
retrieveManaged := true,
scalacOptions += "-deprecation",
@@ -34,18 +48,33 @@ object ScalariformBuild extends Build {
publish := (),
publishLocal := ())) aggregate (scalariform, cli, misc)
+ implicit class Regex(sc: StringContext) {
+ def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
+ }
+
def getScalaTestDependency(scalaVersion: String) = scalaVersion match {
- case "2.8.0" ⇒ "org.scalatest" %% "scalatest" % "1.3.1.RC2" % "test"
- case "2.10.0" ⇒ "org.scalatest" %% "scalatest" % "1.9.1" % "test"
- case "2.10.1" ⇒ "org.scalatest" %% "scalatest" % "1.9.1" % "test"
- case "2.9.3" ⇒ "org.scalatest" %% "scalatest" % "1.9.1" % "test"
- case _ ⇒ "org.scalatest" %% "scalatest" % "1.7.2" % "test"
+ case "2.11.0-M8" ⇒ "org.scalatest" %% s"scalatest" % "2.1.RC1" % "test"
+ case "2.11.0-M7" ⇒ "org.scalatest" %% s"scalatest" % "2.0.1-SNAP4" % "test"
+ case r"2.10.\d+" ⇒ "org.scalatest" % "scalatest_2.10" % "2.0" % "test"
+ case "2.9.3" ⇒ "org.scalatest" %% "scalatest" % "1.9.1" % "test"
+ case _ ⇒ "org.scalatest" %% "scalatest" % "1.7.2" % "test"
+ }
+
+ def get2_11Dependencies(scalaVersion: String): List[ModuleID] = scalaVersion match {
+ case r"2.11.0-M\d" => List(
+ "org.scala-lang.modules" %% "scala-xml" % "1.0.0-RC7",
+ "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.0-RC5"
+ )
+ case _ => Nil
}
lazy val scalariform: Project = Project("scalariform", file("scalariform"), settings =
subprojectSettings ++ sbtbuildinfo.Plugin.buildInfoSettings ++ eclipseSettings ++
Seq(
- libraryDependencies <<= (scalaVersion, libraryDependencies) { (sv, deps) ⇒ deps :+ getScalaTestDependency(sv) },
+ libraryDependencies <<= (scalaVersion, libraryDependencies) { (sv, deps) ⇒
+ deps ++ get2_11Dependencies(sv) :+ getScalaTestDependency(sv)
+ },
+ testOptions in Test += Tests.Argument("-oI"),
pomExtra := pomExtraXml,
publishMavenStyle := true,
publishArtifact in Test := false,
@@ -57,8 +86,10 @@ object ScalariformBuild extends Build {
publishTo <<= isSnapshot(getPublishToRepo)))
def getPublishToRepo(isSnapshot: Boolean) =
- if (isSnapshot) Some("snapshots" at "https://oss.sonatype.org/content/repositories/snapshots")
- else Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2")
+ if (isSnapshot)
+ Some("snapshots" at "https://oss.sonatype.org/content/repositories/snapshots")
+ else
+ Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2")
lazy val cli = Project("cli", file("cli"), settings = subprojectSettings ++ SbtOneJar.oneJarSettings ++
Seq(
@@ -88,8 +119,8 @@ object ScalariformBuild extends Build {
- git@github.com:mdr/scalariform.git
- scm:git:git@github.com:mdr/scalariform
+ git@github.com:daniel-trinh/scalariform.git
+ scm:git:git@github.com:daniel-trinh/scalariform
@@ -97,6 +128,11 @@ object ScalariformBuild extends Build {
Matt Russell
https://github.com/mdr/
+
+ daniel-trinh
+ Daniel Trinh
+ https://github.com/daniel-trinh/
+
-}
+}
\ No newline at end of file
diff --git a/project/build.properties b/project/build.properties
index 9b860e23..37b489cb 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.12.3
+sbt.version=0.13.1
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 4a817d0f..fcd57349 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,18 +1,15 @@
-resolvers += Classpaths.typesafeResolver
+resolvers += Classpaths.typesafeReleases
addSbtPlugin("com.github.retronym" % "sbt-onejar" % "0.8")
resolvers += Classpaths.typesafeSnapshots
-
-addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.2.0")
-addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.0.1")
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")
-resolvers += Resolver.url("sbt-plugin-releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)
+addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.2.1")
-addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8")
+addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.1")
-addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.2.2")
-
-retrieveManaged := true
+addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.3.0")
+retrieveManaged := true
\ No newline at end of file
diff --git a/project/project/plugins.sbt b/project/project/plugins.sbt
index 4393611d..21f94b2c 100644
--- a/project/project/plugins.sbt
+++ b/project/project/plugins.sbt
@@ -1,4 +1,4 @@
resolvers += Classpaths.typesafeSnapshots
-addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.2")
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")
diff --git a/scalariform/src/main/scala/scalariform/formatter/Alignment.scala b/scalariform/src/main/scala/scalariform/formatter/Alignment.scala
new file mode 100644
index 00000000..626e8d8c
--- /dev/null
+++ b/scalariform/src/main/scala/scalariform/formatter/Alignment.scala
@@ -0,0 +1,59 @@
+package scalariform.formatter
+
+import scalariform.parser._
+import Math._
+import scalariform.formatter.preferences._
+
+// For now, this is just a place to store alignment related functionality.
+// TOOD: refactor duplicate behavior in here
+object Alignment {
+ type EitherAlignableParam = Either[ConsecutiveSingleLineParams, Param]
+ type EitherAlignableEqualsExpr = Either[ConsecutiveSingleLineEqualsExprs, CallExpr]
+ type EitherAlignableCaseClause = Either[ConsecutiveSingleLineCaseClauses, CaseClause]
+
+ case class ConsecutiveSingleLineParams(params: List[Param], maxSectionLengths: ParamSectionLengths, thisSectionLengths: ParamSectionLengths) {
+ def prepend(param: Param, newLengths: ParamSectionLengths): ConsecutiveSingleLineParams = {
+ ConsecutiveSingleLineParams(param :: params, maxSectionLengths.max(newLengths), thisSectionLengths)
+ }
+
+ // Splits the head param off, returning it and the remaining params.
+ // This doesn't recalculate section lengths.
+ def pop: (Option[Param], ConsecutiveSingleLineParams) = params match {
+ case param :: remainingParams ⇒
+ (Some(param), copy(params = remainingParams))
+ case Nil ⇒
+ (None, copy(params = Nil))
+ }
+ }
+
+ case class ConsecutiveSingleLineEqualsExprs(
+ equalsExprs: List[EqualsExpr],
+ largestIdLength: Int) {
+
+ def prepend(equalsExpr: EqualsExpr, length: Int) = {
+ ConsecutiveSingleLineEqualsExprs(equalsExpr :: equalsExprs, max(length, largestIdLength))
+ }
+ }
+
+ case class ConsecutiveSingleLineCaseClauses(
+ clauses: List[CaseClause],
+ largestCasePatternLength: Int,
+ smallestCasePatternLength: Int) {
+ def prepend(clause: CaseClause, length: Int) =
+ ConsecutiveSingleLineCaseClauses(clause :: clauses, max(length, largestCasePatternLength), min(length, smallestCasePatternLength))
+
+ def patternLengthRange = largestCasePatternLength - smallestCasePatternLength
+
+ }
+
+ case class ParamSectionLengths(prefixLength: Int, idLength: Int, prefixAndIdLength: Int, typeLength: Int) {
+ def max(newParamSectionLength: ParamSectionLengths): ParamSectionLengths = {
+ val ParamSectionLengths(newPrefixLength, newIdLength, newPrefixAndIdLength, newTypeLength) = newParamSectionLength
+ ParamSectionLengths(
+ math.max(prefixLength, newPrefixLength),
+ math.max(idLength, newIdLength),
+ math.max(prefixAndIdLength, newPrefixAndIdLength),
+ math.max(typeLength, newTypeLength))
+ }
+ }
+}
\ No newline at end of file
diff --git a/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
index 9255a4bc..9235dd0a 100644
--- a/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
@@ -7,6 +7,7 @@ import scalariform.utils.Utils
import scalariform.utils.TextEditProcessor
import scalariform.utils.BooleanLang._
import scalariform.formatter.preferences._
+import Alignment._
import PartialFunction._
import scala.math.{ max, min }
@@ -61,28 +62,23 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
formatResult
}
- private def groupClauses(caseClausesAstNode: CaseClauses): List[Either[ConsecutiveSingleLineCaseClauses, CaseClause]] = {
+ private def groupClauses(caseClausesAstNode: CaseClauses): List[EitherAlignableCaseClause] = {
val clausesAreMultiline = containsNewline(caseClausesAstNode) || hiddenPredecessors(caseClausesAstNode.firstToken).containsNewline
- def groupClauses(caseClauses: List[CaseClause], first: Boolean): List[Either[ConsecutiveSingleLineCaseClauses, CaseClause]] =
+ def groupClauses(caseClauses: List[CaseClause], first: Boolean): List[EitherAlignableCaseClause] =
caseClauses match {
case Nil ⇒ Nil
case (caseClause @ CaseClause(casePattern, statSeq)) :: otherClauses ⇒
val otherClausesGrouped = groupClauses(otherClauses, first = false)
- val formattedCasePattern = {
- val casePatternSource = getSource(casePattern)
- val casePatternFormatResult = formatCasePattern(casePattern)(FormatterState(indentLevel = 0))
- val offset = casePattern.firstToken.offset
- val edits = writeTokens(casePatternSource, casePattern.tokens, casePatternFormatResult, offset)
- TextEditProcessor.runEdits(casePatternSource, edits)
+ val formattedCasePattern = formattedAstNode(casePattern) {
+ formatCasePattern(casePattern)(FormatterState(indentLevel = 0))
}
val newlineBeforeClause = hiddenPredecessors(caseClause.firstToken).containsNewline ||
previousCaseClauseEndsWithNewline(caseClause, caseClausesAstNode)
// 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)
@@ -102,14 +98,6 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
groupClauses(caseClausesAstNode.caseClauses, first = true)
}
- private case class ConsecutiveSingleLineCaseClauses(clauses: List[CaseClause], largestCasePatternLength: Int, smallestCasePatternLength: Int) {
- def prepend(clause: CaseClause, length: Int) =
- ConsecutiveSingleLineCaseClauses(clause :: clauses, max(length, largestCasePatternLength), min(length, smallestCasePatternLength))
-
- def patternLengthRange = largestCasePatternLength - smallestCasePatternLength
-
- }
-
private def formatCasePattern(casePattern: CasePattern, arrowInstructionOpt: Option[PlaceAtColumn] = None)(implicit formatterState: FormatterState): FormatResult = {
val CasePattern(caseToken: Token, pattern: Expr, guardOption: Option[Guard], arrow: Token) = casePattern
var formatResult: FormatResult = NoFormatResult
@@ -164,5 +152,4 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
case Some((separator, None)) if separator.isNewline ⇒ statSeq.copy(otherStats = statSeq.otherStats.init)
case _ ⇒ statSeq
}
-
-}
+}
\ No newline at end of file
diff --git a/scalariform/src/main/scala/scalariform/formatter/CommentFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/CommentFormatter.scala
index 42ae48b0..ad49d759 100644
--- a/scalariform/src/main/scala/scalariform/formatter/CommentFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/CommentFormatter.scala
@@ -14,7 +14,8 @@ trait CommentFormatter { self: HasFormattingPreferences with ScalaFormatter ⇒
val (contents, _) = rest.splitAt(rest.length - "*/".length)
val firstLine :: otherLines = contents.split("""\r?\n([ \t]*(\*(?!/))?)?""", Integer.MAX_VALUE).toList
val afterStarSpaces = if (formattingPreferences(MultilineScaladocCommentsStartOnFirstLine)) 2 else 1
- val adjustedLines = dropInitialSpaces(firstLine, 1) :: (otherLines map { dropInitialSpaces(_, afterStarSpaces) })
+ val initialSpaces = firstLine takeWhile (_.isWhitespace)
+ val adjustedLines = dropInitialSpaces(firstLine, initialSpaces.size) :: (otherLines map { dropInitialSpaces(_, afterStarSpaces) })
// val adjustedLines map { line ⇒ if (line startsWith "*/") "*" + line else line }
(start, adjustedLines)
}
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 4303b947..b7e55b2f
--- a/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala
@@ -4,9 +4,10 @@ import scalariform.lexer.Chars
import scalariform.lexer.Token
import scalariform.lexer.Tokens._
import scalariform.parser._
-import scalariform.utils.Utils
+import scalariform.utils.{ TextEditProcessor, Utils }
import scalariform.formatter.preferences._
import scala.PartialFunction._
+import Alignment._
trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter with HasHiddenTokenInfo with TypeFormatter with TemplateFormatter with ScalaFormatter with XmlFormatter with CaseClauseFormatter ⇒
@@ -114,8 +115,19 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
case (PrefixExprElement(_), _) ⇒ if (Chars.isOperatorPart(element.firstToken.text(0))) CompactEnsuringGap else Compact
case (Argument(_), _) ⇒ Compact
case (_, _: ArgumentExprs) if formattingPreferences(PreserveSpaceBeforeArguments) ⇒ CompactPreservingGap // TODO: Probably not needed now with CallExpr
- case (_, _) if element.firstTokenOption exists { firstToken ⇒ newlineBefore(firstToken) && !(Set(COMMA, COLON) contains firstToken.tokenType) } ⇒
- currentFormatterState = currentFormatterState.indentForExpressionBreakIfNeeded
+ case (_, elem) if element.firstTokenOption exists { firstToken ⇒ newlineBefore(firstToken) && !(Set(COMMA, COLON) contains firstToken.tokenType) } ⇒
+ val isNestedArgument = elem match {
+ case Argument(Expr(CallExpr(_, _, _, moreArgs, _) :: tail)) if moreArgs.isEmpty ⇒ false
+ case Argument(Expr(EqualsExpr(_, _, Expr(headExpr :: innerTail)) :: tail)) ⇒ headExpr match {
+ case CallExpr(_, _, _, moreArgs, _) ⇒ if (moreArgs.isEmpty) false else true
+ case _ ⇒ false
+ }
+ case _ ⇒ true
+ }
+
+ if (isNestedArgument)
+ currentFormatterState = currentFormatterState.indentForExpressionBreakIfNeeded
+
currentFormatterState.currentIndentLevelInstruction
}
@@ -273,17 +285,127 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
def format(argumentExprs: ArgumentExprs)(implicit formatterState: FormatterState): (FormatResult, FormatterState) = argumentExprs match {
case BlockArgumentExprs(contents) ⇒ (format(contents), formatterState)
- case ParenArgumentExprs(lparen, contents, rparen) ⇒
+ case args @ ParenArgumentExprs(lparen, contents, rparen) ⇒
var currentFormatterState = formatterState
var formatResult: FormatResult = NoFormatResult
- val (contentsFormatResult, updatedFormatterState) = formatExprElements(GeneralTokens(List(lparen)) :: contents)
+
+ val (contentsFormatResult, updatedFormatterState) = formatExprElements(GeneralTokens(List(lparen)) :: contents)(currentFormatterState)
formatResult ++= contentsFormatResult
currentFormatterState = updatedFormatterState
- if (formattingPreferences(PreserveDanglingCloseParenthesis) && hiddenPredecessors(rparen).containsNewline && contents.nonEmpty)
+
+ val alignedFormatResult = alignArguments(args)
+
+ formatResult ++= alignedFormatResult
+ val firstTokenIsOnNewline = contents.headOption.exists { x ⇒
+ val firstToken = x.firstToken
+ hiddenPredecessors(firstToken).containsNewline || formatResult.tokenWillHaveNewline(firstToken)
+ }
+ if (firstTokenIsOnNewline)
formatResult = formatResult.before(rparen, formatterState.currentIndentLevelInstruction)
+
(formatResult, currentFormatterState)
}
+ def calculateEqualsExprIdLength(equalsExpr: EqualsExpr): Int = {
+ val maybeLength = condOpt(equalsExpr.lhs) {
+ case List(callExpr: CallExpr) ⇒ callExpr.id.length
+ }
+ maybeLength.getOrElse(0)
+ }
+
+ protected def alignArguments(parenArguments: ParenArgumentExprs)(implicit formatterState: FormatterState): FormatResult = {
+ val alignArgsEnabled = formattingPreferences(AlignArguments) && !formattingPreferences(IndentWithTabs)
+ var formatResult: FormatResult = NoFormatResult
+
+ var argumentFormatterState = formatterState
+ val ParenArgumentExprs(lparen, contents, rparen) = parenArguments
+
+ /* Force a newline for the first argument if this is a set of
+ * multi line arguments:
+ * Call(aa,
+ * bb,
+ * cc) ==>
+ * Call(
+ * aa,
+ * bb,
+ * cc)
+ */
+ val firstTwoArguments = contents.iterator.filter { x ⇒
+ cond(x) {
+ case Argument(_) ⇒ true
+ case callExpr: CallExpr ⇒ true
+ case equalsExpr: EqualsExpr ⇒ true
+ }
+ }.take(2).toList
+ if (firstTwoArguments.size == 2) {
+ val secondArgument = firstTwoArguments.tail.head
+ val firstArgument = firstTwoArguments.head
+ if (hiddenPredecessors(secondArgument.firstToken).containsNewline) {
+ formatResult = formatResult.before(firstArgument.firstToken, argumentFormatterState.nextIndentLevelInstruction)
+ }
+ }
+
+ var currentExprNewlineCount = 0
+
+ // TODO: refactor this as well as "def groupParams" to share logic
+ val eitherAlignableArguments = contents.foldLeft(List[EitherAlignableEqualsExpr]()) { (existingExprs, exprElement) ⇒
+ if (!alignArgsEnabled) {
+ val nextArg = condOpt(exprElement) {
+ case Argument(Expr(List(callExpr: CallExpr))) ⇒
+ Right(callExpr) :: existingExprs
+ case Argument(Expr(List(equalsExpr: EqualsExpr))) ⇒
+ Left(ConsecutiveSingleLineEqualsExprs(List(equalsExpr), calculateEqualsExprIdLength(equalsExpr))) :: existingExprs
+ }
+ nextArg.getOrElse(existingExprs)
+ } else {
+ exprElement match {
+ case Argument(Expr(List(equalsExpr: EqualsExpr))) ⇒
+ currentExprNewlineCount = hiddenPredecessors(exprElement.firstToken).text.count(_ == '\n')
+ existingExprs match {
+ case Left(exprs @ ConsecutiveSingleLineEqualsExprs(_, length)) :: tail ⇒
+ if (currentExprNewlineCount >= 2)
+ Left(ConsecutiveSingleLineEqualsExprs(List(equalsExpr), calculateEqualsExprIdLength(equalsExpr))) :: existingExprs
+ else
+ Left(exprs.prepend(equalsExpr, calculateEqualsExprIdLength(equalsExpr))) :: tail
+ case Right(y) :: tail ⇒
+ Left(ConsecutiveSingleLineEqualsExprs(List(equalsExpr), calculateEqualsExprIdLength(equalsExpr))) :: existingExprs
+ case Nil ⇒
+ Left(ConsecutiveSingleLineEqualsExprs(List(equalsExpr), calculateEqualsExprIdLength(equalsExpr))) :: existingExprs
+ }
+ case Argument(Expr(List(callExpr: CallExpr))) ⇒
+ currentExprNewlineCount = hiddenPredecessors(exprElement.firstToken).text.count(_ == '\n')
+ Right(callExpr) :: existingExprs
+ case _ ⇒ existingExprs
+ }
+ }
+ }
+
+ eitherAlignableArguments foreach {
+ case Left(ConsecutiveSingleLineEqualsExprs(exprs, maxIdLength)) ⇒
+ exprs foreach { expr ⇒
+ val firstToken = expr.firstToken
+
+ // If there's a newline before this argument, OR there will be a newline after formatting
+ if (hiddenPredecessors(firstToken).containsNewline || formatResult.tokenWillHaveNewline(firstToken)) {
+ formatResult = formatResult.before(firstToken, argumentFormatterState.nextIndentLevelInstruction)
+ formatResult = formatResult.before(
+ expr.equals,
+ PlaceAtColumn(
+ 0,
+ maxIdLength + 1,
+ Some(firstToken)))
+ }
+ }
+ case Right(callExpr) ⇒
+ val firstToken = callExpr.firstToken
+ if (hiddenPredecessors(firstToken).containsNewline) {
+ formatResult = formatResult.before(firstToken, argumentFormatterState.nextIndentLevelInstruction)
+ }
+ }
+
+ formatResult
+ }
+
private def format(parenExpr: ParenExpr)(implicit formatterState: FormatterState): (FormatResult, FormatterState) = {
val ParenExpr(lparen, contents, rparen) = parenExpr
format(ParenArgumentExprs(lparen, contents, rparen))
@@ -849,10 +971,159 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
}.foldLeft(formatResult._1 ++ result) { _ ++ _ }
val currentLeftFormat = Some(EnsureNewlineAndIndent(0, paramClause.firstTokenOption))
formattingPreferences.indentStyle
- (resultWithNewLines, formatResult._2, currentLeftFormat)
+ (resultWithNewLines, formatterState, currentLeftFormat)
}._1
}
+ // TODO: Parts of this function might be useful in implementing other alignment features
+ protected def calculateParamSectionLengths(param: Param, first: Boolean)(implicit formatterState: FormatterState): Option[ParamSectionLengths] = {
+ val Param(annotations, modifiers, valOrVarOpt, id, paramTypeOpt, defaultValueOpt) = param
+
+ val formattedParam = formattedAstNode(param) {
+ format(param)(formatterState)
+ }
+
+ def calculateLengths: ParamSectionLengths = {
+ def calculatePrefixLength: Int = {
+ // Calculate longest "prefix" length. Annotations, modifiers, and val/var contribute
+ // to this number.
+ val allPrefixTokens =
+ annotations.flatMap(_.tokens) ++
+ modifiers.flatMap(_.tokens) ++
+ valOrVarOpt
+ var prefixLength = 0
+ allPrefixTokens.filter(!_.isNewline).foreach {
+ prefixLength += _.length
+ }
+
+ // Account for whitespace between prefix token types. This assumes everything
+ // will be placed on a single line with no newlines between prefixes.
+ val numberOfPrefixTypes = Seq(
+ !annotations.isEmpty,
+ valOrVarOpt.isDefined).count(_ == true) + modifiers.length
+ if (numberOfPrefixTypes > 0)
+ prefixLength += numberOfPrefixTypes - 1
+
+ prefixLength
+ }
+
+ // Account for the colon (and possible space) after the parameter's name
+ def calculateIdLength: Int = {
+ if (formattingPreferences(SpaceBeforeColon))
+ id.length + 2
+ else
+ id.length + 1
+ }
+
+ def calculateTypeLength: Int = {
+ // Calculate longest "type" length.
+ val typeLengthOpt = paramTypeOpt map {
+ case (_, typeAst) ⇒
+ val formattedType = formattedAstNode(typeAst) {
+ format(typeAst)(formatterState)
+ }
+ formattedType.length
+ }
+ typeLengthOpt.getOrElse(0)
+ }
+
+ val prefixLength = calculatePrefixLength
+ val idLength = calculateIdLength
+ val prefixAndIdLength = {
+ if (prefixLength > 0)
+ prefixLength + idLength + 1 // the + 1 is to account for whitespace
+ else
+ idLength
+ }
+
+ ParamSectionLengths(prefixLength, idLength, prefixAndIdLength, calculateTypeLength)
+ }
+
+ val newlineBeforeParam = hiddenPredecessors(param.firstToken).containsNewline
+
+ if (formattedParam.contains('\n') || (!first && !newlineBeforeParam))
+ None
+ else
+ Some(calculateLengths)
+ }
+
+ /**
+ * Groups consecutive single line params in a [[scalariform.parser.ParamClause]] for alignment.
+ * The head of the return value (and head of the params list in the returned ConsecutiveSingleLineParams is guaranteed
+ * to be the very first parameter in the paramClause. The other parameters are not necessarily in the order they appear.
+ * @param paramClause
+ * @param formatterState
+ *
+ * @return List of grouped params. Left stores a group of parameters that can be aligned together,
+ * Right stores an unalignable param.
+ */
+ private def groupParams(paramClause: ParamClause, alignParameters: Boolean)(implicit formatterState: FormatterState): List[EitherAlignableParam] = {
+ val ParamClause(_, implicitOption, firstParamOption, otherParamsWithComma, _) = paramClause
+
+ val otherParams = otherParamsWithComma.map { case (comma, param) ⇒ param }
+
+ // This is reversed because "appendParamToGroup" works on lists, and will
+ // create the list in the reverse order of the list it is given.
+ val allParams = (firstParamOption.toList ++ otherParams).reverse
+
+ def appendParamToGroup(previousParam: Option[Param],
+ paramToAppend: Param,
+ nextParam: Option[Param],
+ groupedParams: List[EitherAlignableParam]): List[EitherAlignableParam] = {
+
+ // This unintuitive line is dependent on the ordering of groupedParams being passed
+ // in. It's in reverse.
+ val isFirstParam = !nextParam.isDefined
+
+ val firstParamAlignable = !implicitOption.isDefined ||
+ (newlineBefore(implicitOption.get) && otherParams != Nil && newlineBefore(otherParams.head))
+
+ val paramIsAlignable = alignParameters && (!isFirstParam || firstParamAlignable)
+
+ if (alignParameters && paramIsAlignable) {
+ calculateParamSectionLengths(paramToAppend, isFirstParam) match {
+ case Some(sectionLengths) ⇒
+ groupedParams match {
+ case Right(param) :: tail ⇒
+ Left(ConsecutiveSingleLineParams(List(paramToAppend), sectionLengths, sectionLengths)) :: groupedParams
+ case Left(existingParams) :: tail ⇒
+ if (previousParam.isDefined) {
+ /* Group params separately if a blank line between two params:
+ * case class Spacing(a: Int = 1,
+ * bee: Int = 2,
+ *
+ * ceee: String = "",
+ * deeee: Any = Nothing)
+ */
+ val numNewlinesBeforeParam = hiddenPredecessors(previousParam.get.firstToken).text.count(_ == '\n')
+ if (numNewlinesBeforeParam >= 2)
+ Left(ConsecutiveSingleLineParams(List(paramToAppend), sectionLengths, sectionLengths)) :: groupedParams
+ else
+ Left(existingParams.prepend(paramToAppend, sectionLengths)) :: tail
+ } else {
+ Left(existingParams.prepend(paramToAppend, sectionLengths)) :: tail
+ }
+ case Nil ⇒
+ Left(ConsecutiveSingleLineParams(List(paramToAppend), sectionLengths, sectionLengths)) :: Nil
+ }
+ case None ⇒
+ Right(paramToAppend) :: groupedParams
+ }
+ } else {
+ Right(paramToAppend) :: groupedParams
+ }
+ }
+
+ val staggeredParams = Utils.withPreviousAndNext(allParams)
+
+ val paramsGroup = staggeredParams.foldLeft(List[EitherAlignableParam]()) { (groupedParams, prevAndNext) ⇒
+ val (prevParam, param, nextParam) = prevAndNext
+ appendParamToGroup(prevParam, param, nextParam, groupedParams)
+ }
+
+ paramsGroup
+ }
+
private def formatParamClause(paramClause: ParamClause, doubleIndentParams: Boolean = false)(implicit formatterState: FormatterState): (FormatResult, FormatterState) = {
val ParamClause(lparen, implicitOption, firstParamOption, otherParams, rparen) = paramClause
val paramIndent = if (doubleIndentParams) 2 else 1
@@ -860,36 +1131,159 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
var formatResult: FormatResult = NoFormatResult
var paramFormatterState = formatterState
val alignParameters = formattingPreferences(AlignParameters) && !formattingPreferences(IndentWithTabs)
- for (firstParam ← firstParamOption) {
- val token = implicitOption getOrElse firstParam.firstToken
- if (hiddenPredecessors(token).containsNewline) {
- formatResult = formatResult.before(token, formatterState.indent(paramIndent).currentIndentLevelInstruction)
- paramFormatterState = if (alignParameters) formatterState.alignWithToken(relativeToken) else formatterState.indent(paramIndent)
- } else if (containsNewline(firstParam) && alignParameters)
- paramFormatterState = formatterState.alignWithToken(relativeToken)
+
+ /* Force a newline for the first argument if this is a set of
+ * multi line arguments:
+ * def a(aa: Int,
+ * bb: String,
+ * cc: Boolean) ==>
+ * def a(
+ * aa: Int,
+ * bb: String,
+ * cc: Boolean)
+ */
+ val firstTwoArguments = firstParamOption ++ otherParams.headOption.map(_._2)
+ if (firstTwoArguments.size == 2) {
+ val secondArgument = firstTwoArguments.tail.head
+ val firstArgument = firstTwoArguments.head
+ if (hiddenPredecessors(secondArgument.firstToken).containsNewline) {
+ formatResult ++= formatResult.before(firstArgument.firstToken, paramFormatterState.nextIndentLevelInstruction)
+ }
+ }
+
+ val hasContent = implicitOption.isDefined || firstParamOption.isDefined || !otherParams.isEmpty
+ val firstTokenIsOnNewline = hiddenPredecessors(relativeToken).containsNewline || formatResult.tokenWillHaveNewline(relativeToken)
+
+ // Place rparen on it's own line if this is a multi-line param clause
+ if (firstTokenIsOnNewline && hasContent)
+ formatResult = formatResult.before(rparen, paramFormatterState.currentIndentLevelInstruction)
+
+ val groupedParams = groupParams(paramClause, alignParameters)
+
+ // Separate the first parameter from the groupedParams, since we have to
+ // do special formatting for the first param.
+ val ((firstGroupedParamOption, maxSectionLengthsOption), otherGroupedParams) = groupedParams.headOption match {
+ case Some(x) ⇒ x match {
+ case Left(consecutiveParams) ⇒
+ val (firstParam, remainingConsecutiveParams) = consecutiveParams.pop
+ ((firstParam, Some(remainingConsecutiveParams.maxSectionLengths)), Left(remainingConsecutiveParams) :: groupedParams.tail)
+ case p @ Right(param) ⇒
+ ((Some(param), None), groupedParams.tail)
+ }
+ case None ⇒ ((None, None), Nil)
+ }
+
+ for (firstParam ← firstGroupedParamOption) {
+ maxSectionLengthsOption match {
+ case Some(lengths) ⇒
+
+ // Indent prefixes (annotations, modifiers, and id) if alignParameters is enabled
+ alignFirstParam(firstParam)
+
+ // Indent Type
+ indentType(firstParam, lengths)
+
+ // Indent Default
+ indentDefault(firstParam, lengths)
+ case None ⇒
+ alignFirstParam(firstParam)
+ }
formatResult ++= format(firstParam)(paramFormatterState)
}
- for ((comma, param) ← otherParams) {
- val token = param.firstToken
- if (hiddenPredecessors(token).containsNewline) {
+ otherGroupedParams.foreach {
+ case Left(ConsecutiveSingleLineParams(params, maxSectionLengths, thisSectionLengths)) ⇒
+ params.foreach { param ⇒
+ val firstToken = param.firstToken
+
+ // Indent prefixes (annotations, modifiers, and id)
+ alignOtherParams(firstToken)
+
+ // Indent Type
+ indentType(param, maxSectionLengths)
+
+ // Indent Default
+ indentDefault(param, maxSectionLengths)
+
+ formatResult ++= format(param)(paramFormatterState)
+ }
+ case Right(param) ⇒
+ alignOtherParams(param.firstToken)
+ formatResult ++= format(param)(paramFormatterState)
+ }
+
+ def alignFirstParam(firstParam: Param) = {
+ // Place implicit on it's own line
+ for (implicitToken ← implicitOption) {
+ if (hiddenPredecessors(implicitToken).containsNewline || (containsNewline(firstParam) && alignParameters))
+ formatResult = formatResult.before(implicitToken, paramFormatterState.indent(paramIndent).currentIndentLevelInstruction)
+ }
+
+ val firstToken = firstParam.firstToken
+ val implicitOrFirstToken = implicitOption getOrElse firstToken
+
+ if (alignParameters)
+ paramFormatterState = formatterState.alignWithToken(relativeToken)
+
+ if (hiddenPredecessors(implicitOrFirstToken).containsNewline) {
+ formatResult = formatResult.before(firstToken, formatterState.indent(paramIndent).currentIndentLevelInstruction)
+ if (!alignParameters)
+ paramFormatterState = formatterState.indent(paramIndent)
+ } else if (containsNewline(firstParam) && alignParameters) {
+ paramFormatterState = formatterState.alignWithToken(relativeToken)
+ }
+ }
+
+ def alignOtherParams(firstToken: Token) = {
+ if (hiddenPredecessors(firstToken).containsNewline) {
paramFormatterState = if (alignParameters) formatterState.alignWithToken(relativeToken) else formatterState.indent(paramIndent)
- formatResult = formatResult.before(token, paramFormatterState.currentIndentLevelInstruction)
+ formatResult = formatResult.before(firstToken, paramFormatterState.currentIndentLevelInstruction)
+ }
+ }
+
+ def indentType(param: Param, maxSectionLengths: ParamSectionLengths) = {
+ for ((colon, typeAst) ← param.paramTypeOpt) {
+ val typeSpaces = maxSectionLengths.prefixAndIdLength + 1
+ formatResult = formatResult.before(
+ typeAst.firstToken,
+ PlaceAtColumn(
+ 0,
+ typeSpaces,
+ paramFormatterState.indentRelativeToTokenOption))
+ }
+ }
+
+ def indentDefault(param: Param, maxSectionLengths: ParamSectionLengths) = {
+ for ((equal, default) ← param.defaultValueOpt) {
+ val defaultSpaces = {
+ maxSectionLengths.prefixAndIdLength +
+ maxSectionLengths.typeLength + 2
+ }
+ formatResult = formatResult.before(
+ equal,
+ PlaceAtColumn(
+ 0,
+ defaultSpaces,
+ paramFormatterState.indentRelativeToTokenOption))
}
- formatResult ++= format(param)(paramFormatterState)
}
+
(formatResult, paramFormatterState)
}
private def format(param: Param)(implicit formatterState: FormatterState): FormatResult = {
val Param(annotations: List[Annotation], modifiers: List[Modifier], valOrVarOpt: Option[Token], id: Token, paramTypeOpt: Option[(Token, Type)], defaultValueOpt: Option[(Token, Expr)]) = param
var formatResult: FormatResult = NoFormatResult
- for (annotation ← annotations)
+
+ for (annotation ← annotations) {
formatResult ++= format(annotation)
- for ((colon, paramType) ← paramTypeOpt)
+ }
+ for ((colon, paramType) ← paramTypeOpt) {
formatResult ++= format(paramType)
- for ((equals, expr) ← defaultValueOpt)
+ }
+ for ((equals, expr) ← defaultValueOpt) {
formatResult ++= format(expr)
+ }
formatResult
}
@@ -916,9 +1310,13 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
val newFormatterState = formatterState.copy(inSingleLineBlock = singleLineBlock)
if (singleLineBlock) {
+ if (!formattingPreferences(SpacesAroundMultiImports))
+ formatResult = formatResult.before(firstImportSelector.firstToken, Compact)
formatResult ++= format(firstImportSelector)
for ((comma, otherImportSelector) ← otherImportSelectors)
formatResult ++= format(otherImportSelector)
+ if (!formattingPreferences(SpacesAroundMultiImports))
+ 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/FormatResult.scala b/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala
index 92d0cd54..406ebe64 100644
--- a/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala
@@ -6,9 +6,9 @@ import scalariform.parser._
import scalariform.utils._
object FormatResult {
-
+
val EMPTY = FormatResult(Map(), Map(), Map())
-
+
}
case class FormatResult(predecessorFormatting: Map[Token, IntertokenFormatInstruction],
@@ -34,6 +34,13 @@ case class FormatResult(predecessorFormatting: Map[Token, IntertokenFormatInstru
if (token.isNewline) formatNewline(token, formatInstruction)
else before(token, formatInstruction)
+ def tokenWillHaveNewline(token: Token): Boolean = {
+ val hasNewlineInstruction = predecessorFormatting.get(token) map {
+ PartialFunction.cond(_) { case newlineInstruction: EnsureNewlineAndIndent ⇒ true }
+ }
+ hasNewlineInstruction.getOrElse(false)
+ }
+
def mergeWith(other: FormatResult): FormatResult =
FormatResult(this.predecessorFormatting ++ other.predecessorFormatting,
this.inferredNewlineFormatting ++ other.inferredNewlineFormatting,
@@ -63,4 +70,4 @@ case object CompactPreservingGap extends IntertokenFormatInstruction
case class EnsureNewlineAndIndent(indentLevel: Int, relativeTo: Option[Token] = None) extends IntertokenFormatInstruction
/** Places the token at spaces number of spaces after the indent level, padding with spaces if necessary */
-case class PlaceAtColumn(indentLevel: Int, spaces: Int) extends IntertokenFormatInstruction
\ No newline at end of file
+case class PlaceAtColumn(indentLevel: Int, spaces: Int, relativeTo: Option[Token] = None) extends IntertokenFormatInstruction
\ No newline at end of file
diff --git a/scalariform/src/main/scala/scalariform/formatter/FormatterState.scala b/scalariform/src/main/scala/scalariform/formatter/FormatterState.scala
index 63ae0e53..3f43c6e2 100644
--- a/scalariform/src/main/scala/scalariform/formatter/FormatterState.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/FormatterState.scala
@@ -26,4 +26,4 @@ case class FormatterState(
def clearExpressionBreakHappened = copy(expressionBreakHappened = false)
-}
+}
\ No newline at end of file
diff --git a/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
index 29cb2e0b..8337842d 100644
--- a/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
@@ -45,6 +45,23 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
result
}
+ /**
+ * Converts an AstNode into what it should look like in text after Scalariform has run.
+ * Useful for calculating the actual length of an [[scalariform.parser.AstNode]] after formatting.
+ *
+ * @param ast The AST to format and render as a string
+ * @param astFormatResult Should run formatting actions for 'ast'
+ * @return Formatted string representation of what the AstNode should look like after Scalariform
+ * has run
+ */
+ protected def formattedAstNode(ast: AstNode)(astFormatResult: ⇒ FormatResult): String = {
+ val source = getSource(ast)
+ val formatResult = astFormatResult
+ val offset = ast.firstToken.offset
+ val edits = writeTokens(source, ast.tokens, formatResult, offset)
+ TextEditProcessor.runEdits(source, edits)
+ }
+
private def alterSuspendFormatting(text: String): Option[Boolean] =
if (text contains "format: OFF")
Some(true)
@@ -162,11 +179,12 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
builder.append(" ")
else
writeIntertokenCompact()
- case PlaceAtColumn(indentLevel, spaces) ⇒
+ case PlaceAtColumn(indentLevel, spaces, relativeTo) ⇒
require(!formattingPreferences(IndentWithTabs))
writeIntertokenCompact()
+ val relativeIndent = relativeTo flatMap tokenIndentMap.get getOrElse 0
val indentLength = Spaces(formattingPreferences(IndentSpaces)).length(indentLevel)
- builder.append(" " * (indentLength + spaces - builder.currentColumn))
+ builder.append(" " * (indentLength + relativeIndent + spaces - builder.currentColumn))
case EnsureNewlineAndIndent(indentLevel, relativeTo) ⇒
require(!(formattingPreferences(IndentWithTabs) && relativeTo.isDefined))
val baseIndentOption = relativeTo flatMap tokenIndentMap.get
diff --git a/scalariform/src/main/scala/scalariform/formatter/preferences/IFormattingPreferences.scala b/scalariform/src/main/scala/scalariform/formatter/preferences/IFormattingPreferences.scala
index 18ab2c9f..6fa5a043 100644
--- a/scalariform/src/main/scala/scalariform/formatter/preferences/IFormattingPreferences.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/preferences/IFormattingPreferences.scala
@@ -50,4 +50,4 @@ trait HasFormattingPreferences {
val formattingPreferences: IFormattingPreferences
-}
+}
\ No newline at end of file
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 5ef1a32a..f693e55d
--- a/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala
@@ -60,11 +60,12 @@ trait IntegerPreferenceDescriptor extends PreferenceDescriptor[Int] {
}
object AllPreferences {
- val preferences: List[PreferenceDescriptor[_]] = List(RewriteArrowSymbols, IndentSpaces, SpaceBeforeColon, CompactStringConcatenation,
- PreserveSpaceBeforeArguments, AlignParameters, DoubleIndentClassDeclaration, FormatXml, IndentPackageBlocks,
+ val preferences: List[PreferenceDescriptor[_]] = List(
+ RewriteArrowSymbols, IndentSpaces, SpaceBeforeColon, CompactStringConcatenation,
+ PreserveSpaceBeforeArguments, AlignParameters, AlignArguments, DoubleIndentClassDeclaration, FormatXml, IndentPackageBlocks,
AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, IndentLocalDefs, PreserveDanglingCloseParenthesis,
SpaceInsideParentheses, SpaceInsideBrackets, SpacesWithinPatternBinders, MultilineScaladocCommentsStartOnFirstLine, IndentWithTabs,
- CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk, BreakMultipleParameterGroups,
+ CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk, SpacesAroundMultiImports, BreakMultipleParameterGroups,
BreakMultipleParameterGroups.BreakingThreshold)
val preferencesByKey: Map[String, PreferenceDescriptor[_]] = {
@@ -113,6 +114,12 @@ case object AlignParameters extends BooleanPreferenceDescriptor {
val defaultValue = false
}
+case object AlignArguments extends BooleanPreferenceDescriptor {
+ val key = "alignArguments"
+ val description = "Align method arguments on different lines in the same column"
+ val defaultValue = false
+}
+
case object DoubleIndentClassDeclaration extends BooleanPreferenceDescriptor {
val key = "doubleIndentClassDeclaration"
val description = "Double indent either a class's parameters or its inheritance list"
@@ -151,6 +158,7 @@ case object IndentLocalDefs extends BooleanPreferenceDescriptor {
val defaultValue = false
}
+@deprecated("This has been dropped in favor of always placing ')' on a newline if the clause is multi-line.", since = "0.1.5")
case object PreserveDanglingCloseParenthesis extends BooleanPreferenceDescriptor {
val key = "preserveDanglingCloseParenthesis"
val description = "Allow a newline before a ')' in an argument expression"
@@ -199,6 +207,12 @@ case object PlaceScaladocAsterisksBeneathSecondAsterisk extends BooleanPreferenc
val defaultValue = false
}
+case object SpacesAroundMultiImports extends BooleanPreferenceDescriptor {
+ val key = "spacesAroundMultiImports"
+ 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"
diff --git a/scalariform/src/main/scala/scalariform/lexer/Tokens.scala b/scalariform/src/main/scala/scalariform/lexer/Tokens.scala
index 4e7b305a..b52fb7c8 100644
--- a/scalariform/src/main/scala/scalariform/lexer/Tokens.scala
+++ b/scalariform/src/main/scala/scalariform/lexer/Tokens.scala
@@ -114,5 +114,4 @@ object Tokens {
val LITERALS = Set(CHARACTER_LITERAL, INTEGER_LITERAL, FLOATING_POINT_LITERAL, STRING_LITERAL, STRING_PART, SYMBOL_LITERAL, TRUE, FALSE, NULL)
-}
-
+}
\ No newline at end of file
diff --git a/scalariform/src/main/scala/scalariform/parser/AstNodes.scala b/scalariform/src/main/scala/scalariform/parser/AstNodes.scala
index 23988e7f..c62a8c0b 100644
--- a/scalariform/src/main/scala/scalariform/parser/AstNodes.scala
+++ b/scalariform/src/main/scala/scalariform/parser/AstNodes.scala
@@ -445,5 +445,4 @@ case class XmlProcessingInstruction(token: Token) extends XmlContents { lazy val
case class XmlExpr(first: XmlContents, otherElements: List[XmlContents]) extends ExprElement {
lazy val tokens = flatten(first, otherElements)
-}
-
+}
\ No newline at end of file
diff --git a/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala
index a2e106a6..efa45510 100644
--- a/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala
@@ -28,8 +28,8 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
|}"""
"""{
- |case x =>
- |while (true) {
+ |case x =>
+ |while (true) {
|1
|}
|}""" ==>
@@ -89,8 +89,8 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
"a match { case b => ; c }" ==> "a match { case b => ; c }"
// See issue #60
- """a match {
- |case b =>
+ """a match {
+ |case b =>
|val c = d
|case e =>
|}""" ==>
@@ -99,7 +99,7 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
| val c = d
| case e =>
|}"""
-
+
"""a match {
|/* foo*/
|case x if z=> 1
@@ -186,7 +186,7 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
|}"""
"""a match {
- | case b
+ | case b
|=> 1
| case ccc => 2
|}""" ==>
@@ -217,7 +217,7 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
{
- implicit val formattingPreferences =
+ implicit val formattingPreferences =
FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true).setPreference(RewriteArrowSymbols, true)
"""a match {
@@ -228,12 +228,11 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
| case b ⇒ 42
| case ccc ⇒ 24
|}"""
-
}
{
- implicit val formattingPreferences =
+ implicit val formattingPreferences =
FormattingPreferences
.setPreference(AlignSingleLineCaseStatements, true)
.setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 5)
@@ -306,4 +305,4 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
| case elem @ Multi(values @ _*) =>
|}"""
-}
+}
\ No newline at end of file
diff --git a/scalariform/src/test/scala/scalariform/formatter/CommentFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/CommentFormatterTest.scala
index 073096f2..a0838b02 100644
--- a/scalariform/src/test/scala/scalariform/formatter/CommentFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/CommentFormatterTest.scala
@@ -201,6 +201,13 @@ class CommentFormatterTest extends AbstractFormatterTest {
"""/**
| */
|"""
- }
+ """/** This method applies f to each
+ | * element of the given list.
+ | */""" ==>
+ """/** This method applies f to each
+ | * element of the given list.
+ | */
+ |"""
+ }
}
diff --git a/scalariform/src/test/scala/scalariform/formatter/ForExprFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/ForExprFormatterTest.scala
index 39c5084c..44092fdd 100644
--- a/scalariform/src/test/scala/scalariform/formatter/ForExprFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/ForExprFormatterTest.scala
@@ -140,14 +140,16 @@ class ForExprFormatterTest extends AbstractExpressionFormatterTest {
|yield n)""" ==>
"""Some(
| for (n <- 1 to 10)
- | yield n)"""
+ | yield n
+ |)"""
"""Some(
|for (n <- 1 to 10)
|proc())""" ==>
"""Some(
| for (n <- 1 to 10)
- | proc())"""
+ | proc()
+ |)"""
}
diff --git a/scalariform/src/test/scala/scalariform/formatter/ImportFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/ImportFormatterTest.scala
index cc824044..cc376716 100644
--- a/scalariform/src/test/scala/scalariform/formatter/ImportFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/ImportFormatterTest.scala
@@ -2,6 +2,7 @@ package scalariform.formatter
import scalariform.parser._
import scalariform.formatter._
+import scalariform.formatter.preferences.{SpacesAroundMultiImports, FormattingPreferences}
// format: OFF
class ImportFormatterTest extends AbstractFormatterTest {
@@ -18,6 +19,14 @@ class ImportFormatterTest extends AbstractFormatterTest {
| wibble => wobble
|}"""
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesAroundMultiImports, false)
+
+ "import foo.{bar=>baz}" ==> "import foo.{bar => baz}"
+ "import foo.{bar=>baz},baz.biz" ==> "import foo.{bar => baz}, baz.biz"
+ }
+
override val debug = false
type Result = CompilationUnit
diff --git a/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala
index bb85f5a3..885b5eaa 100644
--- a/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala
@@ -7,429 +7,450 @@ import scalariform.formatter.preferences._
// format: OFF
class MiscExpressionFormatterTest extends AbstractExpressionFormatterTest {
- "→" ==> "→"
- "this" ==> "this"
- "super [ B ] . t" ==> "super[B].t"
- "E2 . super [ B ] . t" ==> "E2.super[B].t"
- "1" ==> "1"
- "true" ==> "true"
- "2.345" ==> "2.345"
- "2 + 2" ==> "2 + 2"
-
- "a max(b)" ==> "a max (b)"
- "-5f max(2)" ==> "-5f max (2)"
- "-5 max(2)" ==> "-5 max (2)"
- "-5f.max(2)" ==> "-5f.max(2)"
- "-5.max(2)" ==> "-5.max(2)"
-
- "42" ==> "42"
- "-42" ==> "-42"
-
- "- ~" ==> "- ~"
-
- """println("hello")""" ==> """println("hello")"""
- "1 * (2 + 3) * 4" ==> "1 * (2 + 3) * 4"
-
- """println(getClass().getSimpleName() + " passed.")""" ==>
- """println(getClass().getSimpleName() + " passed.")"""
-
- "a(b).c" ==> "a(b).c"
-
- "b = 2" ==> "b = 2"
- "b_+= = 2" ==> "b_+= = 2"
- "2: Int" ==> "2: Int"
- "x: _*" ==> "x: _*"
- "x: _ *" ==> "x: _*"
- "x_ : Int" ==> "x_ : Int"
- "|v| : Int" ==> "|v| : Int"
- "×× : (A, A)" ==> "×× : (A, A)"
-
- "{ case (_~_) => }" ==> "{ case (_ ~ _) => }"
- "{ case (a~_) => }" ==> "{ case (a ~ _) => }"
- "{ case (_~b) => }" ==> "{ case (_ ~ b) => }"
-
- "(1, 2, 3, 4)" ==> "(1, 2, 3, 4)"
- "(x: Int, y: List[String], z: Map[_ <: K, V])" ==> "(x: Int, y: List[String], z: Map[_ <: K, V])"
-
- "a(3)=5" ==> "a(3) = 5"
-
- "-3 + -2" ==> "-3 + -2"
- "-3+(-2)" ==> "-3 + (-2)"
- "-a * +b * ~c * !d" ==> "-a * +b * ~c * !d"
- "FOO?" ==> "FOO?"
- "x_ ?" ==> "x_ ?"
- "palindrome reverse" ==> "palindrome reverse"
-
- "_" ==> "_"
- "println _" ==> "println _"
- "s.isInstanceOf[String]" ==> "s.isInstanceOf[String]"
-
- "placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest" ==>
- "placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest"
-
- "in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)" ==>
- "in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)"
-
- "stripParens(reduceStack(true, base, topinfo.operand, 0, true))" ==>
- "stripParens(reduceStack(true, base, topinfo.operand, 0, true))"
-
- "surround(open, close)(enumerators(), Nil)" ==> "surround(open, close)(enumerators(), Nil)"
-
- "makeColour(red = 253, green = 712, blue = 120)" ==> "makeColour(red = 253, green = 712, blue = 120)"
-
- "_ => 3" ==> "_ => 3"
- "(_: Int) => 3" ==> "(_: Int) => 3"
- "(x: String, y: Map[String, String]) => y(x)" ==> "(x: String, y: Map[String, String]) => y(x)"
-
- """2: @Foo({println("bar")
- |3})""" ==>
- """2: @Foo({
- | println("bar")
- | 3
- |})"""
-
- """f: { def n: Int
- |def m: Int}""" ==>
- """f: {
- | def n: Int
- | def m: Int
- |}"""
-
-
- """List[Int { val n: Int
- |val m: Int }]()""" ==>
- """List[Int {
- | val n: Int
- | val m: Int
- |}]()"""
-
-
- """42 match {
- |case x: Int { val n: Int
- |val m: Int } => 42
- |}""" ==>
- """42 match {
- | case x: Int {
- | val n: Int
- | val m: Int
- | } => 42
- |}"""
-
- {
- implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, false)
+ "→" ==> "→"
+ "this" ==> "this"
+ "super [ B ] . t" ==> "super[B].t"
+ "E2 . super [ B ] . t" ==> "E2.super[B].t"
+ "1" ==> "1"
+ "true" ==> "true"
+ "2.345" ==> "2.345"
+ "2 + 2" ==> "2 + 2"
- """42 match {
- | case foo_ @Bar =>
- |}""" ==>
- """42 match {
- | case foo_ @Bar =>
- |}"""
+ "a max(b)" ==> "a max (b)"
+ "-5f max(2)" ==> "-5f max (2)"
+ "-5 max(2)" ==> "-5 max (2)"
+ "-5f.max(2)" ==> "-5f.max(2)"
+ "-5.max(2)" ==> "-5.max(2)"
- }
+ "42" ==> "42"
+ "-42" ==> "-42"
- "NEWLINE" ==> "NEWLINE"
- "NEWLINES" ==> "NEWLINES"
+ "- ~" ==> "- ~"
- "\"\"\"triplequoted\"\"\"" ==> "\"\"\"triplequoted\"\"\""
+ """println("hello")""" ==> """println("hello")"""
+ "1 * (2 + 3) * 4" ==> "1 * (2 + 3) * 4"
- "{ type x = Equal[App[Lam[X], X]#Eval, X] }" ==> "{ type x = Equal[App[Lam[X], X]#Eval, X] }"
+ """println(getClass().getSimpleName() + " passed.")""" ==>
+ """println(getClass().getSimpleName() + " passed.")"""
- """{
- | type U = Int
- | type T <: Seq[U]
- |}""" ==>
- """{
- | type U = Int
- | type T <: Seq[U]
- |}"""
+ "a(b).c" ==> "a(b).c"
- "{ type X[+T]=List[T]}" ==> "{ type X[+T] = List[T] }"
+ "b = 2" ==> "b = 2"
+ "b_+= = 2" ==> "b_+= = 2"
+ "2: Int" ==> "2: Int"
+ "x: _*" ==> "x: _*"
+ "x: _ *" ==> "x: _*"
+ "x_ : Int" ==> "x_ : Int"
+ "|v| : Int" ==> "|v| : Int"
+ "×× : (A, A)" ==> "×× : (A, A)"
- "new A(b, c)" ==> "new A(b, c)"
+ "{ case (_~_) => }" ==> "{ case (_ ~ _) => }"
+ "{ case (a~_) => }" ==> "{ case (a ~ _) => }"
+ "{ case (_~b) => }" ==> "{ case (_ ~ b) => }"
- "1/2" ==> "1 / 2"
- "1+/2" ==> "1 +/ 2"
- "1+/+2" ==> "1 +/+ 2"
- "1*/2" ==> "1 */ 2"
+ "(1, 2, 3, 4)" ==> "(1, 2, 3, 4)"
+ "(x: Int, y: List[String], z: Map[_ <: K, V])" ==> "(x: Int, y: List[String], z: Map[_ <: K, V])"
- "1*/*a*/2" ==> "1 * /*a*/ 2"
- "1 +/* /* var */ var */2" ==> "1 + /* /* var */ var */ 2"
- "1 + /* /* var */ var */2" ==> "1 + /* /* var */ var */ 2"
+ "a(3)=5" ==> "a(3) = 5"
- """(1//2
- |+2)""" ==>
- """(1 //2
- | + 2)""" // TODO: Review
-
- "1.to(13)" ==> "1.to(13)"
- "0.asInstanceOf[Character]" ==> "0.asInstanceOf[Character]"
+ "-3 + -2" ==> "-3 + -2"
+ "-3+(-2)" ==> "-3 + (-2)"
+ "-a * +b * ~c * !d" ==> "-a * +b * ~c * !d"
+ "FOO?" ==> "FOO?"
+ "x_ ?" ==> "x_ ?"
+ "palindrome reverse" ==> "palindrome reverse"
- "b match { case _: List[List[C]] => d }" ==> "b match { case _: List[List[C]] => d }"
+ "_" ==> "_"
+ "println _" ==> "println _"
+ "s.isInstanceOf[String]" ==> "s.isInstanceOf[String]"
- """for {
- | n <- Some(42)
- | _ <- Some(42)
- |} yield n""" ==>
- """for {
- | n <- Some(42)
- | _ <- Some(42)
- |} yield n"""
+ "placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest" ==>
+ "placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest"
- "foo(implicit x => implicitly[X])" ==> "foo(implicit x => implicitly[X])"
+ "in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)" ==>
+ "in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)"
- "(x: Int) => 42" ==> "(x: Int) => 42"
+ "stripParens(reduceStack(true, base, topinfo.operand, 0, true))" ==>
+ "stripParens(reduceStack(true, base, topinfo.operand, 0, true))"
- "tail.partition(_ "tail.partition(_ < pivot)"
+ "surround(open, close)(enumerators(), Nil)" ==> "surround(open, close)(enumerators(), Nil)"
- "postWorkItem { () => }" ==> "postWorkItem { () => }"
+ "makeColour(red = 253, green = 712, blue = 120)" ==> "makeColour(red = 253, green = 712, blue = 120)"
- """new C(new D {
- |println("foo")
- |println("bar")
- |})""" ==>
- """new C(new D {
- | println("foo")
- | println("bar")
- |})"""
-
- {
- implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, false)
-
- """b match {
- |case y@ =>
- |}""" ==>
- """b match {
- | case y@ =>
- |}""" // TODO: Whitespace around @ in this case?
- }
-
- """1 / // foo
- |2""" ==>
- """1 / // foo
- | 2"""
-
- "(USCORE ~ opt(wildcardType) |/ /* id |/ */typ_)" ==> "(USCORE ~ opt(wildcardType) |/ /* id |/ */ typ_)"
-
- "a match {case b => c; case d => e}" ==> "a match { case b => c; case d => e }"
-
- "Option(foo) match { case Some(x)=> 42 case None => 12}" ==>
- "Option(foo) match { case Some(x) => 42 case None => 12 }"
-
- """a match {
- |case b|(c) =>
- |}""" ==>
- """a match {
- | case b | (c) =>
- |}"""
+ """a(
+ |)""" ==> """a()"""
- """new B
- |{
- |println("foo")
- |}""" ==>
- """new B {
- | println("foo")
- |}"""
-
- """println
- |{foo
- |}""" ==>
- """println {
- | foo
- |}"""
-
- """println
- |{
- | foo}""" ==>
- """println {
- | foo
- |}"""
-
- """println
- |{foo}""" ==>
- """println { foo }"""
-
-
- """doBlock(xs) {(x:Int) => println(x)
- |println("bobble")
- |}""" ==>
- """doBlock(xs) { (x: Int) =>
- | println(x)
- | println("bobble")
- |}"""
-
- """doBlock(xs) {x => println(x)
- |println("bobble")
- |}""" ==>
- """doBlock(xs) { x =>
- | println(x)
- | println("bobble")
- |}"""
-
- """doBlock(xs) {(x:Int) => println(x)}""" ==> """doBlock(xs) { (x: Int) => println(x) }"""
-
- """foo
- |{ bar }
- |{ baz }""" ==>
- """foo { bar } { baz }"""
-
- """foo { bar } { baz }""" ==> """foo { bar } { baz }"""
-
- """foo { () =>
- |}""" ==>
- """foo { () =>
- |}"""
-
- """3 +// foo
- |4""" ==>
- """3 + // foo
- | 4"""
-
- """3 +
- |{ 4 * 12
- |}""" ==>
- """3 +
- | {
- | 4 * 12
- | }"""
-
- """1 +
- |2 +
- |3""" ==>
- """1 +
- | 2 +
- | 3"""
+ "_ => 3" ==> "_ => 3"
+ "(_: Int) => 3" ==> "(_: Int) => 3"
+ "(x: String, y: Map[String, String]) => y(x)" ==> "(x: String, y: Map[String, String]) => y(x)"
+
+ """2: @Foo({println("bar")
+ |3})""" ==>
+ """2: @Foo({
+ | println("bar")
+ | 3
+ |})"""
+
+ """f: { def n: Int
+ |def m: Int}""" ==>
+ """f: {
+ | def n: Int
+ | def m: Int
+ |}"""
+
+
+ """List[Int { val n: Int
+ |val m: Int }]()""" ==>
+ """List[Int {
+ | val n: Int
+ | val m: Int
+ |}]()"""
+
+
+ """42 match {
+ |case x: Int { val n: Int
+ |val m: Int } => 42
+ |}""" ==>
+ """42 match {
+ | case x: Int {
+ | val n: Int
+ | val m: Int
+ | } => 42
+ |}"""
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, false)
+
+ """42 match {
+ | case foo_ @Bar =>
+ |}""" ==>
+ """42 match {
+ | case foo_ @Bar =>
+ |}"""
+
+ }
+
+ "NEWLINE" ==> "NEWLINE"
+ "NEWLINES" ==> "NEWLINES"
+
+ "\"\"\"triplequoted\"\"\"" ==> "\"\"\"triplequoted\"\"\""
+
+ "{ type x = Equal[App[Lam[X], X]#Eval, X] }" ==> "{ type x = Equal[App[Lam[X], X]#Eval, X] }"
+
+ """{
+ | type U = Int
+ | type T <: Seq[U]
+ |}""" ==>
+ """{
+ | type U = Int
+ | type T <: Seq[U]
+ |}"""
+
+ "{ type X[+T]=List[T]}" ==> "{ type X[+T] = List[T] }"
+
+ "new A(b, c)" ==> "new A(b, c)"
+
+ "1/2" ==> "1 / 2"
+ "1+/2" ==> "1 +/ 2"
+ "1+/+2" ==> "1 +/+ 2"
+ "1*/2" ==> "1 */ 2"
+
+ "1*/*a*/2" ==> "1 * /*a*/ 2"
+ "1 +/* /* var */ var */2" ==> "1 + /* /* var */ var */ 2"
+ "1 + /* /* var */ var */2" ==> "1 + /* /* var */ var */ 2"
+
+ """(1//2
+ |+2)""" ==>
+ """(1 //2
+ | + 2)""" // TODO: Review
+
+ "1.to(13)" ==> "1.to(13)"
+ "0.asInstanceOf[Character]" ==> "0.asInstanceOf[Character]"
+
+ "b match { case _: List[List[C]] => d }" ==> "b match { case _: List[List[C]] => d }"
+
+ """for {
+ | n <- Some(42)
+ | _ <- Some(42)
+ |} yield n""" ==>
+ """for {
+ | n <- Some(42)
+ | _ <- Some(42)
+ |} yield n"""
+
+ "foo(implicit x => implicitly[X])" ==> "foo(implicit x => implicitly[X])"
+
+ "(x: Int) => 42" ==> "(x: Int) => 42"
+
+ "tail.partition(_ "tail.partition(_ < pivot)"
+
+ "postWorkItem { () => }" ==> "postWorkItem { () => }"
+
+ """new C(new D {
+ |println("foo")
+ |println("bar")
+ |})""" ==>
+ """new C(new D {
+ | println("foo")
+ | println("bar")
+ |})"""
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, false)
+
+ """b match {
+ |case y@ =>
+ |}""" ==>
+ """b match {
+ | case y@ =>
+ |}""" // TODO: Whitespace around @ in this case?
+ }
+
+ """1 / // foo
+ |2""" ==>
+ """1 / // foo
+ | 2"""
+
+ "(USCORE ~ opt(wildcardType) |/ /* id |/ */typ_)" ==> "(USCORE ~ opt(wildcardType) |/ /* id |/ */ typ_)"
+
+ "a match {case b => c; case d => e}" ==> "a match { case b => c; case d => e }"
+
+ "Option(foo) match { case Some(x)=> 42 case None => 12}" ==>
+ "Option(foo) match { case Some(x) => 42 case None => 12 }"
+
+ """a match {
+ |case b|(c) =>
+ |}""" ==>
+ """a match {
+ | case b | (c) =>
+ |}"""
+
+ """new B
+ |{
+ |println("foo")
+ |}""" ==>
+ """new B {
+ | println("foo")
+ |}"""
+
+ """println
+ |{foo
+ |}""" ==>
+ """println {
+ | foo
+ |}"""
+
+ """println
+ |{
+ | foo}""" ==>
+ """println {
+ | foo
+ |}"""
+
+ """println
+ |{foo}""" ==>
+ """println { foo }"""
+
+
+ """doBlock(xs) {(x:Int) => println(x)
+ |println("bobble")
+ |}""" ==>
+ """doBlock(xs) { (x: Int) =>
+ | println(x)
+ | println("bobble")
+ |}"""
+
+ """doBlock(xs) {x => println(x)
+ |println("bobble")
+ |}""" ==>
+ """doBlock(xs) { x =>
+ | println(x)
+ | println("bobble")
+ |}"""
+
+ """doBlock(xs) {(x:Int) => println(x)}""" ==> """doBlock(xs) { (x: Int) => println(x) }"""
+
+ """foo
+ |{ bar }
+ |{ baz }""" ==>
+ """foo { bar } { baz }"""
+
+ """foo { bar } { baz }""" ==> """foo { bar } { baz }"""
+
+ """foo { () =>
+ |}""" ==>
+ """foo { () =>
+ |}"""
+
+ """3 +// foo
+ |4""" ==>
+ """3 + // foo
+ | 4"""
+
+ """3 +
+ |{ 4 * 12
+ |}""" ==>
+ """3 +
+ | {
+ | 4 * 12
+ | }"""
+
+ """1 +
+ |2 +
+ |3""" ==>
+ """1 +
+ | 2 +
+ | 3"""
"""foo(1,
|2)""" ==>
- """foo(1,
- | 2)"""
+ """foo(
+ | 1,
+ | 2
+ |)"""
- """/* a */
- |b""" ==>
- """/* a */ b"""
+ """/* a */
+ |b""" ==>
+ """/* a */ b"""
"""a(
|if (b) c)""" ==>
"""a(
- | if (b) c)"""
+ | if (b) c
+ |)"""
"""a(
|if (b)
|c)""" ==>
"""a(
| if (b)
- | c)"""
+ | c
+ |)"""
- """a("A",
+ """a("A",
| b("B",
| c(1, 2),
- | c(3, 4)),
- | b("B2",
+ | c(3, 4)),
+ | b("B2",
| c(5, 6)))""" ==>
- """a("A",
- | b("B",
+ """a(
+ | "A",
+ | b(
+ | "B",
| c(1, 2),
- | c(3, 4)),
- | b("B2",
- | c(5, 6)))"""
+ | c(3, 4)
+ | ),
+ | b(
+ | "B2",
+ | c(5, 6)
+ | )
+ |)"""
"""1 + (a,
| b, c)""" ==>
- """1 + (a,
- | b, c)"""
-
- """1 + (
- | a, b, c)""" ==>
"""1 + (
- | a, b, c)"""
-
- """1 + (a
- |, b, c)""" ==>
- """1 + (a, b, c)"""
-
- "()" ==> "()"
-
- {
- implicit val formattingPreferences = FormattingPreferences.setPreference(SpaceBeforeColon, true)
- "(a: Int) => 3" ==> "(a : Int) => 3"
- }
-
- """{ // format: +spaceBeforeColon
- | val a:Int = 2
- |}""" ==>
- """{ // format: +spaceBeforeColon
- | val a : Int = 2
- |}"""
+ | a,
+ | b, c
+ |)"""
- "_.a" ==> "_.a"
-
- {
- implicit val formattingPreferences = FormattingPreferences.setPreference(CompactStringConcatenation, true)
- """"foo"+"bar"""" ==> """"foo"+"bar""""
- """"foo" + "bar"""" ==> """"foo"+"bar""""
- """foo + "bar"""" ==> """foo+"bar""""
- """"foo" + bar""" ==> """"foo"+bar"""
- """foo + bar""" ==> """foo + bar"""
- }
-
- """a { implicit b =>
- |println(b)
- |}""" ==>
- """a { implicit b =>
- | println(b)
- |}"""
-
- """a { b =>
- |println(b)
- |}""" ==>
- """a { b =>
- | println(b)
- |}"""
+ """1 + (
+ | a, b, c)""" ==>
+ """1 + (
+ | a, b, c
+ |)"""
+
+ """1 + (a
+ |, b, c)""" ==>
+ """1 + (a, b, c)"""
+
+ "()" ==> "()"
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(SpaceBeforeColon, true)
+ "(a: Int) => 3" ==> "(a : Int) => 3"
+ }
+
+ """{ // format: +spaceBeforeColon
+ | val a:Int = 2
+ |}""" ==>
+ """{ // format: +spaceBeforeColon
+ | val a : Int = 2
+ |}"""
+
+ "_.a" ==> "_.a"
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(CompactStringConcatenation, true)
+ """"foo"+"bar"""" ==> """"foo"+"bar""""
+ """"foo" + "bar"""" ==> """"foo"+"bar""""
+ """foo + "bar"""" ==> """foo+"bar""""
+ """"foo" + bar""" ==> """"foo"+bar"""
+ """foo + bar""" ==> """foo + bar"""
+ }
+
+ """a { implicit b =>
+ |println(b)
+ |}""" ==>
+ """a { implicit b =>
+ | println(b)
+ |}"""
+
+ """a { b =>
+ |println(b)
+ |}""" ==>
+ """a { b =>
+ | println(b)
+ |}"""
"""a(b,
|/* c */d)""" ==>
- """a(b,
- | /* c */ d)"""
+ """a(
+ | b,
+ | /* c */ d
+ |)"""
- """submit(
- |
- |)""" ==>
- """submit()"""
+ """submit(
+ |
+ |)""" ==>
+ """submit()"""
"""(
- |42,
+ |42,
|46
|)""" ==>
"""(
| 42,
- | 46)""" // I prefer no initial indent for tuples, although you could argue it should be consistent with ParenExprs
-
+ | 46
+ |)""" // I prefer no initial indent for tuples, although you could argue it should be consistent with ParenExprs
+
"""a(b,
|c => {
|d})""" ==>
- """a(b,
+ """a(
+ | b,
| c => {
| d
- | })"""
+ | }
+ |)"""
- """a(b,
+ """a(b,
|(c), {
|d})""" ==>
- """a(b,
+ """a(
+ | b,
| (c), {
| d
- | })"""
+ | }
+ |)"""
"""a(
- | () =>
+ | () =>
| b)""" ==>
"""a(
| () =>
- | b)"""
-
+ | b
+ |)"""
- {
- implicit val formattingPreferences = FormattingPreferences.setPreference(PreserveDanglingCloseParenthesis, true)
"""Book(
| name = "Name",
@@ -442,350 +463,540 @@ class MiscExpressionFormatterTest extends AbstractExpressionFormatterTest {
| rating = 5
|)"""
- }
-
- """Book(
- | name = "Name",
- | author = "Author",
- | rating = 5
- |)""" ==>
- """Book(
- | name = "Name",
- | author = "Author",
- | rating = 5)"""
-
-
- """foobar(
+ """foobar(
|(1,2),
- |(3, 4),
- |(5, 6),
+ |(3, 4),
+ |(5, 6),
|(7, 8))""" ==>
"""foobar(
| (1, 2),
| (3, 4),
| (5, 6),
- | (7, 8))"""
+ | (7, 8)
+ |)"""
- """(1
- |,2)""" ==>
- """(1, 2)"""
+ """(1
+ |,2)""" ==>
+ """(1, 2)"""
- """a(1
- |,2)""" ==>
- """a(1, 2)"""
+ """a(1
+ |,2)""" ==>
+ """a(1, 2)"""
"""a(
- |b,
- |c +
+ |b,
+ |c +
|d)""" ==>
"""a(
| b,
| c +
- | d)"""
-
- """(a ->
- |new B)""" ==>
- """(a ->
- | new B)"""
-
- """(1
- | + {
- |foo
- |})""" ==>
- """(1
- | + {
- | foo
- | })"""
-
- """a +
- | b + (c +
- | d)""" ==>
- """a +
- | b + (c +
- | d)"""
-
- """42
- |: Int""" ==>
- """42: Int"""
-
- "if (true) 1; else 2" ==> "if (true) 1; else 2" // Check SEMI + ELSE rule
-
- "a: ::" ==> "a: ::"
-
-
- """(a
- | + b
- |+ c)""" ==>
- """(a
- | + b
- | + c)"""
-
- """(a +
- | b +
- |c)""" ==>
- """(a +
- | b +
- | c)"""
-
- """(a +
- |( b +
- |c))""" ==>
- """(a +
- | (b +
- | c))"""
-
- """a +
- |b +
- |c""" ==>
- """a +
- | b +
- | c"""
-
- """a match {
- | case wibble(
- | wobble(
- | wubble(x))) => y
- | }""" ==>
- """a match {
- | case wibble(
- | wobble(
- | wubble(x))) => y
- |}"""
-
- """'a'
- |.b
- |.c""" ==>
- """'a'
- | .b
- | .c"""
-
- """a.
- |b().c match {
- |case d =>
- |}""" ==>
- """a.
- | b().c match {
- | case d =>
- | }"""
-
- """a()
- |.b(c(
- |d))""" ==>
- """a()
- | .b(c(
- | d))"""
-
- """a().
- |b(c => {
- |d
- |})""" ==>
- """a().
- | b(c => {
| d
- | })"""
-
- """((a).b
- |{
- | c
- |})""" ==>
- """((a).b {
- | c
- |})"""
-
- """(a).b
- |{
- | c
- |}""" ==>
- """(a).b {
- | c
- |}"""
-
- """('a'.b
- | (c))""" ==>
- """('a'.b(c))"""
-
- """a match {
- |case b if c &&
- |d => {e
- |}
- |}""" =/=>
- """a match {
- | case b if c &&
- | d => {
- | e
- | }
- |}""" because " we don't thread the expression break state through case statement"
-
- """a =
- |b""" ==>
- """a =
- | b"""
- """a =
- |b + c +
- |d""" ==>
- """a =
- | b + c +
- | d"""
-
- """a
- |.b =
- |c""" ==>
- """a
- | .b =
- | c"""
-
- """a
- |.b = {
- |c
- |}""" ==>
- """a
- | .b = {
- | c
- | }"""
-
- """(f
- | (b))""" ==>
- """(f(b))"""
-
- {
-
- implicit val formattingPreferences = FormattingPreferences.setPreference(PreserveSpaceBeforeArguments, true)
-
- "getDirectives(source) should be (expectedDirectives)" ==>
- "getDirectives(source) should be (expectedDirectives)"
-
- "getDirectives(source) should be(expectedDirectives)" ==>
- "getDirectives(source) should be(expectedDirectives)"
+ |)"""
- }
- """(if (a) b else c
- |, d)""" ==>
- """(if (a) b else c, d)"""
+ """(a ->
+ |new B)""" ==>
+ """(a ->
+ | new B)"""
+
+ """(1
+ | + {
+ |foo
+ |})""" ==>
+ """(1
+ | + {
+ | foo
+ | })"""
+
+ """a +
+ | b + (c +
+ | d)""" ==>
+ """a +
+ | b + (c +
+ | d)"""
+
+ """42
+ |: Int""" ==>
+ """42: Int"""
+
+ "if (true) 1; else 2" ==> "if (true) 1; else 2" // Check SEMI + ELSE rule
+
+ "a: ::" ==> "a: ::"
+
+
+ """(a
+ | + b
+ |+ c)""" ==>
+ """(a
+ | + b
+ | + c)"""
+
+ """(a +
+ | b +
+ |c)""" ==>
+ """(a +
+ | b +
+ | c)"""
+
+ """(a +
+ |( b +
+ |c))""" ==>
+ """(a +
+ | (b +
+ | c))"""
+
+ """a +
+ |b +
+ |c""" ==>
+ """a +
+ | b +
+ | c"""
+
+ """a match {
+ | case wibble(
+ | wobble(
+ | wubble(x))) => y
+ | }""" ==>
+ """a match {
+ | case wibble(
+ | wobble(
+ | wubble(x))) => y
+ |}"""
+
+ """'a'
+ |.b
+ |.c""" ==>
+ """'a'
+ | .b
+ | .c"""
+
+"""a.
+ |b().c match {
+ |case d =>
+ |}""" ==>
+"""a.
+ | b().c match {
+ | case d =>
+ | }"""
+
+ """a()
+ |.b(c(
+ |d))""" ==>
+ """a()
+ | .b(c(
+ | d
+ | ))"""
+
+ """a().
+ |b(c => {
+ |d
+ |})""" ==>
+ """a().
+ | b(c => {
+ | d
+ | })"""
+
+ """((a).b
+ |{
+ | c
+ |})""" ==>
+ """((a).b {
+ | c
+ |})"""
+
+ """(a).b
+ |{
+ | c
+ |}""" ==>
+ """(a).b {
+ | c
+ |}"""
+
+ """('a'.b
+ | (c))""" ==>
+ """('a'.b(c))"""
+
+ """a match {
+ |case b if c &&
+ |d => {e
+ |}
+ |}""" =/=>
+ """a match {
+ | case b if c &&
+ | d => {
+ | e
+ | }
+ |}""" because " we don't thread the expression break state through case statement"
+
+ """a =
+ |b""" ==>
+ """a =
+ | b"""
+ """a =
+ |b + c +
+ |d""" ==>
+ """a =
+ | b + c +
+ | d"""
+
+ """a
+ |.b =
+ |c""" ==>
+ """a
+ | .b =
+ | c"""
+
+ """a
+ |.b = {
+ |c
+ |}""" ==>
+ """a
+ | .b = {
+ | c
+ | }"""
+
+ """(f
+ | (b))""" ==>
+ """(f(b))"""
+
+ {
+
+ implicit val formattingPreferences = FormattingPreferences.setPreference(PreserveSpaceBeforeArguments, true)
+
+ "getDirectives(source) should be (expectedDirectives)" ==>
+ "getDirectives(source) should be (expectedDirectives)"
+
+ "getDirectives(source) should be(expectedDirectives)" ==>
+ "getDirectives(source) should be(expectedDirectives)"
+
+ }
+
+ """(if (a) b else c
+ |, d)""" ==>
+ """(if (a) b else c, d)"""
+
+ """a(b,
+ |c) + {
+ |d
+ |}""" ==>
+ """a(
+ | b,
+ | c
+ |) + {
+ | d
+ |}"""
+
+ """(b,
+ |c) + {
+ |d}""" ==>
+ """(
+ | b,
+ | c
+ |) + {
+ | d
+ | }"""
+
+ """ XScalaWT.shell("title",
+ | label("label"),
+ | popupMenu(
+ | viewer(
+ | // TODO
+ | )
+ | )
+ | )""" ==>
+ """XScalaWT.shell(
+ | "title",
+ | label("label"),
+ | popupMenu(
+ | viewer( // TODO
+ | )
+ | )
+ |)"""
+
+ """a(b)
+ |.c(d)
+ |.e(f)
+ |.g""" ==>
+ """a(b)
+ | .c(d)
+ | .e(f)
+ | .g"""
+
+ """(a,
+ |b) + (c,
+ |d) + (e,
+ | f) + g""" ==>
+ """(
+ | a,
+ | b
+ |) + (
+ | c,
+ | d
+ | ) + (
+ | e,
+ | f
+ | ) + g"""
+
+ """(a, b)""" ==> """(a, b)"""
+ """a + (b,
+ |c) +
+ |d""" ==>
+ """a + (
+ | b,
+ | c
+ |) +
+ | d"""
+
+ """a + f(b,
+ | c) +
+ |d""" ==>
+ """a + f(
+ | b,
+ | c
+ |) +
+ | d"""
+
+ """a
+ |.b(
+ |c)
+ |.d""" ==>
+ """a
+ | .b(
+ | c
+ | )
+ | .d"""
+
+
+ "Foo.this" ==> "Foo.this"
+
+ """List.range(1, r) flatMap (
+ | i => List.range(1, i) map (j => (i, j))
+ |)""" ==>
+ """List.range(1, r) flatMap (
+ | i => List.range(1, i) map (j => (i, j))
+ |)"""
+
+ """a map {
+ | b =>
+ | c
+ | d
+ |}""" ==>
+ """a map {
+ | b =>
+ | c
+ | d
+ |}"""
+
+ """Things.foreach {
+ | thing =>
+ | println("_%s".format(thing))
+ |}""" ==>
+ """Things.foreach {
+ | thing =>
+ | println("_%s".format(thing))
+ |}""" // See issue 21
+
+ """a.map {
+ | b => c
+ |}""" ==>
+ """a.map {
+ | b => c
+ |}"""
+
+ "f()[Foo]" ==> "f()[Foo]"
+ "a [ b . C ] [ d . E ] [ f . G ] " ==> "a[b.C][d.E][f.G]"
+
+ "{ val P(a, b*c) = p }" ==> "{ val P(a, b * c) = p }"
+
+
+ """new {} with A(new {
+ |val x = 42}) with B(new {
+ |val x = 42})""" ==>
+ """new {} with A(new {
+ | val x = 42
+ |}) with B(new {
+ | val x = 42
+ |})"""
- """a(b,
- |c) + {
+ """a(
+ |b,
+ |c,
|d
- |}""" ==>
- """a(b,
- | c) + {
- | d
- | }"""
-
- """(b,
- |c) + {
- |d}""" ==>
- """(b,
- | c) + {
- | d
- | }"""
-
- """ XScalaWT.shell("title",
- | label("label"),
- | popupMenu(
- | viewer(
- | // TODO
- | )
- | )
- | )""" ==>
- """XScalaWT.shell("title",
- | label("label"),
- | popupMenu(
- | viewer( // TODO
- | )))"""
-
- """a(b)
- |.c(d)
- |.e(f)
- |.g""" ==>
- """a(b)
- | .c(d)
- | .e(f)
- | .g"""
-
- """(a,
- |b) + (c,
- |d) + (e,
- | f) + g""" ==>
- """(a,
- | b) + (c,
- | d) + (e,
- | f) + g"""
-
- """a + (b,
- |c) +
- |d""" ==>
- """a + (b,
- | c) +
- | d"""
-
- """a + f(b,
- | c) +
- |d""" ==>
- """a + f(b,
- | c) +
- | d"""
-
- """a
- |.b(
- |c)
- |.d""" ==>
- """a
- | .b(
- | c)
- | .d"""
-
-
- "Foo.this" ==> "Foo.this"
-
- """List.range(1, r) flatMap (
- | i => List.range(1, i) map (j => (i, j))
+ |)(
+ | e,
+ | f,
+ | g
|)""" ==>
- """List.range(1, r) flatMap (
- | i => List.range(1, i) map (j => (i, j)))"""
+ """a(
+ | b,
+ | c,
+ | d
+ |)(
+ | e,
+ | f,
+ | g
+ |)"""
- """a map {
- | b =>
- | c
- | d
- |}""" ==>
- """a map {
- | b =>
- | c
- | d
- |}"""
-
- """Things.foreach {
- | thing =>
- | println("_%s".format(thing))
- |}""" ==>
- """Things.foreach {
- | thing =>
- | println("_%s".format(thing))
- |}""" // See issue 21
-
- """a.map {
- | b => c
- |}""" ==>
- """a.map {
- | b => c
- |}"""
-
- "f()[Foo]" ==> "f()[Foo]"
- "a [ b . C ] [ d . E ] [ f . G ] " ==> "a[b.C][d.E][f.G]"
-
- "{ val P(a, b*c) = p }" ==> "{ val P(a, b * c) = p }"
-
-
- """new {} with A(new {
- |val x = 42}) with B(new {
- |val x = 42})""" ==>
- """new {} with A(new {
- | val x = 42
- |}) with B(new {
- | val x = 42
- |})"""
-
- override val debug = false
-
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignArguments, true)
+
+ """Method(a, b, c)""" ==> """Method(a, b, c)"""
+
+ // Force a newline if arguments are multi line
+ """Method(aaa = "",
+ |bb = 1,
+ |c = null)""" ==>
+ """Method(
+ | aaa = "",
+ | bb = 1,
+ | c = null
+ |)"""
+
+ """method(multiLineArgument = {
+ | val string = "hello world"
+ | println(string)
+ |},
+ |b = 1,
+ |c = null)""" =/=>
+ """method(
+ | multiLineArgument = {
+ | val string = "hello world"
+ | println(string)
+ | },
+ | shortParam = 1,
+ | shorter = null)""" because "TODO: this didn't work before AlignArguments, but is worth fixing"
+
+ """o.p(aaaaa(x_x,z,y),
+ | b(x,
+ | yy,
+ | zzz(
+ | a,
+ | b,
+ | c
+ | )
+ | ),
+ |c(firstGroupOne(x)),
+ | d,
+ | e,
+ | f
+ |)""" ==>
+ """o.p(
+ | aaaaa(x_x, z, y),
+ | b(
+ | x,
+ | yy,
+ | zzz(
+ | a,
+ | b,
+ | c
+ | )
+ | ),
+ | c(firstGroupOne(x)),
+ | d,
+ | e,
+ | f
+ |)"""
+
+ """o.manyArguments(
+ | abc = 0,
+ | abcOne = 1,
+ | abcTwo,
+ | abcThree = 3,
+ | abcFour = 4,
+ | abcFive = 3
+ |)""" ==>
+ """o.manyArguments(
+ | abc = 0,
+ | abcOne = 1,
+ | abcTwo,
+ | abcThree = 3,
+ | abcFour = 4,
+ | abcFive = 3
+ |)"""
+
+ """Nested1(abcccc = 1,
+ | abc2 = 2,
+ | abcThree = 3
+ |)""" ==>
+ """Nested1(
+ | abcccc = 1,
+ | abc2 = 2,
+ | abcThree = 3
+ |)"""
+
+ """o.grouped(
+ | firstGroupOne = 1,
+ | firstGroup2 = "One",
+ |
+ | secondGroupOne = 2,
+ | secondGroup2 = "Two",
+ |
+ | thirdGroupOne = 3,
+ | thirdGroup2 = Three(3)
+ |)""" ==>
+ """o.grouped(
+ | firstGroupOne = 1,
+ | firstGroup2 = "One",
+ |
+ | secondGroupOne = 2,
+ | secondGroup2 = "Two",
+ |
+ | thirdGroupOne = 3,
+ | thirdGroup2 = Three(3)
+ |)"""
+
+ """multiClause(
+ | arg1 = 1,
+ | argument2 = 2)(
+ | args3 = 3,
+ | arg4 = 4)(
+ | arg5 = 5)""" ==>
+ """multiClause(
+ | arg1 = 1,
+ | argument2 = 2
+ |)(
+ | args3 = 3,
+ | arg4 = 4
+ |)(
+ | arg5 = 5
+ |)"""
+
+ """a(
+ |b = c)(
+ |c,
+ |d)(
+ |d)""" ==>
+ """a(
+ | b = c
+ |)(
+ | c,
+ | d
+ |)(
+ | d
+ |)"""
+
+ """Nested0(
+ | arg1 = Nested1(abcccc = 1,
+ | abc2 = 2,
+ | abcThree = 3
+ | ),
+ | NestedTwo(abcccc = 1,
+ | abc2 = 2,
+ | abcThree = 3
+ | )
+ |)""" ==>
+ """Nested0(
+ | arg1 = Nested1(
+ | abcccc = 1,
+ | abc2 = 2,
+ | abcThree = 3
+ | ),
+ | NestedTwo(
+ | abcccc = 1,
+ | abc2 = 2,
+ | abcThree = 3
+ | )
+ |)"""
}
+ override val debug = false
+}
\ No newline at end of file
diff --git a/scalariform/src/test/scala/scalariform/formatter/MiscFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/MiscFormatterTest.scala
new file mode 100644
index 00000000..3aae6386
--- /dev/null
+++ b/scalariform/src/test/scala/scalariform/formatter/MiscFormatterTest.scala
@@ -0,0 +1,46 @@
+package scalariform.formatter
+
+import scalariform.parser.{FullDefOrDcl, ScalaParser}
+
+class MiscFormatterTest extends AbstractFormatterTest {
+
+ """class Foo(
+ | bar: String,
+ | baz: String
+ |)""" ==>
+ """class Foo(
+ | bar: String,
+ | baz: String
+ |)"""
+
+ """class Foo(
+ | bar: String,
+ | baz: String)""" ==>
+ """class Foo(
+ | bar: String,
+ | baz: String
+ |)"""
+
+ """class Foo(
+ |)""" ==>
+ """class Foo()"""
+
+ """class a()""" ==>
+ """class a()"""
+
+ """def a()""" ==>
+ """def a()"""
+
+ """class a(b: Int)""" ==>
+ """class a(b: Int)"""
+
+ """def a(b: Int)""" ==>
+ """def a(b: Int)"""
+
+ def parse(parser: ScalaParser) = parser.nonLocalDefOrDcl()
+
+ type Result = FullDefOrDcl
+
+ def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0))
+
+}
\ No newline at end of file
diff --git a/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala
index 4634e8d5..ae340c07 100644
--- a/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala
@@ -60,8 +60,5 @@ class PackageFormatterTest extends AbstractFormatterTest {
|class Baz
|}
|}"""
-
}
-
-
}
diff --git a/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala
index 972bfbef..22b3c69f 100644
--- a/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala
@@ -7,77 +7,77 @@ import scalariform.formatter.preferences._
// format: OFF
class TemplateFormatterTest extends AbstractFormatterTest {
- "case class A" ==> "case class A"
+"case class A" ==> "case class A"
- """class A extends B {
- | foo()
- | bar()
- |}""" ==>
- """class A extends B {
- | foo()
- | bar()
- |}"""
+"""class A extends B {
+ | foo()
+ | bar()
+ |}""" ==>
+"""class A extends B {
+ | foo()
+ | bar()
+ |}"""
- """class A {
- |val n: Int
- |}""" ==>
- """class A {
- | val n: Int
- |}"""
+"""class A {
+ |val n: Int
+ |}""" ==>
+"""class A {
+ | val n: Int
+ |}"""
- "class A" ==> "class A"
- "trait A" ==> "trait A"
-
- "class A private (val b: C)" ==> "class A private (val b: C)"
- "class A [B]" ==> "class A[B]"
- "class A[B]private(val c: D)" ==> "class A[B] private (val c: D)"
- "class A (val b: C) (val d: E) (implicit val f: G)" ==> "class A(val b: C)(val d: E)(implicit val f: G)"
- "class A (implicit val f: G)" ==> "class A(implicit val f: G)"
-
- "abstract class E [F]private(val h: I) (implicit j: K) extends{} with L(2) with M{}" ==>
- "abstract class E[F] private (val h: I)(implicit j: K) extends {} with L(2) with M {}"
-
- "class A{}" ==> "class A {}"
-
- "class A@Deprecated()private (val b: C)" ==> "class A @Deprecated() private (val b: C)"
- "class A@Annotation1()@Annotation2()(val b: C)" ==> "class A @Annotation1() @Annotation2() (val b: C)"
- "class A[B]@Annotation()private(val c: D)" ==> "class A[B] @Annotation() private (val c: D)"
-
- "class A @Deprecated" ==> "class A @Deprecated"
- "class A @Deprecated private" ==> "class A @Deprecated private"
- "class A @Deprecated private (n: Int)" ==> "class A @Deprecated private (n: Int)"
-
- """@A@B(c = "d")abstract class E [F]@G()private(val h: I) (implicit j: K) extends{} with L(2) with M{}""" ==>
- """@A @B(c = "d") abstract class E[F] @G() private (val h: I)(implicit j: K) extends {} with L(2) with M {}"""
-
- """@A/*a*/@B
- |/*b*/class E""" =/=>
- """@A/*a*/
- |@B
- |/*b*/
- |class E""" because "of inconsistency between spacing between annotations and comments"
-
- """/*a*/@A/*b*/@B(c = "d")/*c*/abstract class/*d*/E/*e*/[F]/*f*/@G()/*g*/private/*h*/(val h: I)/*i*/(implicit j: K)/*j*/extends/*k*/{} with/*l*/L(2) with M/*m*/{}""" =/=>
- """/*a*/
- |@A/*b*/
- |@B(c = "d")/*c*/
- |abstract class/*d*/E/*e*/[F]/*f*/@G()/*g*/private/*h*/(val h: I)/*i*/(implicit j: K)/*j*/extends/*k*/{} with/*l*/L(2) with M/*m*/{}""" because "sort out what we want"
-
+"class A" ==> "class A"
+"trait A" ==> "trait A"
- {
-
- implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, true)
+"class A private (val b: C)" ==> "class A private (val b: C)"
+"class A [B]" ==> "class A[B]"
+"class A[B]private(val c: D)" ==> "class A[B] private (val c: D)"
+"class A (val b: C) (val d: E) (implicit val f: G)" ==> "class A(val b: C)(val d: E)(implicit val f: G)"
+"class A (implicit val f: G)" ==> "class A(implicit val f: G)"
+
+"abstract class E [F]private(val h: I) (implicit j: K) extends{} with L(2) with M{}" ==>
+ "abstract class E[F] private (val h: I)(implicit j: K) extends {} with L(2) with M {}"
+
+"class A{}" ==> "class A {}"
+
+"class A@Deprecated()private (val b: C)" ==> "class A @Deprecated() private (val b: C)"
+"class A@Annotation1()@Annotation2()(val b: C)" ==> "class A @Annotation1() @Annotation2() (val b: C)"
+"class A[B]@Annotation()private(val c: D)" ==> "class A[B] @Annotation() private (val c: D)"
+
+"class A @Deprecated" ==> "class A @Deprecated"
+"class A @Deprecated private" ==> "class A @Deprecated private"
+"class A @Deprecated private (n: Int)" ==> "class A @Deprecated private (n: Int)"
+
+"""@A@B(c = "d")abstract class E [F]@G()private(val h: I) (implicit j: K) extends{} with L(2) with M{}""" ==>
+"""@A @B(c = "d") abstract class E[F] @G() private (val h: I)(implicit j: K) extends {} with L(2) with M {}"""
+
+"""@A/*a*/@B
+ |/*b*/class E""" =/=>
+"""@A/*a*/
+ |@B
+ |/*b*/
+ |class E""" because "of inconsistency between spacing between annotations and comments"
+
+"""/*a*/@A/*b*/@B(c = "d")/*c*/abstract class/*d*/E/*e*/[F]/*f*/@G()/*g*/private/*h*/(val h: I)/*i*/(implicit j: K)/*j*/extends/*k*/{} with/*l*/L(2) with M/*m*/{}""" =/=>
+"""/*a*/
+ |@A/*b*/
+ |@B(c = "d")/*c*/
+ |abstract class/*d*/E/*e*/[F]/*f*/@G()/*g*/private/*h*/(val h: I)/*i*/(implicit j: K)/*j*/extends/*k*/{} with/*l*/L(2) with M/*m*/{}""" because "sort out what we want"
+
+
+{
+
+implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, true)
+
+"@(Id@Field) class A" ==> "@(Id @Field) class A"
+
+}
- "@(Id@Field) class A" ==> "@(Id @Field) class A"
-
- }
-
"""class A {
- |
+ |
| class B
- |
+ |
| protected def c
- |
+ |
|}""" ==>
"""class A {
|
@@ -88,7 +88,7 @@ class TemplateFormatterTest extends AbstractFormatterTest {
|}"""
"""class A{
- |(
+ |(
|null match {
|case b => val c = {d: Int => 1}
|1.toString
@@ -101,7 +101,8 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| case b =>
| val c = { d: Int => 1 }
| 1.toString
- | })
+ | }
+ | )
|}"""
"""class C1492 {
@@ -156,7 +157,7 @@ class TemplateFormatterTest extends AbstractFormatterTest {
|}"""
"""trait A {
- |this: B =>
+ |this: B =>
|val c
|}""" ==>
"""trait A {
@@ -164,8 +165,8 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| val c
|}"""
- """trait A {
- |this: B =>
+ """trait A {
+ |this: B =>
|println("foo")
|}""" ==>
"""trait A {
@@ -179,12 +180,12 @@ class TemplateFormatterTest extends AbstractFormatterTest {
"@serializable class A" ==> "@serializable class A"
"@volatile var nParticles = 0" ==> "@volatile var nParticles = 0" // Issue #28
-
+
"""@volatile
|var nParticles = 0""" ==>
"""@volatile
|var nParticles = 0"""
-
+
"""class A extends B[C] {
|println("foo")
|}""" ==>
@@ -287,9 +288,9 @@ class TemplateFormatterTest extends AbstractFormatterTest {
"class A {\r\n b()\r\n}" ==> "class A {\r\n b()\r\n}"
"""class A(
- |m: Int,
+ |m: Int,
|n: { def open(): Unit
- |def close(): Unit},
+ |def close(): Unit},
|o: Int)""" ==>
"""class A(
| m: Int,
@@ -297,12 +298,13 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| def open(): Unit
| def close(): Unit
| },
- | o: Int)"""
+ | o: Int
+ |)"""
"""class A(
|n: Int, m: {def foo(): Int
|def bar(a: String): Int}, o: Int,
- |p: Int,
+ |p: Int,
|m: {def foo(): Int
|def bar(a: String): Int})""" ==>
"""class A(
@@ -314,22 +316,234 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| m: {
| def foo(): Int
| def bar(a: String): Int
- | })"""
+ | }
+ |)"""
+
+{
+ implicit val formattingPreferences = FormattingPreferences.
+ setPreference(AlignParameters, true).
+ setPreference(SpaceBeforeColon, true).
+ setPreference(SpaceInsideBrackets, true)
+
+ """def a(
+ |a: Int = 1,
+ |abc: Boolean = true): Int""" ==>
+ """def a(
+ | a : Int = 1,
+ | abc : Boolean = true
+ |) : Int"""
+
+ """def a(
+ |a: Option[Either[Int]] = 1,
+ |abc: Boolean = true): Int""" ==>
+ """def a(
+ | a : Option[ Either[ Int ] ] = 1,
+ | abc : Boolean = true
+ |) : Int"""
+}
- {
+{
+ implicit val formattingPreferences = FormattingPreferences.
+ setPreference(AlignParameters, true).
+ setPreference(RewriteArrowSymbols, true)
+
+ // Formats rewritten arrows correctly
+ """def A(
+ | a: A => B = null,
+ | bee: => B = null,
+ | c: B => C = null
+ |): D""" ==>
+ """def A(
+ | a: A ⇒ B = null,
+ | bee: ⇒ B = null,
+ | c: B ⇒ C = null
+ |): D"""
+
+ """class a(
+ | b: Int
+ |)""" ==>
+ """class a(
+ | b: Int
+ |)"""
+
+ """class a(
+ | a: String = "",
+ | b: Int = 0
+ |)(
+ | c: String = "",
+ | d: Int = 1
+ |)(
+ | implicit
+ | val e: String = "",
+ | f: Int = 2
+ |)""" =/=>
+ """class a(
+ | a: String = ""
+ | b: Int = 0
+ |)(
+ | c: String = ""
+ | d: Int = 1
+ |)(
+ | implicit
+ | val e: String = ""
+ | f: Int = 2
+ |)"""
+}
+
+{
implicit val formattingPreferences = FormattingPreferences.setPreference(AlignParameters, true)
- """class A(n: Int,
+
+ // Make sure spacing in same line implicit parameters is preserved
+ """class A[T](a: T)(implicit b: B)""" ==>
+ """class A[T](a: T)(implicit b: B)"""
+ """class A[T](a: T)(implicit b: B, c: C)""" ==>
+ """class A[T](a: T)(implicit b: B, c: C)"""
+ """class A[T](a: T)(implicit b: B, c: C,
+ |d: D)""" ==>
+ """class A[T](a: T)(implicit b: B, c: C,
+ | d: D)"""
+
+ // Split into 3 columns: name, type, and default
+ """def showInput[A](
+ | parent: Component = null,
+ | message: Any,
+ | title: String = uiString("OptionPane.inputDialogTitle"),
+ | messageType: Message.Value = Message.Question,
+ | icon: Icon = EmptyIcon,
+ | entries: Seq[A] = Nil,
+ | initial: A): Option[A]""" ==>
+ """def showInput[A](
+ | parent: Component = null,
+ | message: Any,
+ | title: String = uiString("OptionPane.inputDialogTitle"),
+ | messageType: Message.Value = Message.Question,
+ | icon: Icon = EmptyIcon,
+ | entries: Seq[A] = Nil,
+ | initial: A
+ |): Option[A]"""
+
+ // Formats function types correctly
+ """private def executeWithinClient[T](
+ |crawlerConfig: String => JsValue = Fancy.function,
+ |f: HttpCrawlerClient => T,
+ |port: Int = SpecHelper.port): T""" ==>
+ """private def executeWithinClient[T](
+ | crawlerConfig: String => JsValue = Fancy.function,
+ | f: HttpCrawlerClient => T,
+ | port: Int = SpecHelper.port
+ |): T"""
+
+ // By name parameters have correct spacing
+ """def a(
+ | p1: => (SomeLongByNameParam => SomeShorterParam) = Null,
+ | param2: SomeShorterParam = Null): A""" ==>
+ """def a(
+ | p1: => (SomeLongByNameParam => SomeShorterParam) = Null,
+ | param2: SomeShorterParam = Null
+ |): A"""
+
+ // Formats parameterized types correctly
+ """def A(complicatedType: Option[B ,C, D[E, F,G]] = None,
+ | simpleType: String = ""): B""" ==>
+ """def A(
+ | complicatedType: Option[B, C, D[E, F, G]] = None,
+ | simpleType: String = ""
+ |): B"""
+
+
+ // Param gets placed onto a new line due to current limitations of existing IntertokenFormatInstructions
+ """case class Spacing(param: Int = 1,
+ |paramTwo: Int = 2,
+ |paramThree: String = "3")""" ==>
+ """case class Spacing(
+ | param: Int = 1,
+ | paramTwo: Int = 2,
+ | paramThree: String = "3"
+ |)"""
+
+ // Groups and formats consecutive single line parameters (multi line params)
+ """case class Spacing(param: Int = 1,
+ |paramTwo: Int = 2,
+ |paramThree: {
+ | val test: Int
+ |},
+ |paramFour: Option[String] = Some("One"),
+ |paramFive: Any = Nothing)""" ==>
+ """case class Spacing(
+ | param: Int = 1,
+ | paramTwo: Int = 2,
+ | paramThree: {
+ | val test: Int
+ | },
+ | paramFour: Option[String] = Some("One"),
+ | paramFive: Any = Nothing
+ |)"""
+
+ // Groups and formats consecutive single line parameters (newlines)
+ """case class Spacing(
+ |param: Int = 1,
+ |paramTwo: Int = 2,
+ |
+ |paramFour: Option[String] = Some("One"),
+ |paramFive: Any = Nothing)""" ==>
+ """case class Spacing(
+ | param: Int = 1,
+ | paramTwo: Int = 2,
+ |
+ | paramFour: Option[String] = Some("One"),
+ | paramFive: Any = Nothing
+ |)"""
+
+ // Aligns implicits and curried parameters properly
+ """class SomeClass(
+ |parameterOne: Int = 1,
+ |val parameterTwo: Option[String] = None,
+ |three: String = "three")(
+ |intermediate: Int
+ |)(
+ |implicit val four: Int,
+ |five: String,
+ |six: Boolean)""" ==>
+ """class SomeClass(
+ | parameterOne: Int = 1,
+ | val parameterTwo: Option[String] = None,
+ | three: String = "three"
+ |)(
+ | intermediate: Int
+ |)(
+ | implicit
+ | val four: Int,
+ | five: String,
+ | six: Boolean
+ |)"""
+
+ // Handles annotations, modifiers, and comments
+ """def extraStuff(
+ |// comment 1
+ |@Annotated paramOne: Int = 1, // comment 2
+ |/* comment 3 */ private val modifiedTwo: String = "two",
+ |@Annotated2("complicatedAnnotation") @A3("Another") protected annotatedAndModified: Option[Int] = Some(3))""" ==>
+ """def extraStuff(
+ | // comment 1
+ | @Annotated paramOne: Int = 1, // comment 2
+ | /* comment 3 */ private val modifiedTwo: String = "two",
+ | @Annotated2("complicatedAnnotation")@A3("Another") protected annotatedAndModified: Option[Int] = Some(3)
+ |)"""
+
+ """class A(n: Int,
|z: { val m
|val n },
|m: Int)""" ==>
- """class A(n: Int,
- | z: {
- | val m
- | val n
- | },
- | m: Int)"""
-
- """class A(m: Int,
+ """class A(
+ | n: Int,
+ | z: {
+ | val m
+ | val n
+ | },
+ | m: Int
+ |)"""
+
+ """class A(m: Int,
|n: {
|val x: String
|val y : String
@@ -337,38 +551,43 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| o: Int = {
| 42
|})""" ==>
- """class A(m: Int,
- | n: {
- | val x: String
- | val y: String
- | },
- | o: Int = {
- | 42
- | })"""
+ """class A(
+ | m: Int,
+ | n: {
+ | val x: String
+ | val y: String
+ | },
+ | o: Int = {
+ | 42
+ | }
+ |)"""
"""class A(n: {
| def close(): Unit
| def open(): Unit
- |},
+ |},
|m: Int)""" ==>
- """class A(n: {
- | def close(): Unit
- | def open(): Unit
- | },
- | m: Int)"""
-
+ """class A(
+ | n: {
+ | def close(): Unit
+ | def open(): Unit
+ | },
+ | m: Int
+ |)"""
+
"""class A(
|implicit n: {
|def x: Int
|def y: Int
|})""" ==>
"""class A(
- | implicit n: {
+ | implicit
+ | n: {
| def x: Int
| def y: Int
- | })"""
-
-
+ | }
+ |)"""
+
"""class A(n: {
|def x: Int
|})""" ==>
@@ -376,53 +595,59 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| def x: Int
| })"""
- """class A(a: Int,
- |b: Int)(c: { val d: Int
- |})""" ==>
"""class A(a: Int,
- | b: Int)(c: {
- | val d: Int
- | })"""
-
- }
-
- """class A(a: Int,
|b: Int)(c: { val d: Int
|})""" ==>
- """class A(a: Int,
- | b: Int)(c: {
+ """class A(
+ | a: Int,
+ | b: Int
+ |)(c: {
| val d: Int
| })"""
+ }
+
+ """class A(a: Int,
+ |b: Int)(c: { val d: Int
+ |})""" ==>
+ """class A(
+ | a: Int,
+ | b: Int
+ |)(c: {
+ | val d: Int
+ |})"""
+
{
implicit val formattingPreferences = FormattingPreferences.setPreference(DoubleIndentClassDeclaration, true)
- """class Person(
- | name: String,
- | age: Int)
- | extends Entity
- | with Logging
- | with Identifiable
- | with Serializable""" ==>
- """class Person(
- | name: String,
- | age: Int)
- | extends Entity
- | with Logging
- | with Identifiable
- | with Serializable"""
+ """class Person(
+ | name: String,
+ | age: Int)
+ | extends Entity
+ | with Logging
+ | with Identifiable
+ | with Serializable""" ==>
+ """class Person(
+ | name: String,
+ | age: Int
+ |)
+ | extends Entity
+ | with Logging
+ | with Identifiable
+ | with Serializable"""
+
+ """class Person(
+ | name: String,
+ | age: Int) {
+ | def firstMethod = 42
+ |}""" ==>
+ """class Person(
+ | name: String,
+ | age: Int
+ |) {
+ | def firstMethod = 42
+ |}"""
- """class Person(
- | name: String,
- | age: Int) {
- | def firstMethod = 42
- |}""" ==>
- """class Person(
- | name: String,
- | age: Int) {
- | def firstMethod = 42
- |}"""
-
- """class Person(name: String, age: Int, birthdate: Date, astrologicalSign: String, shoeSize: Int, favoriteColor: java.awt.Color)
+ """class Person(name: String, age: Int, birthdate: Date, astrologicalSign: String, shoeSize: Int, favoriteColor: java.awt.Color)
|extends Entity
|with Logging
|with Identifiable
@@ -437,21 +662,22 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| def firstMethod = 42
|}"""
- """class Person(
- |name: String,
- | age: Int)
- |extends Entity {
- |def method() = 42
- |}""" ==>
- """class Person(
- | name: String,
- | age: Int)
- | extends Entity {
- | def method() = 42
- |}"""
+ """class Person(
+ |name: String,
+ | age: Int)
+ |extends Entity {
+ |def method() = 42
+ |}""" ==>
+ """class Person(
+ | name: String,
+ | age: Int
+ |)
+ | extends Entity {
+ | def method() = 42
+ |}"""
- """trait A
- |extends B
+ """trait A
+ |extends B
|with C {
|println("d")
|}""" ==>
@@ -462,11 +688,11 @@ class TemplateFormatterTest extends AbstractFormatterTest {
|}"""
}
-
+
"trait Function1[@specialized(Int, Long, Double) -T1, @specialized(Unit, Int, Long, Double) +R] extends AnyRef" ==>
"trait Function1[@specialized(Int, Long, Double) -T1, @specialized(Unit, Int, Long, Double) +R] extends AnyRef"
-
- """class C
+
+"""class C
|extends {
|val name = "Bob"
|}""" ==>
@@ -607,7 +833,7 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| bar()
|}"""
- // format: ON
+// format: ON
override val debug = false
@@ -617,4 +843,4 @@ class TemplateFormatterTest extends AbstractFormatterTest {
def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0))
-}
+}
\ No newline at end of file