Skip to content

Commit e51e7fd

Browse files
authored
Merge pull request #256 from godenji/0.2.5
0.2.5 release
2 parents 85d570c + 4ee6d36 commit e51e7fd

23 files changed

+158
-44
lines changed

CHANGELOG

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
0.2.5 (27/October/17)
2+
3+
* Added support for single case pattern without forced newline (fixes #29)
4+
15
0.2.4 (25/October/17)
26

37
* Updated to Scala 2.12.4

README.rst

+15-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Usage within a project
5252

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

55-
"org.scalariform" %% "scalariform" % "0.2.4"
55+
"org.scalariform" %% "scalariform" % "0.2.5"
5656

5757
Integration with Eclipse
5858
------------------------
@@ -765,6 +765,20 @@ is formatted as:
765765
case 1 ⇒ println("odd")
766766
}
767767
768+
singleCasePatternOnNewline
769+
~~~~~~~~~~~~~~~~~~~~~~~~~~
770+
771+
Default: ``true``
772+
773+
When ``singleCasePatternOnNewline`` is ``false`` the default behavior of forcing
774+
a single case pattern onto a newline is disabled. This allows for the following formatting style:
775+
776+
.. code:: scala
777+
778+
items.map { case (key, value) =>
779+
(key, transform(value))
780+
}
781+
768782
spaceBeforeColon
769783
~~~~~~~~~~~~~~~~
770784

formatterPreferences.properties

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ danglingCloseParenthesis=Force
2121
#placeScaladocAsterisksBeneathSecondAsterisk=false
2222
#preserveSpaceBeforeArguments=false
2323
#rewriteArrowSymbols=false
24+
#singleCasePatternOnNewline=true
2425
#spaceBeforeColon=false
2526
#spaceBeforeContextColon=false
2627
#spaceInsideBrackets=false

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>org.scalariform</groupId>
66
<artifactId>scalariform.parent</artifactId>
7-
<version>0.2.4</version>
7+
<version>0.2.5</version>
88
<packaging>pom</packaging>
99

1010
<!-- scm configuration is require to extract the github hash-->

scalariform.feature/feature.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<feature
33
id="scalariform.feature"
44
label="Scalariform"
5-
version="0.2.4">
5+
version="0.2.5">
66

77
<description>
88
Scala Code formatter

scalariform.feature/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
<parent>
99
<artifactId>scalariform.parent</artifactId>
1010
<groupId>org.scalariform</groupId>
11-
<version>0.2.4</version>
11+
<version>0.2.5</version>
1212
</parent>
1313
</project>

scalariform.update/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
<parent>
99
<artifactId>scalariform.parent</artifactId>
1010
<groupId>org.scalariform</groupId>
11-
<version>0.2.4</version>
11+
<version>0.2.5</version>
1212
</parent>
1313
</project>

scalariform.update/site.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<site>
33
<description name="Scalariform Update Site"
4-
url="https://github.com/scala-ide/scalariform/tree/0.2.4/scalariform.update/target/site">
4+
url="https://github.com/scala-ide/scalariform/tree/0.2.5/scalariform.update/target/site">
55
Scalariform Update Site
66
</description>
7-
<feature url="features/scalariform.feature_0.2.4.jar" version="0.2.4" id="scalariform.feature">
7+
<feature url="features/scalariform.feature_0.2.5.jar" version="0.2.5" id="scalariform.feature">
88
<category name="Scala"/>
99
</feature>
1010
<category-def name="Scala" label="Scala"/>

scalariform.update/target/site.zip

0 Bytes
Binary file not shown.
1 Byte
Binary file not shown.
1 Byte
Binary file not shown.
Binary file not shown.
Binary file not shown.

scalariform.update/target/site/site.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<site>
33
<description name="Scalariform Update Site"
4-
url="https://github.com/scala-ide/scalariform/tree/0.2.4/scalariform.update/target/site">
4+
url="https://github.com/scala-ide/scalariform/tree/0.2.5/scalariform.update/target/site">
55
Scalariform Update Site
66
</description>
7-
<feature url="features/scalariform.feature_0.2.4.jar" version="0.2.4" id="scalariform.feature">
7+
<feature url="features/scalariform.feature_0.2.5.jar" version="0.2.5" id="scalariform.feature">
88
<category name="Scala"/>
99
</feature>
1010
<category-def name="Scala" label="Scala"/>
4.35 KB
Binary file not shown.

