Skip to content

Commit

Permalink
Merge pull request #256 from godenji/0.2.5
Browse files Browse the repository at this point in the history
0.2.5 release
  • Loading branch information
godenji authored Oct 28, 2017
2 parents 85d570c + 4ee6d36 commit e51e7fd
Show file tree
Hide file tree
Showing 23 changed files with 158 additions and 44 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
0.2.5 (27/October/17)

* Added support for single case pattern without forced newline (fixes #29)

0.2.4 (25/October/17)

* Updated to Scala 2.12.4
Expand Down
16 changes: 15 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Usage within a project

Have a use for the scalariform source code directly? You can use it as a build dependency: ::

"org.scalariform" %% "scalariform" % "0.2.4"
"org.scalariform" %% "scalariform" % "0.2.5"

Integration with Eclipse
------------------------
Expand Down Expand Up @@ -765,6 +765,20 @@ is formatted as:
case 1 ⇒ println("odd")
}
singleCasePatternOnNewline
~~~~~~~~~~~~~~~~~~~~~~~~~~

Default: ``true``

When ``singleCasePatternOnNewline`` is ``false`` the default behavior of forcing
a single case pattern onto a newline is disabled. This allows for the following formatting style:

.. code:: scala
items.map { case (key, value) =>
(key, transform(value))
}
spaceBeforeColon
~~~~~~~~~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions formatterPreferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ danglingCloseParenthesis=Force
#placeScaladocAsterisksBeneathSecondAsterisk=false
#preserveSpaceBeforeArguments=false
#rewriteArrowSymbols=false
#singleCasePatternOnNewline=true
#spaceBeforeColon=false
#spaceBeforeContextColon=false
#spaceInsideBrackets=false
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.scalariform</groupId>
<artifactId>scalariform.parent</artifactId>
<version>0.2.4</version>
<version>0.2.5</version>
<packaging>pom</packaging>

<!-- scm configuration is require to extract the github hash-->
Expand Down
2 changes: 1 addition & 1 deletion scalariform.feature/feature.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<feature
id="scalariform.feature"
label="Scalariform"
version="0.2.4">
version="0.2.5">

<description>
Scala Code formatter
Expand Down
2 changes: 1 addition & 1 deletion scalariform.feature/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<parent>
<artifactId>scalariform.parent</artifactId>
<groupId>org.scalariform</groupId>
<version>0.2.4</version>
<version>0.2.5</version>
</parent>
</project>
2 changes: 1 addition & 1 deletion scalariform.update/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<parent>
<artifactId>scalariform.parent</artifactId>
<groupId>org.scalariform</groupId>
<version>0.2.4</version>
<version>0.2.5</version>
</parent>
</project>
4 changes: 2 additions & 2 deletions scalariform.update/site.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<site>
<description name="Scalariform Update Site"
url="https://github.com/scala-ide/scalariform/tree/0.2.4/scalariform.update/target/site">
url="https://github.com/scala-ide/scalariform/tree/0.2.5/scalariform.update/target/site">
Scalariform Update Site
</description>
<feature url="features/scalariform.feature_0.2.4.jar" version="0.2.4" id="scalariform.feature">
<feature url="features/scalariform.feature_0.2.5.jar" version="0.2.5" id="scalariform.feature">
<category name="Scala"/>
</feature>
<category-def name="Scala" label="Scala"/>
Expand Down
Binary file modified scalariform.update/target/site.zip
Binary file not shown.
Binary file modified scalariform.update/target/site/artifacts.jar
Binary file not shown.
Binary file modified scalariform.update/target/site/content.jar
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
4 changes: 2 additions & 2 deletions scalariform.update/target/site/site.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<site>
<description name="Scalariform Update Site"
url="https://github.com/scala-ide/scalariform/tree/0.2.4/scalariform.update/target/site">
url="https://github.com/scala-ide/scalariform/tree/0.2.5/scalariform.update/target/site">
Scalariform Update Site
</description>
<feature url="features/scalariform.feature_0.2.4.jar" version="0.2.4" id="scalariform.feature">
<feature url="features/scalariform.feature_0.2.5.jar" version="0.2.5" id="scalariform.feature">
<category name="Scala"/>
</feature>
<category-def name="Scala" label="Scala"/>
Expand Down
Binary file modified scalariform.update/target/site_assembly.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion scalariform/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Scalariform
Bundle-SymbolicName: scalariform
Bundle-Version: 0.2.4
Bundle-Version: 0.2.5
Require-Bundle: org.scala-lang.scala-library,
org.scala-lang.modules.scala-xml
Bundle-ClassPath: .
Expand Down
2 changes: 1 addition & 1 deletion scalariform/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<artifactId>scalariform.parent</artifactId>
<groupId>org.scalariform</groupId>
<version>0.2.4</version>
<version>0.2.5</version>
</parent>
<dependencies>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi

