Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid empty lines in the beginning and end of blocks #1431

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions docs/configuration.md
Expand Up @@ -432,6 +432,39 @@ else {
}
```

### `newlines.avoidEmptyLinesAroundBlock`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section can be removed now.


```scala mdoc:defaults
newlines.avoidEmptyLinesAroundBlock
```

```scala mdoc:scalafmt
newlines.avoidEmptyLinesAroundBlock = false
---
def foo: String = {

val aux = {

"bar"

}

aux

}
```

```scala mdoc:scalafmt
newlines.avoidEmptyLinesAroundBlock = true
---
def foo: String = {
val aux = {
"bar"
}
aux
}
```

## Rewrite Rules

To enable a rewrite rule, add it to the config like this
Expand Down
@@ -0,0 +1,20 @@
package org.scalafmt.config

import metaconfig.{Conf, ConfDecoder, ConfEncoder, Configured}

sealed abstract class Edition(val order: Int, val name: String)

object Edition {
implicit val ordering: Ordering[Edition] = Ordering.by[Edition, Int](_.order)

implicit val decoder: ConfDecoder[Edition] = ConfDecoder.instance {
case Conf.Str("2019-10") => Configured.ok(Edition201910)
case _ => Configured.ok(EditionLatest)
}

implicit val encoder: ConfEncoder[Edition] =
ConfEncoder.instance(edition => Conf.Str(edition.name))
}

case object Edition201910 extends Edition(0, "2019-10")
case object EditionLatest extends Edition(Int.MaxValue, "latest")
Expand Up @@ -3,6 +3,8 @@ package org.scalafmt.config
import metaconfig._
import metaconfig.generic.Surface

import Edition.ordering._

/**
* @param penalizeSingleSelectMultiArgList
* If true, adds a penalty to newlines before a dot starting a select
Expand Down Expand Up @@ -110,9 +112,14 @@ case class Newlines(
beforeImplicitKWInVerticalMultiline: Boolean = false,
alwaysBeforeElseAfterCurlyIf: Boolean = false,
alwaysBeforeMultilineDef: Boolean = true,
avoidAfterYield: Boolean = true
avoidAfterYield: Boolean = true,
avoidEmptyLinesAroundBlock: Option[Boolean] = None
) {
val reader: ConfDecoder[Newlines] = generic.deriveDecoder(this).noTypos

def shouldAvoidEmptyLinesAroundBlock(edition: Edition): Boolean = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to a val inside ScalafmtConfig

avoidEmptyLinesAroundBlock.getOrElse(edition > Edition201910)
}
}

object Newlines {
Expand Down
Expand Up @@ -159,7 +159,8 @@ case class ScalafmtConfig(
verticalAlignMultilineOperators: Boolean = false,
onTestFailure: String = "",
encoding: Codec = "UTF-8",
project: ProjectFiles = ProjectFiles()
project: ProjectFiles = ProjectFiles(),
edition: Edition = EditionLatest
) {
private implicit val runnerReader = runner.reader
private implicit val projectReader = project.reader
Expand Down
Expand Up @@ -184,6 +184,7 @@ class Router(formatOps: FormatOps) {
selfAnnotation.nonEmpty
val nl: Modification =
if (isSelfAnnotation) newlines2Modification(formatToken)
else if (style.newlines.shouldAvoidEmptyLinesAroundBlock(style.edition)) NewlineT()
else NewlineT(shouldGet2xNewlines(tok, style, owners))

val (startsLambda, lambdaPolicy, lambdaArrow, lambdaIndent) =
Expand Down Expand Up @@ -347,6 +348,11 @@ class Router(formatOps: FormatOps) {
)
}

case FormatToken(_, T.RightBrace(), _)
if style.newlines.shouldAvoidEmptyLinesAroundBlock(style.edition) && newlines > 1 =>
Seq(
Split(NoSplit, 0)
)
case FormatToken(_, T.RightBrace(), _) =>
Seq(
Split(xmlSpace(rightOwner), 0),
Expand Down
1 change: 0 additions & 1 deletion scalafmt-tests/src/test/resources/default/Advanced.stat
Expand Up @@ -223,7 +223,6 @@ callStatement = js.If(genIsInstanceOf(callTrg, rtClass.tpe), {
rawApply
} else {
val reflBoxClassPatched = {

def isIntOrLongKind(kind: TypeKind) = kind match {
case _: INT | LONG => true
case _ => false
Expand Down
1 change: 0 additions & 1 deletion scalafmt-tests/src/test/resources/default/Apply.stat
Expand Up @@ -249,7 +249,6 @@ class ResolutionCopier(x: Int) {
}
>>>
class ResolutionCopier(x: Int) {

def visitClassDeclaration(node: ClassDeclaration): Boolean = {
val toNode = this._toNode.asInstanceOf[ClassDeclaration];
javaBooleanAnd(
Expand Down
1 change: 0 additions & 1 deletion scalafmt-tests/src/test/resources/default/Class.stat
Expand Up @@ -62,7 +62,6 @@ class MediaStream() extends EventTarget {
}
>>>
class MediaStream() extends EventTarget {

/**
*/
val ended: Boolean = js.native
Expand Down
5 changes: 0 additions & 5 deletions scalafmt-tests/src/test/resources/default/Comment.stat
Expand Up @@ -10,7 +10,6 @@
}
>>>
{

def cancel(reason: Any): js.Promise[Any] = js.native // comment

/**
Expand All @@ -29,7 +28,6 @@ object KeyValue {
}
>>>
object KeyValue {

// ================================
// 6.3.1 Special Key Values

Expand All @@ -45,7 +43,6 @@ object KeyValue {
}
>>>
object KeyValue {

// comment
/** This key value */
final val Unidentified = "Unidentified"
Expand Down Expand Up @@ -74,7 +71,6 @@ object D {
}
>>>
object D {

private val decompressedPrefixes: Seq[(String, String)] =
compressedPrefixes map { case (a, b) => (b, a) }

Expand All @@ -94,7 +90,6 @@ object Primes {
}
>>>
object Primes {

// prime sieve; use instead of the test or stream when you know the
// upper bound of the primes you will need.
// en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Expand Down
1 change: 0 additions & 1 deletion scalafmt-tests/src/test/resources/default/DefDef.stat
Expand Up @@ -9,7 +9,6 @@ object a {
}
>>>
object a {

/**
* Returns True is this state will always return better formatting than other.
*/
Expand Down
1 change: 0 additions & 1 deletion scalafmt-tests/src/test/resources/default/Fidelity.source
Expand Up @@ -10,7 +10,6 @@ object ScalaJSGroupID {
}
>>>
object ScalaJSGroupID {

def auto_impl(c: Context { type PrefixType = ScalaJSGroupID })()
: Expr[CrossGroupArtifactID] = {
reify {}
Expand Down
4 changes: 0 additions & 4 deletions scalafmt-tests/src/test/resources/default/Idempotency.stat
Expand Up @@ -86,7 +86,6 @@ val bindingFuture = Http().bindAndHandleSync({
>>>
{
{

{
{
{
Expand All @@ -103,7 +102,6 @@ val bindingFuture = Http().bindAndHandleSync({
}
}
}

}
<<< rendering #339
{{
Expand All @@ -130,7 +128,6 @@ val bindingFuture = Http().bindAndHandleSync({
RequestRenderingContext(request, hostHeader, sendEntityTrigger)
}
}

})
}
}
Expand Down Expand Up @@ -169,7 +166,6 @@ val bindingFuture = Http().bindAndHandleSync({
})
new ResponseParsingMerge(rootParser)
}

})
}
}
Expand Down
Expand Up @@ -132,7 +132,6 @@ object A {
}
>>>
object A {

/** test */
def foo(): Int = 0
// bar
Expand Down
@@ -0,0 +1,55 @@
maxColumn = 80
newlines.avoidEmptyLinesAroundBlock = true

<<< should remove empty lines at the beginning of a def block
def other: String = {

"Result"
}
>>>
def other: String = {
"Result"
}

<<< should remove empty lines at the beginning and end of a def block
def other: String = {

"Result"

}
>>>
def other: String = {
"Result"
}

<<< should remove empty lines at the beginning and end of a val block
def other: String = {

val aux = {

"Result"

}

aux

}
>>>
def other: String = {
val aux = {
"Result"
}

aux
}

<<< should remove empty lines at the end of a block
def other: String = {
"Result"


}
>>>
def other: String = {
"Result"
}
Expand Up @@ -15,14 +15,12 @@ object a {
}
>>>
object a {

val x: Int => String = {
case 2 =>
"two"
case _ =>
"other"
}

}
<<< case clauses with stuff
object a {
Expand All @@ -41,7 +39,6 @@ object a {
}
>>>
object a {

val x: Int => String = {
case 2 =>
println("TWO")
Expand All @@ -50,7 +47,6 @@ object a {
// Nice
"other"
}

}
<<< case clauses to unit
object a {
Expand All @@ -66,12 +62,10 @@ object a {
}
>>>
object a {

val x: Int => Unit = {
case 0 =>
case 1 =>
case 2 =>
case _ => println("?")
}

}
Expand Up @@ -15,15 +15,13 @@ object a {
}
>>>
object a {

def x(i: Int): String =
if (i == 0)
"zero"
else if (i < 0)
"sub-zero"
else
"other"

}
<<< if-else with stuff
object a {
Expand All @@ -50,7 +48,6 @@ object a {
}
>>>
object a {

def x(i: Int): String =
if (i == 0)
/* what */
Expand Down Expand Up @@ -88,7 +85,6 @@ object a {
}
>>>
object a {

val x: Int => Unit =
if (i == 0)
println("zero")
Expand All @@ -98,7 +94,6 @@ object a {
def y(i: Int) =
if (i > 0)
println("yes!")

}
<<< nested if
object a {
Expand Down
Expand Up @@ -32,7 +32,6 @@ private[test] sealed trait Test {
}

private[test] final object Tests {

protected[Tests] final case object Test1 extends Test {
final implicit override lazy val name: String = "foo"
}
Expand Down Expand Up @@ -66,7 +65,6 @@ private[test] sealed trait Test {
}

private[test] final object Tests {

protected[Tests] final case object Test1 extends Test {
final implicit override lazy val name: String = "foo"
}
Expand Down