scalariform/META-INF/MANIFEST.MF

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: Scalariform
44
Bundle-SymbolicName: scalariform
5-
Bundle-Version: 0.2.4
5+
Bundle-Version: 0.2.5
66
Require-Bundle: org.scala-lang.scala-library,
77
org.scala-lang.modules.scala-xml
88
Bundle-ClassPath: .

scalariform/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<parent>
99
<artifactId>scalariform.parent</artifactId>
1010
<groupId>org.scalariform</groupId>
11-
<version>0.2.4</version>
11+
<version>0.2.5</version>
1212
</parent>
1313
<dependencies>
1414
</dependencies>

scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala

+43-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
1818

1919
var formatResult: FormatResult = NoFormatResult
2020
var isFirstCaseClause = true
21+
val hasSingleCaseClause = clauseGroups.size == 1
2122

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

3637
def formatSingleCaseClause(caseClause: CaseClause) {
3738
handleCaseIndent(caseClause)
38-
formatResult ++= formatCaseClause(caseClause)
39+
formatResult ++= formatCaseClause(caseClause, None, hasSingleCaseClause)
3940
isFirstCaseClause = false
4041
}
4142

@@ -46,7 +47,9 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
4647
for (caseClause @ CaseClause(casePattern, statSeq) caseClauses) {
4748
handleCaseIndent(caseClause)
4849
val arrowInstruction = PlaceAtColumn(formatterState.indentLevel, largestCasePatternLength + 1)
49-
formatResult ++= formatCaseClause(caseClause, Some(arrowInstruction))
50+
formatResult ++= formatCaseClause(
51+
caseClause, Some(arrowInstruction), hasSingleCaseClause
52+
)
5053
isFirstCaseClause = false
5154
}
5255
} else {
@@ -104,22 +107,55 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
104107
formatResult
105108
}
106109