var formatResult: FormatResult = NoFormatResult
var isFirstCaseClause = true
val hasSingleCaseClause = clauseGroups.size == 1

// We have to decide whether to indent the hidden tokens before the CASE token (or possibly a preceding
// NEWLINE token from a prior case block).
Expand All @@ -35,7 +36,7 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi

def formatSingleCaseClause(caseClause: CaseClause) {
handleCaseIndent(caseClause)
formatResult ++= formatCaseClause(caseClause)
formatResult ++= formatCaseClause(caseClause, None, hasSingleCaseClause)
isFirstCaseClause = false
}

Expand All @@ -46,7 +47,9 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
for (caseClause @ CaseClause(casePattern, statSeq) caseClauses) {
handleCaseIndent(caseClause)
val arrowInstruction = PlaceAtColumn(formatterState.indentLevel, largestCasePatternLength + 1)
formatResult ++= formatCaseClause(caseClause, Some(arrowInstruction))
formatResult ++= formatCaseClause(
caseClause, Some(arrowInstruction), hasSingleCaseClause
)
isFirstCaseClause = false
}
} else {
Expand Down Expand Up @@ -104,22 +107,55 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
formatResult
}

private def formatCaseClause(caseClause: CaseClause, arrowInstructionOpt: Option[PlaceAtColumn] = None)(implicit formatterState: FormatterState): FormatResult = {
private def formatCaseClause(
caseClause: CaseClause,
arrowInstructionOpt: Option[PlaceAtColumn],
hasSingleCaseClause: Boolean
)(implicit formatterState: FormatterState): FormatResult = {

val CaseClause(casePattern, statSeq) = caseClause
var formatResult: FormatResult = NoFormatResult
formatResult ++= formatCasePattern(casePattern, arrowInstructionOpt)
val hasNewline = caseClause.casePattern.caseToken.associatedWhitespaceAndComments.containsNewline
val singleCaseWithoutNewline = (
hasSingleCaseClause && !hasNewline && !formattingPreferences(SingleCasePatternOnNewline)
)
val singleExpr =
cond(statSeq.firstStatOpt) { case Some(Expr(_)) true } &&
cond(statSeq.otherStats) { case Nil | List((_, None)) true }
val indentBlock =
statSeq.firstTokenOption.isDefined && newlineBefore(statSeq) ||
containsNewline(statSeq) && !singleExpr
if (indentBlock)
formatResult = formatResult.before(statSeq.firstToken, formatterState.nextIndentLevelInstruction)

val stateForStatSeq = if (singleExpr && !indentBlock) formatterState else formatterState.indent
formatResult ++= format(statSeq)(stateForStatSeq)
def unindent(x: Map[Token, IntertokenFormatInstruction]) = x.map {
case (k, v @ EnsureNewlineAndIndent(indentLevel, relativeTo)) =>
k -> EnsureNewlineAndIndent(indentLevel - 1, relativeTo)
case x => x
}

if (indentBlock) {
val result = formatResult.before(statSeq.firstToken, formatterState.nextIndentLevelInstruction)
formatResult =
if(!singleCaseWithoutNewline) result
else
result.copy(
predecessorFormatting =
unindent(result.predecessorFormatting) + ( // unindent first token in case body
caseClause.casePattern.caseToken -> CompactEnsuringGap // remove `case` leading newline
)
)
}

val stateForStatSeq = if (singleExpr && !indentBlock) formatterState else formatterState.indent
formatResult ++= {
val result = format(statSeq)(stateForStatSeq)
if(!singleCaseWithoutNewline) result
else
result.copy( // unindent body tokens
predecessorFormatting = unindent(result.predecessorFormatting),
inferredNewlineFormatting = unindent(result.inferredNewlineFormatting)
)
}
formatResult
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,6 @@ abstract class ScalaFormatter
var suspendFormatting = false
var edits: List[TextEdit] = Nil // Stored in reverse

def printableFormattingInstruction(previousTokenOption: Option[Token], token: Token, nextTokenOption: Option[Token]) = {
val maybePredecessorFormatting = predecessorFormatting.get(token)
val isGaplessAssignment =
// avoid `foreach(_.id= ..)` and `foreach(foo= _)` gapless assignment (see MutateTest.scala)
maybePredecessorFormatting exists {
case x @ PlaceAtColumn(_, _, Some(Token(USCORE, _, _, _))) => token.tokenType == EQUALS
case _ => token.tokenType == EQUALS && nextTokenOption.exists(_.tokenType == USCORE)
}
val maybeInstruction =
if (isGaplessAssignment) Some(CompactEnsuringGap)
else
maybePredecessorFormatting.orElse(
previousTokenOption.map(defaultFormattingInstruction(_, token))
)
maybeInstruction.getOrElse(
if (token.tokenType == EOF) EnsureNewlineAndIndent(0) /* <-- to allow formatting of files with just a scaladoc comment */
else Compact
)
}

for ((previousTokenOption, token, nextTokenOption) Utils.withPreviousAndNext(tokens)) {
val previousTokenIsPrintable = previousTokenOption exists { !isInferredNewline(_) }
if (isInferredNewline(token)) {
Expand All @@ -130,7 +110,9 @@ abstract class ScalaFormatter
basicFormattingInstruction
val nextTokenUnindents = nextTokenOption exists { _.tokenType == RBRACE }
val includeBufferBeforeNextToken = nextTokenOption exists { nextToken
!printableFormattingInstruction(Some(token), nextToken, None).isInstanceOf[EnsureNewlineAndIndent]
!printableFormattingInstruction(
Some(token), nextToken, None, predecessorFormatting
).isInstanceOf[EnsureNewlineAndIndent]
}
edits :::= writeHiddenTokens(builder, inferredNewlines(token), formattingInstruction, nextTokenUnindents,
includeBufferBeforeNextToken, previousTokenIsPrintable, tokenIndentMap).toList
Expand All @@ -142,7 +124,10 @@ abstract class ScalaFormatter
tokenIndentMap += (token -> builder.currentColumn)
builder.append(token.rawText)
} else {
val formattingInstruction = printableFormattingInstruction(previousTokenOption, token, nextTokenOption)
val formattingInstruction =
printableFormattingInstruction(
previousTokenOption, token, nextTokenOption, predecessorFormatting
)
val nextTokenUnindents = token.tokenType == RBRACE
val includeBufferBeforeNextToken = true // <-- i.e. current token
val hiddenTokens = hiddenPredecessors(token)
Expand Down Expand Up @@ -444,6 +429,31 @@ abstract class ScalaFormatter
result
}

private def printableFormattingInstruction(
previousTokenOption: Option[Token],
token: Token,
nextTokenOption: Option[Token],
predecessorFormatting: Map[Token, IntertokenFormatInstruction]): IntertokenFormatInstruction = {

val maybePredecessorFormatting = predecessorFormatting.get(token)
val isGaplessAssignment =
maybePredecessorFormatting match {
// `foreach(_.id= ..)`
case x @ Some(PlaceAtColumn(_, _, Some(Token(USCORE, _, _, _)))) => token.tokenType == EQUALS
// `foreach(foo= _)`
case _ => token.tokenType == EQUALS && nextTokenOption.exists(_.tokenType == USCORE)
}
val maybeInstruction =
if(isGaplessAssignment) Some(CompactEnsuringGap)
else maybePredecessorFormatting.orElse(
previousTokenOption.map(defaultFormattingInstruction(_, token))
)
maybeInstruction.getOrElse(
if (token.tokenType == EOF) EnsureNewlineAndIndent(0) /* <-- to allow formatting of files with just a scaladoc comment */
else Compact
)
}

private def defaultFormattingInstruction(token1: Token, token2: Token): IntertokenFormatInstruction = {
val result = actualDefaultFormattingInstruction(token1, token2)
// println("defaultFormattingInstruction(" + token1 + ", " + token2 + ") = " + result)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ object AllPreferences {
AlignArguments, AlignParameters, AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent,
AllowParamGroupsOnNewlines, CompactControlReadability, CompactStringConcatenation, DanglingCloseParenthesis,
DoubleIndentClassDeclaration, DoubleIndentConstructorArguments, DoubleIndentMethodDeclaration, FirstArgumentOnNewline,
FirstParameterOnNewline, FormatXml, IndentLocalDefs, IndentPackageBlocks, IndentSpaces, IndentWithTabs, MultilineScaladocCommentsStartOnFirstLine,
NewlineAtEndOfFile, PlaceScaladocAsterisksBeneathSecondAsterisk, PreserveSpaceBeforeArguments, RewriteArrowSymbols,
SpaceBeforeColon, SpaceBeforeContextColon, SpaceInsideBrackets, SpaceInsideParentheses, SpacesAroundMultiImports, SpacesWithinPatternBinders
FirstParameterOnNewline, FormatXml, IndentLocalDefs, IndentPackageBlocks, IndentSpaces, IndentWithTabs,
MultilineScaladocCommentsStartOnFirstLine, NewlineAtEndOfFile, PlaceScaladocAsterisksBeneathSecondAsterisk,
PreserveSpaceBeforeArguments, RewriteArrowSymbols, SingleCasePatternOnNewline, SpaceBeforeColon,
SpaceBeforeContextColon, SpaceInsideBrackets, SpaceInsideParentheses, SpacesAroundMultiImports, SpacesWithinPatternBinders
)

val preferencesByKey: Map[String, PreferenceDescriptor[_]] =
Expand Down Expand Up @@ -245,6 +246,12 @@ case object RewriteArrowSymbols extends BooleanPreferenceDescriptor {
val defaultValue = false
}

case object SingleCasePatternOnNewline extends BooleanPreferenceDescriptor {
val key = "singleCasePatternOnNewline"
val description = "Single case in pattern match block on a new line"
val defaultValue = true
}

case object SpaceBeforeColon extends BooleanPreferenceDescriptor {
val key = "spaceBeforeColon"
val description = "Space before colons"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,48 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
| d
|}"""

{
implicit val formattingPreferences = FormattingPreferences.setPreference(
SingleCasePatternOnNewline, false
)
"""a match { case a => b; c;
|d }""" ==>
"""a match { case a =>
| b; c;
| d
|}"""

"""a match { case b =>
|val c = d
|case e =>
|}""" ==>
"""a match {
| case b =>
| val c = d
| case e =>
|}"""

"""list.foreach { case (key, value) =>
|val boo = 1
|boo
|}""" ==>
"""list.foreach { case (key, value) =>
| val boo = 1
| boo
|}"""

"""list.foreach {
|case (key, value) =>
|val boo = 1
|boo
|}""" ==>
"""list.foreach {
| case (key, value) =>
| val boo = 1
| boo
|}"""
}

"a match { case b => ; c }" ==> "a match { case b => ; c }"

// See issue #60
Expand Down
2 changes: 1 addition & 1 deletion version.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version in ThisBuild := "0.2.5-SNAPSHOT"
version in ThisBuild := "0.2.5"

0 comments on commit e51e7fd

Please sign in to comment.