107-
private def formatCaseClause(caseClause: CaseClause, arrowInstructionOpt: Option[PlaceAtColumn] = None)(implicit formatterState: FormatterState): FormatResult = {
110+
private def formatCaseClause(
111+
caseClause: CaseClause,
112+
arrowInstructionOpt: Option[PlaceAtColumn],
113+
hasSingleCaseClause: Boolean
114+
)(implicit formatterState: FormatterState): FormatResult = {
115+
108116
val CaseClause(casePattern, statSeq) = caseClause
109117
var formatResult: FormatResult = NoFormatResult
110118
formatResult ++= formatCasePattern(casePattern, arrowInstructionOpt)
119+
val hasNewline = caseClause.casePattern.caseToken.associatedWhitespaceAndComments.containsNewline
120+
val singleCaseWithoutNewline = (
121+
hasSingleCaseClause && !hasNewline && !formattingPreferences(SingleCasePatternOnNewline)
122+
)
111123
val singleExpr =
112124
cond(statSeq.firstStatOpt) { case Some(Expr(_)) true } &&
113125
cond(statSeq.otherStats) { case Nil | List((_, None)) true }
114126
val indentBlock =
115127
statSeq.firstTokenOption.isDefined && newlineBefore(statSeq) ||
116128
containsNewline(statSeq) && !singleExpr
117-
if (indentBlock)
118-
formatResult = formatResult.before(statSeq.firstToken, formatterState.nextIndentLevelInstruction)
119129

120-
val stateForStatSeq = if (singleExpr && !indentBlock) formatterState else formatterState.indent
121-
formatResult ++= format(statSeq)(stateForStatSeq)
130+
def unindent(x: Map[Token, IntertokenFormatInstruction]) = x.map {
131+
case (k, v @ EnsureNewlineAndIndent(indentLevel, relativeTo)) =>
132+
k -> EnsureNewlineAndIndent(indentLevel - 1, relativeTo)
133+
case x => x
134+
}
135+
136+
if (indentBlock) {
137+
val result = formatResult.before(statSeq.firstToken, formatterState.nextIndentLevelInstruction)
138+
formatResult =
139+
if(!singleCaseWithoutNewline) result
140+
else
141+
result.copy(
142+
predecessorFormatting =
143+
unindent(result.predecessorFormatting) + ( // unindent first token in case body
144+
caseClause.casePattern.caseToken -> CompactEnsuringGap // remove `case` leading newline
145+
)
146+
)
147+
}
122148

149+
val stateForStatSeq = if (singleExpr && !indentBlock) formatterState else formatterState.indent
150+
formatResult ++= {
151+
val result = format(statSeq)(stateForStatSeq)
152+
if(!singleCaseWithoutNewline) result
153+
else
154+
result.copy( // unindent body tokens
155+
predecessorFormatting = unindent(result.predecessorFormatting),
156+
inferredNewlineFormatting = unindent(result.inferredNewlineFormatting)
157+
)
158+
}
123159
formatResult
124160
}
125161

scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala

+32-22
Original file line numberDiff line numberDiff line change
@@ -91,26 +91,6 @@ abstract class ScalaFormatter
9191
var suspendFormatting = false
9292
var edits: List[TextEdit] = Nil // Stored in reverse
9393

94-
def printableFormattingInstruction(previousTokenOption: Option[Token], token: Token, nextTokenOption: Option[Token]) = {
95-
val maybePredecessorFormatting = predecessorFormatting.get(token)
96-
val isGaplessAssignment =
97-
// avoid `foreach(_.id= ..)` and `foreach(foo= _)` gapless assignment (see MutateTest.scala)
98-
maybePredecessorFormatting exists {
99-
case x @ PlaceAtColumn(_, _, Some(Token(USCORE, _, _, _))) => token.tokenType == EQUALS
100-
case _ => token.tokenType == EQUALS && nextTokenOption.exists(_.tokenType == USCORE)
101-
}
102-
val maybeInstruction =
103-
if (isGaplessAssignment) Some(CompactEnsuringGap)
104-
else
105-
maybePredecessorFormatting.orElse(
106-
previousTokenOption.map(defaultFormattingInstruction(_, token))
107-
)
108-
maybeInstruction.getOrElse(
109-
if (token.tokenType == EOF) EnsureNewlineAndIndent(0) /* <-- to allow formatting of files with just a scaladoc comment */
110-
else Compact
111-
)
112-
}
113-
11494
for ((previousTokenOption, token, nextTokenOption) Utils.withPreviousAndNext(tokens)) {
11595
val previousTokenIsPrintable = previousTokenOption exists { !isInferredNewline(_) }
11696
if (isInferredNewline(token)) {
@@ -130,7 +110,9 @@ abstract class ScalaFormatter
130110
basicFormattingInstruction
131111
val nextTokenUnindents = nextTokenOption exists { _.tokenType == RBRACE }
132112
val includeBufferBeforeNextToken = nextTokenOption exists { nextToken
133-
!printableFormattingInstruction(Some(token), nextToken, None).isInstanceOf[EnsureNewlineAndIndent]
113+
!printableFormattingInstruction(
114+
Some(token), nextToken, None, predecessorFormatting
115+
).isInstanceOf[EnsureNewlineAndIndent]
134116
}
135117
edits :::= writeHiddenTokens(builder, inferredNewlines(token), formattingInstruction, nextTokenUnindents,
136118
includeBufferBeforeNextToken, previousTokenIsPrintable, tokenIndentMap).toList
@@ -142,7 +124,10 @@ abstract class ScalaFormatter
142124
tokenIndentMap += (token -> builder.currentColumn)
143125
builder.append(token.rawText)
144126
} else {
145-
val formattingInstruction = printableFormattingInstruction(previousTokenOption, token, nextTokenOption)
127+
val formattingInstruction =
128+
printableFormattingInstruction(
129+
previousTokenOption, token, nextTokenOption, predecessorFormatting
130+
)
146131
val nextTokenUnindents = token.tokenType == RBRACE
147132
val includeBufferBeforeNextToken = true // <-- i.e. current token
148133
val hiddenTokens = hiddenPredecessors(token)
@@ -444,6 +429,31 @@ abstract class ScalaFormatter
444429
result
445430
}
446431

432+
private def printableFormattingInstruction(
433+
previousTokenOption: Option[Token],
434+
token: Token,
435+
nextTokenOption: Option[Token],
436+
predecessorFormatting: Map[Token, IntertokenFormatInstruction]): IntertokenFormatInstruction = {
437+
438+
val maybePredecessorFormatting = predecessorFormatting.get(token)
439+
val isGaplessAssignment =
440+
maybePredecessorFormatting match {
441+
// `foreach(_.id= ..)`
442+
case x @ Some(PlaceAtColumn(_, _, Some(Token(USCORE, _, _, _)))) => token.tokenType == EQUALS
443+
// `foreach(foo= _)`
444+
case _ => token.tokenType == EQUALS && nextTokenOption.exists(_.tokenType == USCORE)
445+
}
446+
val maybeInstruction =
447+
if(isGaplessAssignment) Some(CompactEnsuringGap)
448+
else maybePredecessorFormatting.orElse(
449+
previousTokenOption.map(defaultFormattingInstruction(_, token))
450+
)
451+
maybeInstruction.getOrElse(
452+
if (token.tokenType == EOF) EnsureNewlineAndIndent(0) /* <-- to allow formatting of files with just a scaladoc comment */
453+
else Compact
454+
)
455+
}
456+
447457
private def defaultFormattingInstruction(token1: Token, token2: Token): IntertokenFormatInstruction = {
448458
val result = actualDefaultFormattingInstruction(token1, token2)
449459
// println("defaultFormattingInstruction(" + token1 + ", " + token2 + ") = " + result)

scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala

+10-3
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ object AllPreferences {
9393
AlignArguments, AlignParameters, AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent,
9494
AllowParamGroupsOnNewlines, CompactControlReadability, CompactStringConcatenation, DanglingCloseParenthesis,
9595
DoubleIndentClassDeclaration, DoubleIndentConstructorArguments, DoubleIndentMethodDeclaration, FirstArgumentOnNewline,
96-
FirstParameterOnNewline, FormatXml, IndentLocalDefs, IndentPackageBlocks, IndentSpaces, IndentWithTabs, MultilineScaladocCommentsStartOnFirstLine,
97-
NewlineAtEndOfFile, PlaceScaladocAsterisksBeneathSecondAsterisk, PreserveSpaceBeforeArguments, RewriteArrowSymbols,
98-
SpaceBeforeColon, SpaceBeforeContextColon, SpaceInsideBrackets, SpaceInsideParentheses, SpacesAroundMultiImports, SpacesWithinPatternBinders
96+
FirstParameterOnNewline, FormatXml, IndentLocalDefs, IndentPackageBlocks, IndentSpaces, IndentWithTabs,
97+
MultilineScaladocCommentsStartOnFirstLine, NewlineAtEndOfFile, PlaceScaladocAsterisksBeneathSecondAsterisk,
98+
PreserveSpaceBeforeArguments, RewriteArrowSymbols, SingleCasePatternOnNewline, SpaceBeforeColon,
99+
SpaceBeforeContextColon, SpaceInsideBrackets, SpaceInsideParentheses, SpacesAroundMultiImports, SpacesWithinPatternBinders
99100
)
100101

101102
val preferencesByKey: Map[String, PreferenceDescriptor[_]] =
@@ -245,6 +246,12 @@ case object RewriteArrowSymbols extends BooleanPreferenceDescriptor {
245246
val defaultValue = false
246247
}
247248

249+
case object SingleCasePatternOnNewline extends BooleanPreferenceDescriptor {
250+
val key = "singleCasePatternOnNewline"
251+
val description = "Single case in pattern match block on a new line"
252+
val defaultValue = true
253+
}
254+
248255
case object SpaceBeforeColon extends BooleanPreferenceDescriptor {
249256
val key = "spaceBeforeColon"
250257
val description = "Space before colons"

scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala

+42
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,48 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
8484
| d
8585
|}"""
8686

87+
{
88+
implicit val formattingPreferences = FormattingPreferences.setPreference(
89+
SingleCasePatternOnNewline, false
90+
)
91+
"""a match { case a => b; c;
92+
|d }""" ==>
93+
"""a match { case a =>
94+
| b; c;
95+
| d
96+
|}"""
97+
98+
"""a match { case b =>
99+
|val c = d
100+
|case e =>
101+
|}""" ==>
102+
"""a match {
103+
| case b =>
104+
| val c = d
105+
| case e =>
106+
|}"""
107+
108+
"""list.foreach { case (key, value) =>
109+
|val boo = 1
110+
|boo
111+
|}""" ==>
112+
"""list.foreach { case (key, value) =>
113+
| val boo = 1
114+
| boo
115+
|}"""
116+
117+
"""list.foreach {
118+
|case (key, value) =>
119+
|val boo = 1
120+
|boo
121+
|}""" ==>
122+
"""list.foreach {
123+
| case (key, value) =>
124+
| val boo = 1
125+
| boo
126+
|}"""
127+
}
128+
87129
"a match { case b => ; c }" ==> "a match { case b => ; c }"
88130

89131
// See issue #60

version.sbt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version in ThisBuild := "0.2.5-SNAPSHOT"
1+
version in ThisBuild := "0.2.5"

0 commit comments

Comments
 (0)