diff --git a/CHANGELOG b/CHANGELOG
index 3913a1ff..805f6ca8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,16 @@
+0.1.5 (..)
+* FIX: Type formatter crash on multiline types
+* Track scalac parser -- allow trait-position parents to have parameter blocks
+* Sync changes to InferredSemicolonParser
+
+0.1.4 (24/April/13)
+* FIX: Allow declarations as last statement in case block (issue #60)
+* Update to build 2.10 final
+
0.1.3 (3/October/12)
* Add EOF to ComplilationUnit, ensuring entire source is represented in the tree
* Support $this references in String interpolation
* Update build to sbt 0.12.1
-* FIX: Allow declarations as last statement in case block (issue #60).
0.1.2 (7/May/12)
diff --git a/README.rst b/README.rst
old mode 100644
new mode 100755
index 5fbc3945..0246c4cd
--- a/README.rst
+++ b/README.rst
@@ -28,6 +28,31 @@ You can also configure formatting to be run as a save action (Window -> Preferen
To set preferences, go to Window -> Preferences -> Scala -> Formatter
+Integration with IntelliJ
+-------------------------
+
+IntelliJ already has a built-in Scala code formatter (C-L).
+I use the original settings plus `Wraping and Braces` -> `Align columns in case branches`.
+In order to achieve exactly the same formatting use the following options::
+
+
+ def formattingPreferences = {
+ import scalariform.formatter.preferences._
+ FormattingPreferences()
+ .setPreference(AlignParameters, true)
+ .setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 120)
+ .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true) // IntelliJ compatible
+ .setPreference(CompactControlReadability, false)
+ .setPreference(NoSpacesAroundMultiImports, true)
+ .setPreference(FormatXml, false)
+ .setPreference(PreserveSpaceBeforeArguments, true)
+ .setPreference(IndentWithTabs, false)
+ .setPreference(SpacesWithinPatternBinders, false) // IntelliJ compatible
+ }
+
+
Integration with Emacs/ENSIME
-----------------------------
@@ -59,7 +84,7 @@ Usage::
org.scalariform
scalariform-maven-plugin
- 0.1.3
+ 0.1.4
process-sources
@@ -103,7 +128,7 @@ the following to ``.vimrc`` ::
The executable scalariform.jar can be downloaded from:
- https://github.com/downloads/mdr/scalariform/scalariform.jar
+ https://s3.amazonaws.com/scalariform/scalariform.jar
Command line tool
-----------------
@@ -474,6 +499,22 @@ If ``false``,::
case elem@Multi(values@_*) =>
+chainedPackageClauses
+~~~~~~~~~~~~~~~~~~~~~
+
+Default: ``false``
+
+Example::
+```
+ package com.company.analytics.math.curves.interpolators
+```
+
+Will be reformatted to::
+```
+ package com.company.analytics.math
+ package curves
+ package interpolators
+```
Scala Style Guide
~~~~~~~~~~~~~~~~~
diff --git a/cli/.classpath b/cli/.classpath
index 9b3704ea..e92a111b 100644
--- a/cli/.classpath
+++ b/cli/.classpath
@@ -1,12 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cli/src/main/scala/scalariform/commandline/Main.scala b/cli/src/main/scala/scalariform/commandline/Main.scala
index a549d067..3cd343b6 100644
--- a/cli/src/main/scala/scalariform/commandline/Main.scala
+++ b/cli/src/main/scala/scalariform/commandline/Main.scala
@@ -254,26 +254,11 @@ object Main {
private def transformFilesInPlace(files: Seq[File], encoding: String, doFormat: String ⇒ Option[String], log: String ⇒ Unit): Boolean = {
var problems = false
- // val futures =
- // for (file ← files) yield asyncExec {
- // problems &= transformFileInPlace(file, encoding, doFormat, log)
- // }
- // futures.map(_.get())
for (file ← files)
problems &= transformFileInPlace(file, encoding, doFormat, log)
problems
}
- // private val lock = new ReentrantLock
- // private lazy val executorService = Executors.newCachedThreadPool()
- // private def asyncExec(x: ⇒ Unit): Future[_] = executorService.submit(new Runnable { def run() = x })
- // private def withLock[T](x: ⇒ T): T = {
- // lock.lock()
- // try
- // x
- // finally
- // lock.unlock()
- // }
/**
* @return true iff file is already formatted correctly
*/
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 63da561a..c08bd721 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -45,9 +45,9 @@
# built documents.
#
# The short X.Y version.
-version = '0.1.4-SNAPSHOT'
+version = '0.1.5-SNAPSHOT'
# The full version, including alpha/beta/rc tags.
-release = '0.1.4-SNAPSHOT'
+release = '0.1.5-SNAPSHOT'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/misc/.classpath b/misc/.classpath
index 3f447726..c89ac363 100644
--- a/misc/.classpath
+++ b/misc/.classpath
@@ -1,14 +1,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala b/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala
index 2d127a92..143b3deb 100644
--- a/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala
+++ b/misc/src/main/scala/scalariform/corpusscan/CorpusScanner.scala
@@ -1,16 +1,17 @@
package scalariform.corpusscan
-import scalariform.lexer.{ Token ⇒ _, _ }
-import scalariform.formatter._
-import scalariform.formatter.preferences._
-import scalariform.parser._
-import scala.util.parsing.input._
-import scala.util.parsing.combinator._
import java.io.File
+
import scala.io.Source
-import scalariform.utils.Utils.writeText
+
import org.apache.commons.io.FileUtils
+
import scalariform.commandline.ScalaFileWalker
+import scalariform.formatter._
+import scalariform.formatter.preferences.FormattingPreferences
+import scalariform.lexer._
+import scalariform.parser._
+import scalariform.utils.Utils.writeText
sealed trait ParseFault
case object TokensDoNotCoverSource extends ParseFault
@@ -31,9 +32,9 @@ object CorpusScanner extends SpecificFormatter {
val tokens = ScalaLexer.tokenise(source)
try {
val result = new ScalaParser(tokens.toArray).compilationUnitOrScript()
- if (result.tokens != tokens.init) /* drop EOF */
+ if (result.tokens != tokens) {
Some(BadAstTokens)
- else
+ } else
None
} catch {
case e: ScalaParserException ⇒ Some(UnsuccessfulParse)
@@ -66,9 +67,9 @@ object CorpusScanner extends SpecificFormatter {
}
-object Runner {
+object Runner extends App {
- val corpusDir = "/home/matt/coding/scala-corpus"
+ val corpusDir = "/home/matthew/coding/scala-corpus/repos2"
// val corpusDir = "/home/matt/scala-corpus"
def checkParser() {
@@ -93,14 +94,14 @@ object Runner {
for (file ← ScalaFileWalker.findScalaFiles(corpusDir)) {
print("Formatting: " + file)
CorpusScanner.formatFile(file)
- val parsed = CorpusScanner.attemptToParse(file)
- require(parsed == None, parsed.toString)
+ val parseFaultOpt = CorpusScanner.attemptToParse(file)
+ require(parseFaultOpt == None, parseFaultOpt.toString)
println()
count += 1
}
println(count + " files formatted.")
}
- def main(args: Array[String]) = formatInPlace()
+ formatInPlace()
}
diff --git a/misc/src/main/scala/scalariform/gui/FormatterFrame.scala b/misc/src/main/scala/scalariform/gui/FormatterFrame.scala
index edafd1be..f12d1c27 100644
--- a/misc/src/main/scala/scalariform/gui/FormatterFrame.scala
+++ b/misc/src/main/scala/scalariform/gui/FormatterFrame.scala
@@ -21,6 +21,10 @@ import scalariform.formatter._
import scalariform.formatter.preferences._
import scalariform.lexer._
import scalariform.lexer.Tokens._
+import scalariform.gui.SwingUtils._
+import scalariform.parser._
+import scala.util.parsing.input._
+import scala.util.parsing.combinator._
class FormatterFrame extends JFrame with SpecificFormatter {
@@ -101,10 +105,9 @@ class FormatterFrame extends JFrame with SpecificFormatter {
val textFont = new Font("monospaced", Font.PLAIN, 14)
val astTree = new JTree
- val tokensTable = new JTable
- tokensTable.setCellSelectionEnabled(false)
- tokensTable.setRowSelectionAllowed(true)
- tokensTable.setColumnSelectionAllowed(false)
+
+ val tokensTable = new TokenTable
+ val rawTokensTable = new TokenTable
val outputTextPane = new JTextPane
setFont(outputTextPane, textFont)
@@ -155,8 +158,10 @@ class FormatterFrame extends JFrame with SpecificFormatter {
case e: RuntimeException ⇒
if (showAstCheckBox.isSelected) {
val tokens = ScalaLexer.tokenise(inputText, scalaVersion = SCALA_VERSION)
+ val rawTokens = ScalaLexer.rawTokenise(inputText, scalaVersion = SCALA_VERSION)
val tableModel = new TokenTableModel(tokens, FormatResult(Map(), Map(), Map()))
- tokensTable.setModel(tableModel)
+ tokensTable.setTokens(tokens)
+ rawTokensTable.setTokens(rawTokens)
try {
val parseResult = specificFormatter.parse(new ScalaParser(tokens.toArray))
val treeModel = new ParseTreeModel(parseResult)
@@ -168,21 +173,19 @@ class FormatterFrame extends JFrame with SpecificFormatter {
}
val duration = System.currentTimeMillis - startTime
val tokens = ScalaLexer.tokenise(inputText, scalaVersion = SCALA_VERSION)
+ val rawTokens = ScalaLexer.rawTokenise(inputText, scalaVersion = SCALA_VERSION)
val tokenCount = tokens.size
setTitle("Scalariform " + scalariform.BuildInfo.version + " -- " + duration + "ms, " + tokenCount + " tokens, speed = " + (1000 * tokenCount / (duration + 1)) + " tokens/second")
outputTextPane.setText(outputText)
if (showAstCheckBox.isSelected) {
- import scalariform.parser._
- import scala.util.parsing.input._
- import scala.util.parsing.combinator._
val parseResult =
try
specificFormatter.parse(new ScalaParser(tokens.toArray))
catch {
case e: RuntimeException ⇒
- val tableModel = new TokenTableModel(tokens, FormatResult(Map(), Map(), Map()))
- tokensTable.setModel(tableModel)
+ tokensTable.setTokens(tokens)
+ rawTokensTable.setTokens(rawTokens)
throw e
}
val treeModel = new ParseTreeModel(parseResult)
@@ -191,12 +194,12 @@ class FormatterFrame extends JFrame with SpecificFormatter {
val (outputText, formatResult) = specificFormatter.fullFormat(inputText, scalaVersion = SCALA_VERSION)(OptionsPanel.getFormattingPreferences)
- val tableModel = new TokenTableModel(tokens, formatResult)
- tokensTable.setModel(tableModel)
+ tokensTable.setTokens(tokens, formatResult)
+ rawTokensTable.setTokens(rawTokens)
}
} catch {
- case e ⇒
- outputTextPane.setText(e.toString + "\n" + e.getStackTrace.mkString("\n"))
+ case t: Throwable ⇒
+ outputTextPane.setText(t.toString + "\n" + t.getStackTrace.mkString("\n"))
outputTextPane.setCaretPosition(0)
}
@@ -211,6 +214,7 @@ class FormatterFrame extends JFrame with SpecificFormatter {
resultTabbedPane.addTab("Output", new JScrollPane(outputTextPane))
resultTabbedPane.addTab("AST", new JScrollPane(astTree))
resultTabbedPane.addTab("Tokens", new JScrollPane(tokensTable))
+ resultTabbedPane.addTab("Raw Tokens", new JScrollPane(rawTokensTable))
val splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT)
splitPane.setTopComponent(new JScrollPane(inputTextPane))
@@ -304,26 +308,36 @@ class FormatterFrame extends JFrame with SpecificFormatter {
val parseTreeModel = astTree.getModel.asInstanceOf[ParseTreeModel]
for {
lastComponent ← Option(astTree.getLastSelectedPathComponent)
- (from, to) ← parseTreeModel.getDocumentRange(lastComponent)
+ range ← parseTreeModel.getDocumentRange(lastComponent)
} {
- inputTextPane.setSelectionStart(from)
- inputTextPane.setSelectionEnd(to + 1)
+ inputTextPane.setSelectionStart(range.offset)
+ inputTextPane.setSelectionEnd(range.offset + range.length)
+ inputTextPane.requestFocusInWindow()
+ astTree.requestFocusInWindow()
}
}
})
- tokensTable.getSelectionModel.addListSelectionListener(new ListSelectionListener() {
- def valueChanged(e: ListSelectionEvent) {
- val tableModel = tokensTable.getModel.asInstanceOf[TokenTableModel]
- val selectionIndex = e.getFirstIndex
- if (selectionIndex >= 0) {
- val (from, to) = tableModel.getDocumentRange(selectionIndex)
- inputTextPane.setSelectionStart(from)
- inputTextPane.setSelectionEnd(to + 1)
- }
+ tokensTable.getSelectionModel.addListSelectionListener { e: ListSelectionEvent ⇒
+ for (token ← tokensTable.getSelectedToken) {
+ val range = token.range
+ inputTextPane.setSelectionStart(range.offset)
+ inputTextPane.setSelectionEnd(range.offset + range.length)
+ inputTextPane.requestFocusInWindow()
+ tokensTable.requestFocusInWindow()
}
- })
+ }
+
+ rawTokensTable.getSelectionModel.addListSelectionListener { e: ListSelectionEvent ⇒
+ for (token ← rawTokensTable.getSelectedToken) {
+ val range = token.range
+ inputTextPane.setSelectionStart(range.offset)
+ inputTextPane.setSelectionEnd(range.offset + range.length)
+ inputTextPane.requestFocusInWindow()
+ rawTokensTable.requestFocusInWindow()
+ }
+ }
{
val menuBar = new JMenuBar
@@ -350,13 +364,13 @@ class FormatterFrame extends JFrame with SpecificFormatter {
}
def specificFormatter: SpecificFormatter =
- productionComboBox.getSelectedItem.asInstanceOf[ProductionComboBoxModel.ProductionItem].formatter
+ productionComboBox.getSelectedItem.asInstanceOf[ProductionItem].formatter
- object ProductionComboBoxModel extends DefaultComboBoxModel {
+ class ProductionItem(name: String, val formatter: SpecificFormatter) {
+ override def toString = name
+ }
- class ProductionItem(name: String, val formatter: SpecificFormatter) {
- override def toString = name
- }
+ object ProductionComboBoxModel extends DefaultComboBoxModel[ProductionItem] {
val compilationUnitFormatter = new SpecificFormatter {
@@ -412,31 +426,4 @@ object Samples {
|}""".stripMargin
} // format: ON
-class TokenTableModel(tokens: List[Token], formatResult: FormatResult) extends AbstractTableModel {
- def getColumnCount = 5
- def getRowCount = tokens.size
- def getValueAt(row: Int, col: Int): AnyRef = {
- val token = tokens(row)
- col match {
- case 0 ⇒ token.tokenType
- case 1 ⇒ token.text
- case 2 ⇒ token.offset.asInstanceOf[java.lang.Integer]
- case 3 ⇒ token.lastCharacterOffset.asInstanceOf[java.lang.Integer]
- case 4 ⇒ {
- formatResult.predecessorFormatting.get(token) orElse formatResult.inferredNewlineFormatting.get(token) getOrElse ""
- }
- }
- }
- override def getColumnName(col: Int) = col match {
- case 0 ⇒ "Type"
- case 1 ⇒ "Token text"
- case 2 ⇒ "Start"
- case 3 ⇒ "Finish"
- case 4 ⇒ "Instruction"
- }
- def getDocumentRange(index: Int): (Int, Int) = {
- val token = tokens(index)
- (token.offset, token.lastCharacterOffset)
- }
-}
diff --git a/misc/src/main/scala/scalariform/gui/Main.scala b/misc/src/main/scala/scalariform/gui/Main.scala
index 7f6d360f..35599e9c 100644
--- a/misc/src/main/scala/scalariform/gui/Main.scala
+++ b/misc/src/main/scala/scalariform/gui/Main.scala
@@ -3,15 +3,13 @@ package scalariform.gui
import scalariform.utils.Utils._
import javax.swing.JFrame
-object Main {
+object Main extends App {
- def main(args: Array[String]) {
- onSwingThread {
- val frame = new FormatterFrame
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
- frame.setSize(1280, 600)
- frame.setVisible(true)
- }
+ onSwingThread {
+ val frame = new FormatterFrame
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
+ frame.setSize(1280, 600)
+ frame.setVisible(true)
}
}
diff --git a/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala b/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala
index 224f1fc9..edc26d7d 100644
--- a/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala
+++ b/misc/src/main/scala/scalariform/gui/ParseTreeModel.scala
@@ -1,85 +1,90 @@
package scalariform.gui
-import java.awt.event._
-import net.miginfocom.layout._
-import net.miginfocom.swing._
-import javax.swing._
-import javax.swing.text._
-import java.awt.event._
-import java.awt.{ List ⇒ _, _ }
-
-import javax.swing._
-import javax.swing.event._
-import javax.swing.text._
+import javax.swing.event.TreeModelListener
import javax.swing.tree._
-
-import javax.swing.{ JMenu, JMenuItem, JMenuBar }
-
-import scalariform.utils.Utils._
-import scalariform.parser._
-import scalariform.formatter._
-import scalariform.lexer._
-import scalariform.lexer.Tokens._
+import scalariform.lexer.Token
+import scalariform.parser.AstNode
+import scalariform.utils.Range
class ParseTreeModel(rootAstNode: AstNode) extends TreeModel {
- def getDocumentRange(obj: AnyRef): Option[(Int, Int)] = obj.asInstanceOf[TreeNode].range
+ def getDocumentRange(obj: AnyRef): Option[Range] = obj.asInstanceOf[TreeNode].range
abstract sealed class TreeNode(name: String) {
+
def children: List[TreeNode]
- override def toString = name
- lazy val range: Option[(Int, Int)] = {
- val childRanges = children flatMap { _.range }
- for {
- firstRange ← childRanges.headOption
- lastRange ← childRanges.lastOption
- } yield (firstRange._1, lastRange._2)
+
+ lazy val range: Option[Range] = {
+ val childRanges = children.flatMap(_.range)
+ if (childRanges.isEmpty)
+ None
+ else
+ Some(childRanges.reduceLeft(_ mergeWith _))
}
+ override def toString = name
+
}
case class AstNodeNode(name: String, astNode: AstNode) extends TreeNode(name) {
+
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))
}
+
override def toString = {
val typeName = astNode.getClass.getSimpleName
(if (name != "") name + ": " else "") + typeName
}
+
}
case class TokenNode(name: String, token: Token) extends TreeNode(name) {
+
val children = Nil
+
+ override lazy val range = Some(token.range)
+
override def toString = name + ": " + token
- override lazy val range = Some(token.offset, token.lastCharacterOffset)
}
case class ListNode(name: String, list: List[Any]) extends TreeNode(name) {
- lazy val children = list map { x ⇒ makeTreeNode(x) }
+
+ lazy val children = list.zipWithIndex map { case (x, i) ⇒ makeTreeNode(x, i.toString) }
+
}
case class OptionNode(name: String, opt: Option[Any]) extends TreeNode(name) {
- lazy val children = opt map { x ⇒ makeTreeNode(x) } toList
+
+ lazy val children = opt map { x ⇒ makeTreeNode(x, "Some") } toList
+
}
case class EitherNode(name: String, either: Either[Any, Any]) extends TreeNode(name) {
+
lazy val children = either match {
- case Left(obj) ⇒ List(makeTreeNode(obj))
- case Right(obj) ⇒ List(makeTreeNode(obj))
+ case Left(obj) ⇒ List(makeTreeNode(obj, "Left"))
+ case Right(obj) ⇒ List(makeTreeNode(obj, "Right"))
}
}
case class PairNode(name: String, pair: (Any, Any)) extends TreeNode(name) {
- lazy val children = List(makeTreeNode(pair._1), makeTreeNode(pair._2))
+
+ lazy val children = List(makeTreeNode(pair._1, "_1"), makeTreeNode(pair._2, "_2"))
+
}
case class TodoNode(name: String, obj: Any) extends TreeNode(name) {
+
val children = Nil
+
override def toString = name + ": " + obj
+
}
def makeTreeNode(obj: Any, name: String = ""): TreeNode = obj match {
@@ -89,8 +94,10 @@ class ParseTreeModel(rootAstNode: AstNode) extends TreeModel {
TokenNode(name, token)
case list: List[_] ⇒
ListNode(name, list)
- case option: Option[_] ⇒
- OptionNode(name, option)
+ case Some(x) ⇒
+ makeTreeNode(x, name)
+ case None ⇒
+ OptionNode(name, None)
case either: Either[_, _] ⇒
EitherNode(name, either)
case pair: (_, _) ⇒
@@ -103,8 +110,6 @@ class ParseTreeModel(rootAstNode: AstNode) extends TreeModel {
def getChildCount(obj: AnyRef) = getChildren(obj).length
- private def getChildren(obj: AnyRef) = obj.asInstanceOf[TreeNode].children
-
def getChild(parent: AnyRef, index: Int): AnyRef = getChildren(parent)(index)
def getIndexOfChild(parent: AnyRef, child: AnyRef) = getChildren(parent).indexOf(child)
@@ -112,8 +117,12 @@ class ParseTreeModel(rootAstNode: AstNode) extends TreeModel {
def isLeaf(obj: AnyRef): Boolean = getChildCount(obj) == 0
def addTreeModelListener(l: TreeModelListener) {}
+
def removeTreeModelListener(l: TreeModelListener) {}
+
def valueForPathChanged(path: TreePath, newValue: Any) {}
+ private def getChildren(obj: AnyRef) = obj.asInstanceOf[TreeNode].children
+
}
diff --git a/misc/src/main/scala/scalariform/gui/SwingUtils.scala b/misc/src/main/scala/scalariform/gui/SwingUtils.scala
new file mode 100644
index 00000000..7b5180d2
--- /dev/null
+++ b/misc/src/main/scala/scalariform/gui/SwingUtils.scala
@@ -0,0 +1,13 @@
+package scalariform.gui
+
+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/misc/src/main/scala/scalariform/gui/TokenTable.scala b/misc/src/main/scala/scalariform/gui/TokenTable.scala
new file mode 100644
index 00000000..c71ef964
--- /dev/null
+++ b/misc/src/main/scala/scalariform/gui/TokenTable.scala
@@ -0,0 +1,55 @@
+package scalariform.gui
+
+import scalariform.formatter.FormatResult
+import javax.swing.JTable
+import scalariform.lexer.Token
+import javax.swing.table.AbstractTableModel
+import scalariform.utils.Range
+
+class TokenTable extends JTable(new TokenTableModel(Nil, FormatResult.EMPTY)) {
+
+ setCellSelectionEnabled(false)
+ setRowSelectionAllowed(true)
+ setColumnSelectionAllowed(false)
+
+ def setTokens(tokens: List[Token], formatResult: FormatResult = FormatResult.EMPTY) {
+ val tableModel = new TokenTableModel(tokens, formatResult)
+ setModel(tableModel)
+ }
+
+ override def getModel = super.getModel.asInstanceOf[TokenTableModel]
+
+ def getSelectedToken: Option[Token] =
+ getSelectedRow() match {
+ case -1 ⇒ None
+ case n ⇒ Some(getModel.tokens(n))
+ }
+
+}
+
+class TokenTableModel(val tokens: List[Token], formatResult: FormatResult) extends AbstractTableModel {
+
+ def getColumnCount = 5
+
+ def getRowCount = tokens.size
+
+ def getValueAt(row: Int, col: Int): AnyRef = {
+ val token = tokens(row)
+ col match {
+ case 0 ⇒ token.tokenType
+ case 1 ⇒ token.text
+ case 2 ⇒ token.offset.asInstanceOf[java.lang.Integer]
+ case 3 ⇒ token.lastCharacterOffset.asInstanceOf[java.lang.Integer]
+ case 4 ⇒ formatResult.predecessorFormatting.get(token) orElse formatResult.inferredNewlineFormatting.get(token) getOrElse ""
+ }
+ }
+
+ override def getColumnName(col: Int) = col match {
+ case 0 ⇒ "Type"
+ case 1 ⇒ "Token text"
+ case 2 ⇒ "Start"
+ case 3 ⇒ "Finish"
+ case 4 ⇒ "Instruction"
+ }
+
+}
\ No newline at end of file
diff --git a/notes/scala-sync.txt b/notes/scala-sync.txt
new file mode 100644
index 00000000..30a3f4f0
--- /dev/null
+++ b/notes/scala-sync.txt
@@ -0,0 +1,4 @@
+scalac changes checked 26/April/2013
+
+Scanners.scala: cdffcf8962c9fa606c027fcb5a50a4273976a576
+Parsers.scala: cd148d97225fc7738f7a8ff9d4479cd46d632371
diff --git a/pom.xml b/pom.xml
index 7bec643d..e990a1df 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
org.scalariform
scalariform.parent
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
pom
@@ -14,11 +14,20 @@
- 0.12.0
- 2.8.0
- http://download.scala-ide.org
+ 0.18.1
+ 2.10.2
UTF-8
+ 3.0.4
+ 2.11.0-M5
+ 1.0.0-RC5
+ 2_10
+
+
+ ${maven.version}
+
+
+
scalariform
scalariform.feature
@@ -49,15 +58,11 @@
-
- org.codehaus.mojo
- buildnumber-maven-plugin
- 1.1
-
org.codehaus.mojo
buildnumber-maven-plugin
+ 1.1
validate
@@ -78,14 +83,14 @@
tycho-packaging-plugin
${tycho.version}
- yyyyMMddHHmm'-${buildNumber}'
+ '${version.suffix}-'yyyyMMddHHmm'-${buildNumber}'
true
- org.scala-tools
- maven-scala-plugin
- 2.14
+ net.alchim31.maven
+ scala-maven-plugin
+ 3.1.5
@@ -106,9 +111,9 @@
- galileo
+ kepler
p2
- http://download.eclipse.org/releases/galileo
+ http://download.eclipse.org/releases/kepler
sonatype.release
@@ -126,71 +131,25 @@
-
- release-ide-29
-
-
- scala-toolchain-scalaide-2.0
- Scala Toolchain for Scala IDE 2.0 p2 repository
- p2
- http://download.scala-ide.org/incoming-release-29/dependencies/osgi-toolchain
-
-
-
-
- release-ide-210
-
-
- scala-toolchain-scalaide-2.1
- Scala Toolchain for Scala IDE 2.0 p2 repository
- p2
- http://download.scala-ide.org/incoming-release-210/dependencies/osgi-toolchain
-
-
-
-
- release-ide-211
-
-
- scala-toolchain-scalaide-2.1
- Scala Toolchain for Scala IDE 2.0 p2 repository
- p2
- http://download.scala-ide.org/incoming-release-211/dependencies/osgi-toolchain
-
-
-
-
- scala-2.9.x
-
-
- scala-toolchain-2.9.x
- Scala Toolchain 2.9.x p2 repository
- p2
- ${repo.scala-ide}/scala-eclipse-toolchain-osgi-29x
-
-
-
scala-2.10.x
-
-
- scala-toolchain-2.10.x
- Scala Toolchain trunk p2 repository
- p2
- ${repo.scala-ide}/scala-eclipse-toolchain-osgi-210x
-
-
+
+ 2_10
+
scala-2.11.x
-
-
- scala-toolchain-2.11.x
- Scala Toolchain trunk p2 repository
- p2
- ${repo.scala-ide}/scala-eclipse-toolchain-osgi-211x
-
-
+
+ 2.11.0-SNAPSHOT
+ 2_11
+
+
+
+ org.scala-lang.modules
+ scala-xml_${scala.binary.version}
+ ${scala.xml.version}
+
+
diff --git a/project/Build.scala b/project/Build.scala
index 8a13ddc9..b84ef8d1 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -3,22 +3,21 @@ import sbt.Keys._
import com.github.retronym.SbtOneJar
import com.typesafe.sbteclipse.core.EclipsePlugin.EclipseKeys._
import com.typesafe.sbteclipse.core.EclipsePlugin._
-import com.typesafe.sbtscalariform.ScalariformPlugin
-import com.typesafe.sbtscalariform.ScalariformPlugin.ScalariformKeys
+import com.typesafe.sbt.SbtScalariform
+import com.typesafe.sbt.SbtScalariform.ScalariformKeys
import scalariform.formatter.preferences._
object ScalariformBuild extends Build {
-
- lazy val commonSettings = Defaults.defaultSettings ++ ScalariformPlugin.defaultScalariformSettings ++ Seq(
+ lazy val commonSettings = Defaults.defaultSettings ++ SbtScalariform.defaultScalariformSettings ++ Seq(
organization := "org.scalariform",
- version := "0.1.4-SNAPSHOT",
- scalaVersion := "2.9.2",
+ version := "0.1.5-SNAPSHOT",
+ scalaVersion := "2.10.0",
crossScalaVersions := Seq(
- "2.10.0-M7",
- "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.11.0-M2",
+ "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"),
exportJars := true, // Needed for cli oneJar
retrieveManaged := true,
scalacOptions += "-deprecation",
@@ -36,9 +35,11 @@ object ScalariformBuild extends Build {
publishLocal := ())) aggregate (scalariform, cli, misc)
def getScalaTestDependency(scalaVersion: String) = scalaVersion match {
- case "2.8.0" ⇒ "org.scalatest" %% "scalatest" % "1.3.1.RC2" % "test"
- case "2.10.0-M7" ⇒ "org.scalatest" % "scalatest_2.10.0-M7" % "1.9-2.10.0-M7-B1" % "test"
- case _ ⇒ "org.scalatest" %% "scalatest" % "1.7.2" % "test"
+ 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"
}
lazy val scalariform: Project = Project("scalariform", file("scalariform"), settings =
diff --git a/project/build.properties b/project/build.properties
index 4474a03e..9b860e23 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=0.12.1
+sbt.version=0.12.3
diff --git a/project/plugins.sbt b/project/plugins.sbt
old mode 100644
new mode 100755
index 25bb8511..4a817d0f
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -4,15 +4,15 @@ addSbtPlugin("com.github.retronym" % "sbt-onejar" % "0.8")
resolvers += Classpaths.typesafeSnapshots
-addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0-SNAPSHOT")
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.2.0")
-addSbtPlugin("com.typesafe.sbtscalariform" % "sbtscalariform" % "0.5.1")
+addSbtPlugin("com.typesafe.sbt" % "sbt-scalariform" % "1.0.1")
-// resolvers += Resolver.url("sbt-plugin-releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)
+resolvers += Resolver.url("sbt-plugin-releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)
-addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.6")
+addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8")
-addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.2.0")
+addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.2.2")
retrieveManaged := true
diff --git a/project/project/plugins.sbt b/project/project/plugins.sbt
old mode 100644
new mode 100755
index 1baaef62..d0201e8a
--- a/project/project/plugins.sbt
+++ b/project/project/plugins.sbt
@@ -1,4 +1,3 @@
resolvers += Classpaths.typesafeSnapshots
-addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.0-SNAPSHOT")
-
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.1.2")
diff --git a/scalariform.feature/feature.xml b/scalariform.feature/feature.xml
index d056b45e..d10adaad 100644
--- a/scalariform.feature/feature.xml
+++ b/scalariform.feature/feature.xml
@@ -2,7 +2,7 @@
+ version="0.1.5.qualifier">
Code formatter for Scala 2.8
diff --git a/scalariform.feature/pom.xml b/scalariform.feature/pom.xml
index e3f1c6a5..6f78f8d9 100644
--- a/scalariform.feature/pom.xml
+++ b/scalariform.feature/pom.xml
@@ -5,11 +5,11 @@
4.0.0
scalariform.feature
eclipse-feature
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
scalariform.parent
org.scalariform
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
diff --git a/scalariform.update/pom.xml b/scalariform.update/pom.xml
index 190ed28c..8ed0b120 100644
--- a/scalariform.update/pom.xml
+++ b/scalariform.update/pom.xml
@@ -5,11 +5,11 @@
4.0.0
scalariform.update
eclipse-update-site
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
scalariform.parent
org.scalariform
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
diff --git a/scalariform.update/site.xml b/scalariform.update/site.xml
index dd8f0a1a..0f1492e9 100644
--- a/scalariform.update/site.xml
+++ b/scalariform.update/site.xml
@@ -3,7 +3,7 @@
Scalariform Update Site
-
+
diff --git a/scalariform/.classpath b/scalariform/.classpath
index 41ff9ff0..93d8e858 100644
--- a/scalariform/.classpath
+++ b/scalariform/.classpath
@@ -1,13 +1,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scalariform/.project b/scalariform/.project
index 369bc479..f848d8a7 100644
--- a/scalariform/.project
+++ b/scalariform/.project
@@ -1,35 +1,12 @@
-
- scalariform
- scalariform 0.1
-
-
-
-
- org.eclipse.pde.ManifestBuilder
-
-
-
-
- org.eclipse.pde.SchemaBuilder
-
-
-
-
- org.scala-ide.sdt.core.scalabuilder
-
-
-
-
- org.scalastyle.scalastyleplugin.core.ScalastyleBuilder
-
-
-
-
-
- org.scala-ide.sdt.core.scalanature
- org.eclipse.jdt.core.javanature
- org.eclipse.pde.PluginNature
- org.scalastyle.scalastyleplugin.core.ScalastyleNature
-
-
+ scalariform
+
+
+ org.scala-ide.sdt.core.scalabuilder
+
+
+
+ org.scala-ide.sdt.core.scalanature
+ org.eclipse.jdt.core.javanature
+
+
\ No newline at end of file
diff --git a/scalariform/META-INF/MANIFEST.MF b/scalariform/META-INF/MANIFEST.MF
index 7b688db4..fe283350 100644
--- a/scalariform/META-INF/MANIFEST.MF
+++ b/scalariform/META-INF/MANIFEST.MF
@@ -2,8 +2,9 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Scalariform
Bundle-SymbolicName: scalariform
-Bundle-Version: 0.1.4.qualifier
-Require-Bundle: org.scala-ide.scala.library
+Bundle-Version: 0.1.5.qualifier
+Require-Bundle: org.scala-lang.scala-library
+Import-Package: scala.xml.parsing
Bundle-ClassPath: .
Export-Package: scalariform,
scalariform.astselect,
diff --git a/scalariform/notes/0.1.4.markdown b/scalariform/notes/0.1.4.markdown
new file mode 100644
index 00000000..61370721
--- /dev/null
+++ b/scalariform/notes/0.1.4.markdown
@@ -0,0 +1,3 @@
+* FIX: Allow declarations as last statement in case block (issue #60)
+* Update to build 2.10 final
+
diff --git a/scalariform/pom.xml b/scalariform/pom.xml
index dfc3b2de..2381a734 100644
--- a/scalariform/pom.xml
+++ b/scalariform/pom.xml
@@ -4,20 +4,20 @@
4.0.0
org.scalariform
scalariform
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
eclipse-plugin
scalariform.parent
org.scalariform
- 0.1.4-SNAPSHOT
+ 0.1.5-SNAPSHOT
- org.sonatype.tycho
- maven-osgi-compiler-plugin
+ org.eclipse.tycho
+ tycho-compiler-plugin
${tycho.version}
diff --git a/scalariform/src/main/scala/scalariform/ScalaVersions.scala b/scalariform/src/main/scala/scalariform/ScalaVersions.scala
index 71c34cf0..3aedf44c 100644
--- a/scalariform/src/main/scala/scalariform/ScalaVersions.scala
+++ b/scalariform/src/main/scala/scalariform/ScalaVersions.scala
@@ -12,12 +12,12 @@ object ScalaVersion {
def parse(s: String): Option[ScalaVersion] =
s match {
- case VersionPattern(majorStr, minorStr, extra) =>
+ case VersionPattern(majorStr, minorStr, extra) ⇒
for {
- major <- majorStr.toIntOpt
- minor <- minorStr.toIntOpt
+ major ← majorStr.toIntOpt
+ minor ← minorStr.toIntOpt
} yield ScalaVersion(major, minor, extra)
- case _ =>
+ case _ ⇒
None
}
diff --git a/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
old mode 100644
new mode 100755
index 9255a4bc..fedb2ba8
--- a/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/CaseClauseFormatter.scala
@@ -1,6 +1,6 @@
package scalariform.formatter
-import scalariform.lexer.Token
+import scalariform.lexer.{TokenType, Token}
import scalariform.lexer.Tokens._
import scalariform.parser._
import scalariform.utils.Utils
@@ -81,16 +81,18 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
val newlineBeforeClause = hiddenPredecessors(caseClause.firstToken).containsNewline ||
previousCaseClauseEndsWithNewline(caseClause, caseClausesAstNode)
- // To evaluate whether a clause body is multiline, we ignore a trailing newline:
+ // To evaluate whether a clause body is multiline, we ignore a trailing newline:
val prunedStatSeq = pruneTrailingNewline(statSeq)
val clauseBodyIsMultiline = containsNewline(pruneTrailingNewline(statSeq)) ||
statSeq.firstTokenOption.exists(hiddenPredecessors(_).containsNewline)
- if (formattedCasePattern.contains('\n') || (first && !clausesAreMultiline) || (!first && !newlineBeforeClause) || clauseBodyIsMultiline)
+ if (first && !clausesAreMultiline || !first && !newlineBeforeClause ||
+ !formattingPreferences(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements) && clauseBodyIsMultiline)
Right(caseClause) :: otherClausesGrouped
else {
val arrowAdjust = (if (formattingPreferences(RewriteArrowSymbols)) 1 else casePattern.arrow.length) + 1
- val casePatternLength = formattedCasePattern.length - arrowAdjust
+ val casePatternLengthConsideringNewLines = formattedCasePattern.split('\n').last.length
+ val casePatternLength = casePatternLengthConsideringNewLines - arrowAdjust
otherClausesGrouped match {
case Left(consecutiveSingleLineCaseClauses) :: otherGroups ⇒
Left(consecutiveSingleLineCaseClauses.prepend(caseClause, casePatternLength)) :: otherGroups
@@ -99,7 +101,26 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
}
}
}
- groupClauses(caseClausesAstNode.caseClauses, first = true)
+
+ val caseClauses: List[CaseClause] = caseClausesAstNode.caseClauses
+
+ val ranges: List[(Int, Int)] = if (formattingPreferences(AlignSingleLineCaseStatements.GroupByNewLine)) {
+ val newLinesAt = (caseClauses.zipWithIndex.collect {
+ case (c, i) if c.tokens.exists(_.isNewlines) => i + 1
+ })
+
+ val newLinesWithBeginAndEnd = (if (newLinesAt.contains(0)) List() else List(0)) ++ newLinesAt ++ List(caseClauses.length)
+
+ newLinesWithBeginAndEnd.zip(newLinesWithBeginAndEnd.tail)
+ } else {
+ List(0 -> caseClauses.length)
+ }
+
+ ranges.foldLeft(List[Either[ConsecutiveSingleLineCaseClauses, CaseClause]]()) {
+ case (acc, (begin, end)) =>
+ val slice = caseClauses.slice(begin, end)
+ acc ++ groupClauses(slice, first = true)
+ }
}
private case class ConsecutiveSingleLineCaseClauses(clauses: List[CaseClause], largestCasePatternLength: Int, smallestCasePatternLength: Int) {
@@ -114,6 +135,21 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
val CasePattern(caseToken: Token, pattern: Expr, guardOption: Option[Guard], arrow: Token) = casePattern
var formatResult: FormatResult = NoFormatResult
formatResult ++= format(pattern)
+
+ val beginTokensAfterPipe = List(casePattern.pattern.tokens.head) ++ casePattern.pattern.tokens.zip(casePattern.pattern.tokens.tail).collect {
+ case (Token(PIPE, _, _, _), b) if b.associatedWhitespaceAndComments.containsNewline => b
+ }
+
+ val alignBeginTokens: Map[Token, IntertokenFormatInstruction] = beginTokensAfterPipe.zip(beginTokensAfterPipe.tail).flatMap {
+ case (a, b) => if (b.associatedWhitespaceAndComments.containsNewline) {
+ Map(b -> EnsureNewlineAndIndent(0, Some(a)))
+ } else {
+ Map.empty[Token, IntertokenFormatInstruction]
+ }
+ }.toMap
+
+ formatResult ++= FormatResult(alignBeginTokens, Map(), Map())
+
for (guard ← guardOption)
formatResult ++= format(guard)
arrowInstructionOpt foreach { instruction ⇒ formatResult = formatResult.before(arrow, instruction) }
@@ -149,10 +185,14 @@ trait CaseClauseFormatter { self: HasFormattingPreferences with ExprFormatter wi
if separator.isNewline
} yield separator
- private def previousCaseClauseTrailingNewlineOpt(caseClause: CaseClause, caseClauses: CaseClauses): Option[Token] =
- Utils.pairWithPrevious(caseClauses.caseClauses).collect {
+ private def previousCaseClauseTrailingNewlineOpt(caseClause: CaseClause, caseClauses: CaseClauses): Option[Token] = {
+ val previousCaseClauseOpt = Utils.pairWithPrevious(caseClauses.caseClauses).collect {
case (Some(previousClause), `caseClause`) ⇒ previousClause
- }.headOption.flatMap(getTrailingNewline)
+ }.headOption
+ val hasNewLine = previousCaseClauseOpt.flatMap(getTrailingNewline)
+ val hasNewLineAtEnd = previousCaseClauseOpt.flatMap(_.statSeq.tokens.lastOption.filter(_.isNewline))
+ hasNewLine.orElse(hasNewLineAtEnd)
+ }
private def previousCaseClauseEndsWithNewline(caseClause: CaseClause, caseClauses: CaseClauses): Boolean =
previousCaseClauseTrailingNewlineOpt(caseClause, caseClauses).isDefined
diff --git a/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala
old mode 100644
new mode 100755
index f06d6804..ef59659c
--- a/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/ExprFormatter.scala
@@ -636,15 +636,22 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
(CompactEnsuringGap, indentedState)
formatResult = formatResult.before(statSeq.firstToken, instruction)
formatResult ++= format(params)
+
+ val hasNewScopeAfterArrow = {
+ val arrowIndex = statSeq.tokens.indexWhere(_.tokenType == ARROW)
+ val tokenAfterArrow = statSeq.tokens.lift(arrowIndex + 1)
+ tokenAfterArrow.map(_.tokenType == lbrace.tokenType).getOrElse(false)
+ }
for (firstToken ← subStatSeq.firstTokenOption) {
val instruction =
- if (hiddenPredecessors(firstToken).containsNewline || containsNewline(subStatSeq))
+ if (!hasNewScopeAfterArrow && (hiddenPredecessors(firstToken).containsNewline || containsNewline(subStatSeq)))
statFormatterState(subStatSeq.firstStatOpt)(subStatState).currentIndentLevelInstruction
else
CompactEnsuringGap
formatResult = formatResult.before(firstToken, instruction)
}
- formatResult ++= format(subStatSeq)(subStatState)
+ val subStatStateAfterArrow = if(hasNewScopeAfterArrow) newFormatterState.indent else subStatState
+ formatResult ++= format(subStatSeq)(subStatStateAfterArrow)
case _ ⇒
val instruction = statSeq.selfReferenceOpt match {
case Some((selfReference, arrow)) if !hiddenPredecessors(selfReference.firstToken).containsNewline ⇒
@@ -683,7 +690,7 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
}
for (stat ← firstStatOpt)
- formatResult ++= format(stat)(firstStatFormatterState)
+ formatResult ++= format(stat, true)(firstStatFormatterState)
for ((semi, otherStatOption) ← otherStats) {
@@ -702,7 +709,7 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
CompactEnsuringGap
formatResult = formatResult.before(firstToken, instruction)
}
- formatResult ++= format(otherStat)(otherStatFormatterState)
+ formatResult ++= format(otherStat, false)(otherStatFormatterState)
}
}
@@ -710,15 +717,47 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
formatResult
}
- private def format(stat: Stat)(implicit formatterState: FormatterState): FormatResult =
+ private def format(stat: Stat, firstStat: Boolean)(implicit formatterState: FormatterState): FormatResult =
stat match {
case expr: Expr ⇒ format(expr)
case fullDefOrDcl: FullDefOrDcl ⇒ format(fullDefOrDcl)
case import_ : ImportClause ⇒ format(import_)
case packageBlock: PackageBlock ⇒ format(packageBlock)
+ case packageStat: PackageStat ⇒ format(packageStat, firstStat)
case _ ⇒ NoFormatResult // TODO
}
+ def format(packageStat: PackageStat, firstPackage: Boolean)(implicit formatterState: FormatterState): FormatResult = {
+ var formatResult: FormatResult = NoFormatResult
+
+ if (formattingPreferences(ChainedPackageClauses)) {
+ val PackageStat(packageToken: Token, name: CallExpr) = packageStat
+
+ val packageDepth = if(firstPackage) formattingPreferences(ChainedPackageClauses.PackageDepth) else 1
+
+ def dotsForPackageNames(name: CallExpr): List[Token] = {
+ name.exprDotOpt match {
+ case Some((List(c@CallExpr(_, id, _, _, _)), dot)) =>
+ dot :: dotsForPackageNames(c)
+ case _ =>
+ Nil
+ }
+ }
+
+ val dotsBetweenPackageNames = dotsForPackageNames(name)
+
+ val lineBreaksAfter = dotsBetweenPackageNames.reverse.drop(packageDepth-1)
+
+ for {
+ token <- lineBreaksAfter
+ } {
+ formatResult ++= FormatResult(Map(token -> EnsureNewlineAndIndent(0, Some(packageToken))), Map(), Map())
+ }
+ }
+
+ formatResult
+ }
+
def format(packageBlock: PackageBlock)(implicit formatterState: FormatterState): FormatResult = {
val PackageBlock(packageToken: Token, name: CallExpr, newlineOpt: Option[Token], lbrace: Token, topStats: StatSeq, rbrace: Token) = packageBlock
@@ -909,9 +948,13 @@ trait ExprFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
val newFormatterState = formatterState.copy(inSingleLineBlock = singleLineBlock)
if (singleLineBlock) {
+ if (formattingPreferences(NoSpacesAroundMultiImports))
+ formatResult = formatResult.before(firstImportSelector.firstToken, Compact)
formatResult ++= format(firstImportSelector)
for ((comma, otherImportSelector) ← otherImportSelectors)
formatResult ++= format(otherImportSelector)
+ if (formattingPreferences(NoSpacesAroundMultiImports))
+ formatResult = formatResult.before(rbrace, Compact)
} else {
formatResult = formatResult.before(firstImportSelector.firstToken, formatterState.nextIndentLevelInstruction)
formatResult ++= format(firstImportSelector)
diff --git a/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala b/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala
index 20da836a..92d0cd54 100644
--- a/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/FormatResult.scala
@@ -5,6 +5,12 @@ import scalariform.lexer._
import scalariform.parser._
import scalariform.utils._
+object FormatResult {
+
+ val EMPTY = FormatResult(Map(), Map(), Map())
+
+}
+
case class FormatResult(predecessorFormatting: Map[Token, IntertokenFormatInstruction],
inferredNewlineFormatting: Map[Token, IntertokenFormatInstruction],
xmlRewrites: Map[Token, String]) {
diff --git a/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
old mode 100644
new mode 100755
index 17f945af..e6c1792e
--- a/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/ScalaFormatter.scala
@@ -221,7 +221,12 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
val replacement = builder.substring(startPos)
positionHintOption match {
case Some(positionHint) if hiddenTokens.isEmpty ⇒
- Some(TextEdit(positionHint, length = 0, replacement = replacement))
+ instruction match {
+ case EnsureNewlineAndIndent(indentLevel, Some(Token(PACKAGE, _, _, _))) =>
+ Some(TextEdit(positionHint, length = 1, replacement = replacement + "package "))
+ case _ =>
+ Some(TextEdit(positionHint, length = 0, replacement = replacement))
+ }
case _ ⇒
for {
firstToken ← hiddenTokens.firstTokenOption
@@ -348,7 +353,7 @@ abstract class ScalaFormatter extends HasFormattingPreferences with TypeFormatte
return CompactEnsuringGap
if (type1 == MINUS && (type2 == INTEGER_LITERAL || type2 == FLOATING_POINT_LITERAL))
return Compact
- if (Set(IMPLICIT, VAL, VAR, PRIVATE, PROTECTED, OVERRIDE).contains(type2) && type1 == LPAREN)
+ if (Set(IMPLICIT, VAL, VAR, PRIVATE, PROTECTED, OVERRIDE, FINAL).contains(type2) && type1 == LPAREN)
return Compact
if ((type1 == PROTECTED || type1 == PRIVATE) && type2 == LBRACKET)
return Compact
@@ -423,7 +428,7 @@ object ScalaFormatter {
FINALLY, FOR, FORSOME, IF, IMPLICIT,
IMPORT, LAZY, MATCH, NEW,
OBJECT, OVERRIDE, PACKAGE, PRIVATE, PROTECTED,
- REQUIRES, RETURN, SEALED, /* SUPER, THIS, */
+ RETURN, SEALED, /* SUPER, THIS, */
THROW, TRAIT, TRY, /* TYPE ,*/
VAL, VAR, WHILE, WITH, YIELD,
/* USCORE, */ COLON, EQUALS, ARROW, LARROW, SUBTYPE, VIEWBOUND, SUPERTYPE, /* HASH, AT */
@@ -435,7 +440,7 @@ object ScalaFormatter {
FINALLY, /* FOR, */ FORSOME, /* IF, */ IMPLICIT,
/* IMPORT, */ LAZY, MATCH, /* NEW, */
OBJECT, OVERRIDE, /* PACKAGE, */ PRIVATE, PROTECTED,
- /* REQUIRES, RETURN, */ SEALED, /* SUPER, THIS, */
+ /* RETURN, */ SEALED, /* SUPER, THIS, */
/* THROW, */ TRAIT, /* TRY, TYPE, */
VAL, VAR, /* WHILE, */ WITH, YIELD,
/* USCORE, COLON, */ EQUALS, /* ARROW, */ LARROW, SUBTYPE, VIEWBOUND, SUPERTYPE, /*, HASH, AT, */
diff --git a/scalariform/src/main/scala/scalariform/formatter/SpecificFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/SpecificFormatter.scala
index b0b976d2..82bac11a 100644
--- a/scalariform/src/main/scala/scalariform/formatter/SpecificFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/SpecificFormatter.scala
@@ -51,10 +51,10 @@ trait SpecificFormatter {
} actualFormattingPreferences = actualFormattingPreferences.setPreference(preference, onOrOff)
val parsedTokens = parseResult.tokens.filter(_.tokenType != EOF)
- require(parsedTokens == tokens.init /* <-- drop EOF */, "Parse tokens differ from expected.\n Actual = \n" +
+ require(parsedTokens == tokens.init /* <-- drop EOF */ , "Parse tokens differ from expected.\n Actual = \n" +
parsedTokens.mkString("\n") + "\n expected = \n" + tokens.init.mkString("\n") + "\n parseResult = \n" +
parseResult)
-
+
if (debug) { println("Parse result: " + parseResult) }
val elapsedTime = System.currentTimeMillis - startTime
// if (debug)
diff --git a/scalariform/src/main/scala/scalariform/formatter/TemplateFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/TemplateFormatter.scala
index 81a3a9fd..d201fb5b 100644
--- a/scalariform/src/main/scala/scalariform/formatter/TemplateFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/TemplateFormatter.scala
@@ -50,16 +50,20 @@ trait TemplateFormatter { self: HasFormattingPreferences with AnnotationFormatte
formatResult ++= format(earlyBody)(currentFormatterState)
for (templateParents ← templateParentsOpt) {
- val TemplateParents(type1: Type, argumentExprss: List[ArgumentExprs], withTypes: List[(Token, Type)]) = templateParents
+ val TemplateParents((type1: Type, argumentExprss: List[ArgumentExprs]), withTypes: List[(Token, Type, List[ArgumentExprs])]) = templateParents
+
formatResult ++= format(type1)(currentFormatterState)
for (argumentExprs ← argumentExprss)
formatResult ++= format(argumentExprs)(currentFormatterState)._1
- for ((withToken, type_) ← withTypes) {
+
+ for ((withToken, type_, argumentExprss2) ← withTypes) {
if (hiddenPredecessors(withToken).containsNewline) {
currentFormatterState = formatterState.indent(inheritanceIndent)
formatResult = formatResult.before(withToken, currentFormatterState.currentIndentLevelInstruction)
}
formatResult ++= format(type_)(currentFormatterState)
+ for (argumentExprs2 ← argumentExprss2)
+ formatResult ++= format(argumentExprs2)(currentFormatterState)._1
}
}
}
@@ -113,8 +117,20 @@ trait TemplateFormatter { self: HasFormattingPreferences with AnnotationFormatte
private def format(templateParents: TemplateParents)(implicit formatterState: FormatterState): FormatResult = {
var formatResult: FormatResult = NoFormatResult
- for (argumentExprs ← templateParents.argumentExprss)
+ val TemplateParents((type1: Type, argumentExprss: List[ArgumentExprs]), withTypes: List[(Token, Type, List[ArgumentExprs])]) = templateParents
+ formatResult ++= format(type1)
+ for (argumentExprs ← argumentExprss)
formatResult ++= format(argumentExprs)._1
+
+ // TODO: Unify with TmplDef code
+
+ val currentFormatterState = formatterState
+ for ((withToken, type_, argumentExprss2) ← withTypes) {
+ formatResult ++= format(type_)(currentFormatterState)
+ for (argumentExprs2 ← argumentExprss2)
+ formatResult ++= format(argumentExprs2)(currentFormatterState)._1
+ }
+
formatResult
}
diff --git a/scalariform/src/main/scala/scalariform/formatter/TypeFormatter.scala b/scalariform/src/main/scala/scalariform/formatter/TypeFormatter.scala
index d69d6c11..7b2b725a 100644
--- a/scalariform/src/main/scala/scalariform/formatter/TypeFormatter.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/TypeFormatter.scala
@@ -20,7 +20,7 @@ trait TypeFormatter { self: HasFormattingPreferences with AnnotationFormatter wi
previousElement.isInstanceOf[InfixTypeConstructor] ||
element.isInstanceOf[Refinement] ||
element.isInstanceOf[InfixTypeConstructor])
- formatResult = formatResult.before(element.firstToken, CompactEnsuringGap)
+ formatResult = formatResult.formatNewlineOrOrdinary(element.firstToken, CompactEnsuringGap)
else if (element.isInstanceOf[Annotation]) {
val instruction =
previousElement match {
diff --git a/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala b/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala
old mode 100644
new mode 100755
index 48975161..ed73714d
--- a/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala
+++ b/scalariform/src/main/scala/scalariform/formatter/preferences/PreferenceDescriptor.scala
@@ -62,9 +62,9 @@ trait IntegerPreferenceDescriptor extends PreferenceDescriptor[Int] {
object AllPreferences {
val preferences: List[PreferenceDescriptor[_]] = List(RewriteArrowSymbols, IndentSpaces, SpaceBeforeColon, CompactStringConcatenation,
PreserveSpaceBeforeArguments, AlignParameters, DoubleIndentClassDeclaration, FormatXml, IndentPackageBlocks,
- AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, IndentLocalDefs, PreserveDanglingCloseParenthesis,
+ AlignSingleLineCaseStatements, AlignSingleLineCaseStatements.MaxArrowIndent, AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, IndentLocalDefs, PreserveDanglingCloseParenthesis,
SpaceInsideParentheses, SpaceInsideBrackets, SpacesWithinPatternBinders, MultilineScaladocCommentsStartOnFirstLine, IndentWithTabs,
- CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk)
+ CompactControlReadability, PlaceScaladocAsterisksBeneathSecondAsterisk, NoSpacesAroundMultiImports, ChainedPackageClauses, ChainedPackageClauses.PackageDepth)
val preferencesByKey: Map[String, PreferenceDescriptor[_]] = {
var map: Map[String, PreferenceDescriptor[_]] = Map()
@@ -142,6 +142,18 @@ case object AlignSingleLineCaseStatements extends BooleanPreferenceDescriptor {
val defaultValue = 40
}
+ case object AlignMultiLineCaseStatements extends BooleanPreferenceDescriptor {
+ val key = "alignSingleLineCaseStatements.alignMultiLineCaseStatements"
+ val description = "Align the arrows of consecutive multi-line case statements"
+ val defaultValue = false
+ }
+
+ case object GroupByNewLine extends BooleanPreferenceDescriptor {
+ val key = "alignSingleLineCaseStatements.groupByNewLine"
+ val description = "Treat blocks that are separated by newlines independently"
+ val defaultValue = false
+ }
+
}
case object IndentLocalDefs extends BooleanPreferenceDescriptor {
@@ -196,4 +208,23 @@ case object PlaceScaladocAsterisksBeneathSecondAsterisk extends BooleanPreferenc
val key = "placeScaladocAsterisksBeneathSecondAsterisk"
val description = "Place Scaladoc asterisks beneath the second asterisk in the opening '/**', as opposed to the first"
val defaultValue = false
-}
\ No newline at end of file
+}
+
+case object NoSpacesAroundMultiImports extends BooleanPreferenceDescriptor {
+ val key = "noSpacesAroundMultiImports"
+ val description = "Don't place spaces around multi imports (Java-style)"
+ val defaultValue = false
+}
+
+case object ChainedPackageClauses extends BooleanPreferenceDescriptor {
+ val key = "chainedPackageClauses"
+ val description = "Break up chained package clauses"
+ val defaultValue = false
+
+ case object PackageDepth extends IntegerPreferenceDescriptor {
+ val key = "chainedPackageClauses.packageDepth"
+ val description = "Depth of package nesting"
+ val preferenceType = IntegerPreference(1, 100)
+ val defaultValue = 4
+ }
+}
diff --git a/scalariform/src/main/scala/scalariform/lexer/Keywords.scala b/scalariform/src/main/scala/scalariform/lexer/Keywords.scala
index 552d2f11..1932b4f8 100644
--- a/scalariform/src/main/scala/scalariform/lexer/Keywords.scala
+++ b/scalariform/src/main/scala/scalariform/lexer/Keywords.scala
@@ -32,7 +32,6 @@ object Keywords {
"package" -> PACKAGE,
"private" -> PRIVATE,
"protected" -> PROTECTED,
- "requires" -> REQUIRES,
"return" -> RETURN,
"sealed" -> SEALED,
"super" -> SUPER,
@@ -65,4 +64,4 @@ object Keywords {
"~" -> TILDE,
"!" -> EXCLAMATION)
-}
\ No newline at end of file
+}
diff --git a/scalariform/src/main/scala/scalariform/lexer/NewlineInferencer.scala b/scalariform/src/main/scala/scalariform/lexer/NewlineInferencer.scala
index 2a37e73a..b008a602 100644
--- a/scalariform/src/main/scala/scalariform/lexer/NewlineInferencer.scala
+++ b/scalariform/src/main/scala/scalariform/lexer/NewlineInferencer.scala
@@ -100,8 +100,8 @@ class NewlineInferencer(delegate: WhitespaceAndCommentsGrouper) extends Iterator
false
else if (TOKENS_WHICH_CANNOT_BEGIN_A_STATEMENT contains currentTokenType)
false
-// else if (currentTokenType == CASE && !followingTokenIsClassOrObject(nextToken))
-// false
+ // else if (currentTokenType == CASE && !followingTokenIsClassOrObject(nextToken))
+ // false
else if (regionMarkerStack.nonEmpty && regionMarkerStack.head != RBRACE)
false
else
@@ -138,7 +138,7 @@ object NewlineInferencer {
XML_COMMENT, XML_CDATA, XML_UNPARSED, XML_PROCESSING_INSTRUCTION, USCORE, RPAREN, RBRACKET, RBRACE)
private val TOKENS_WHICH_CANNOT_BEGIN_A_STATEMENT: Set[TokenType] = Set(
- CATCH, ELSE, EXTENDS, FINALLY, FORSOME, MATCH, REQUIRES, WITH, YIELD, COMMA, DOT, SEMI, COLON, /* USCORE, */ EQUALS,
+ CATCH, ELSE, EXTENDS, FINALLY, FORSOME, MATCH, WITH, YIELD, COMMA, DOT, SEMI, COLON, /* USCORE, */ EQUALS,
ARROW, LARROW, SUBTYPE, VIEWBOUND, SUPERTYPE, HASH, LBRACKET, RPAREN, RBRACKET, RBRACE)
private val BLANK_LINE_PATTERN = """(?s).*\n\s*\n.*"""
diff --git a/scalariform/src/main/scala/scalariform/lexer/Token.scala b/scalariform/src/main/scala/scalariform/lexer/Token.scala
index 365122eb..6e5cb72b 100644
--- a/scalariform/src/main/scala/scalariform/lexer/Token.scala
+++ b/scalariform/src/main/scala/scalariform/lexer/Token.scala
@@ -27,6 +27,8 @@ case class Token(tokenType: TokenType, text: String, offset: Int, rawText: Strin
def isNewline = tokenType.isNewline
+ def isNewlines = tokenType.isNewlines
+
@deprecated(message = "Use text instead" /*, since = "0.1.2"*/ )
def getText = text
diff --git a/scalariform/src/main/scala/scalariform/lexer/TokenType.scala b/scalariform/src/main/scala/scalariform/lexer/TokenType.scala
index 2f51e561..fb64f3ba 100644
--- a/scalariform/src/main/scala/scalariform/lexer/TokenType.scala
+++ b/scalariform/src/main/scala/scalariform/lexer/TokenType.scala
@@ -2,7 +2,9 @@ package scalariform.lexer
case class TokenType(name: String, isXml: Boolean = false) {
- def isNewline = this == Tokens.NEWLINE || this == Tokens.NEWLINES
+ def isNewline = this == Tokens.NEWLINE || isNewlines
+
+ def isNewlines = this == Tokens.NEWLINES
def isKeyword = Tokens.KEYWORDS contains this
diff --git a/scalariform/src/main/scala/scalariform/lexer/Tokens.scala b/scalariform/src/main/scala/scalariform/lexer/Tokens.scala
index 3b2be011..4e7b305a 100644
--- a/scalariform/src/main/scala/scalariform/lexer/Tokens.scala
+++ b/scalariform/src/main/scala/scalariform/lexer/Tokens.scala
@@ -78,7 +78,6 @@ object Tokens {
val SEMI = TokenType("SEMI")
val COLON = TokenType("COLON")
val OTHERID = TokenType("OTHERID")
- val REQUIRES = TokenType("REQUIRES")
val NEWLINE = TokenType("NEWLINE")
val FINALLY = TokenType("FINALLY")
val OVERRIDE = TokenType("OVERRIDE")
@@ -105,7 +104,7 @@ object Tokens {
FINALLY, FOR, FORSOME, IF, IMPLICIT,
IMPORT, LAZY, MATCH, NEW,
OBJECT, OVERRIDE, PACKAGE, PRIVATE, PROTECTED,
- REQUIRES, RETURN, SEALED, SUPER, THIS,
+ RETURN, SEALED, SUPER, THIS,
THROW, TRAIT, TRY, TYPE,
VAL, VAR, WHILE, WITH, YIELD)
diff --git a/scalariform/src/main/scala/scalariform/parser/AstNodes.scala b/scalariform/src/main/scala/scalariform/parser/AstNodes.scala
index 9e05b063..23988e7f 100644
--- a/scalariform/src/main/scala/scalariform/parser/AstNodes.scala
+++ b/scalariform/src/main/scala/scalariform/parser/AstNodes.scala
@@ -26,6 +26,7 @@ sealed trait AstNode extends CaseClassReflector {
protected implicit def listToFlattenable[T <% Flattenable](list: List[T]): Flattenable = new Flattenable { val tokens = list flatMap { _.tokens } }
protected implicit def optionToFlattenable[T <% Flattenable](option: Option[T]): Flattenable = new Flattenable { val tokens = option.toList flatMap { _.tokens } }
protected implicit def pairToFlattenable[T1 <% Flattenable, T2 <% Flattenable](pair: (T1, T2)): Flattenable = new Flattenable { val tokens = pair._1.tokens ::: pair._2.tokens }
+ protected implicit def tripleToFlattenable[T1 <% Flattenable, T2 <% Flattenable, T3 <% Flattenable](triple: (T1, T2, T3)): Flattenable = new Flattenable { val tokens = triple._1.tokens ++ triple._2.tokens ++ triple._3.tokens }
protected implicit def eitherToFlattenable[T1 <% Flattenable, T2 <% Flattenable](either: T1 Either T2): Flattenable = new Flattenable {
val tokens = either match {
case Left(f) ⇒ f.tokens
@@ -355,8 +356,8 @@ case class StatSeq(selfReferenceOpt: Option[(Expr, Token)],
}
-case class TemplateParents(type1: Type, argumentExprss: List[ArgumentExprs], withTypes: List[(Token, Type)]) extends AstNode {
- lazy val tokens = flatten(type1, argumentExprss, withTypes)
+case class TemplateParents(typeAndArgs: (Type, List[ArgumentExprs]), withTypesAndArgs: List[(Token, Type, List[ArgumentExprs])]) extends AstNode {
+ lazy val tokens = flatten(typeAndArgs, withTypesAndArgs)
}
case class ImportClause(importToken: Token, importExpr: ImportExpr, otherImportExprs: List[(Token, ImportExpr)]) extends AstNode with Stat {
@@ -415,12 +416,15 @@ sealed trait XmlExprElement extends ExprElement
case class XmlStartTag(startOpen: Token, name: Token, attributes: List[(Option[Token], XmlAttribute)], whitespaceOption: Option[Token], tagClose: Token) extends XmlExprElement {
lazy val tokens = flatten(startOpen, name, attributes, whitespaceOption, tagClose)
}
+
case class XmlAttribute(name: Token, whitespaceOption: Option[Token], equals: Token, whitespaceOption2: Option[Token], valueOrEmbeddedScala: Either[Token, Expr]) extends XmlExprElement {
lazy val tokens = flatten(name, whitespaceOption, equals, whitespaceOption2, valueOrEmbeddedScala)
}
+
case class XmlEmptyElement(startOpen: Token, name: Token, attributes: List[(Option[Token], XmlAttribute)], whitespaceOption: Option[Token], emptyClose: Token) extends XmlElement {
lazy val tokens = flatten(startOpen, name, attributes, whitespaceOption, emptyClose)
}
+
case class XmlEndTag(endOpen: Token, name: Token, whitespaceOption: Option[Token], tagClose: Token) extends XmlExprElement {
lazy val tokens = flatten(endOpen, name, whitespaceOption, tagClose)
}
diff --git a/scalariform/src/main/scala/scalariform/parser/InferredSemicolonScalaParser.scala b/scalariform/src/main/scala/scalariform/parser/InferredSemicolonScalaParser.scala
index 2be86d90..7707f71f 100644
--- a/scalariform/src/main/scala/scalariform/parser/InferredSemicolonScalaParser.scala
+++ b/scalariform/src/main/scala/scalariform/parser/InferredSemicolonScalaParser.scala
@@ -406,6 +406,10 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
dropAnyBraces(pattern())
else if (isIdent)
ident()
+ else if (LBRACE)
+ expr()
+ else if (THIS)
+ nextToken()
else
expr()
}
@@ -651,7 +655,7 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
case NEW ⇒
canApply = false
nextToken()
- template(isTrait = false)
+ template()
case _ ⇒
throw new ScalaParserException("illegal start of simple expression: " + currentToken)
}
@@ -1259,27 +1263,30 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
templateOpt(isTrait = false)
}
- private def templateParents(isTrait: Boolean) = {
- startAnnotType()
- if (LPAREN && !isTrait) multipleArgumentExprs()
- else Nil
+ private def templateParents() {
+ def readAppliedParent() {
+ startAnnotType()
+ if (LPAREN)
+ multipleArgumentExprs()
+ }
+ readAppliedParent()
while (WITH) {
nextToken()
- startAnnotType()
+ readAppliedParent()
}
}
- private def template(isTrait: Boolean) {
+ private def template() {
newLineOptWhenFollowedBy(LBRACE)
if (LBRACE) {
templateBody()
if (WITH) { // TODO check cond
nextToken()
- templateParents(isTrait)
+ templateParents()
templateBodyOpt()
}
} else {
- templateParents(isTrait)
+ templateParents()
templateBodyOpt()
}
}
@@ -1287,7 +1294,7 @@ class InferredSemicolonScalaParser(tokens: Array[Token]) {
private def templateOpt(isTrait: Boolean) {
if (EXTENDS || SUBTYPE && isTrait) {
nextToken()
- template(isTrait)
+ template()
} else {
// val newLineOpt = newLineOptWhenFollowedBy(LBRACE) // Will be picked up by templateBodyOpt ... TODO: double check this
templateBodyOpt()
diff --git a/scalariform/src/main/scala/scalariform/parser/ScalaParser.scala b/scalariform/src/main/scala/scalariform/parser/ScalaParser.scala
index 3bc845c8..036923a1 100644
--- a/scalariform/src/main/scala/scalariform/parser/ScalaParser.scala
+++ b/scalariform/src/main/scala/scalariform/parser/ScalaParser.scala
@@ -798,7 +798,7 @@ class ScalaParser(tokens: Array[Token]) {
case NEW ⇒
canApply = false
val newToken = nextToken()
- val template_ = template(isTrait = false)
+ val template_ = template()
List(New(newToken, template_))
case _ ⇒
throw new ScalaParserException("illegal start of simple expression: " + currentToken)
@@ -1543,33 +1543,37 @@ class ScalaParser(tokens: Array[Token]) {
templateBodyOption = templateOpt_.templateBodyOpt)
}
- private def templateParents(isTrait: Boolean): TemplateParents = {
- val type1 = Type(startAnnotType())
- val argumentExprs_ =
- if (LPAREN && !isTrait) multipleArgumentExprs()
- else Nil
- val withTypes = ListBuffer[(Token, Type)]()
+ private def templateParents(): TemplateParents = {
+ def readAppliedParent(): (Type, List[ArgumentExprs]) = {
+ val parent = Type(startAnnotType())
+ val argss =
+ if (LPAREN) multipleArgumentExprs()
+ else Nil
+ (parent, argss)
+ }
+ val withTypes = ListBuffer[(Token, Type, List[ArgumentExprs])]()
+ val (type1, argumentExprs) = readAppliedParent()
while (WITH) {
val withToken = nextToken()
- val withType = Type(startAnnotType())
- withTypes += ((withToken, withType))
+ val (type2, argumentExprs2) = readAppliedParent()
+ withTypes += ((withToken, type2, argumentExprs2))
}
- TemplateParents(type1, argumentExprs_, withTypes.toList)
+ TemplateParents((type1, argumentExprs), withTypes.toList)
}
- private def template(isTrait: Boolean): Template = {
+ private def template(): Template = {
val newLineOpt = newLineOptWhenFollowedBy(LBRACE)
if (LBRACE) {
val templateBody_ = templateBody().copy(newlineOpt = newLineOpt)
if (WITH) { // TODO check cond
val withToken = nextToken()
- val templateParents_ = templateParents(isTrait)
+ val templateParents_ = templateParents()
val templateBodyOpt_ = templateBodyOpt()
Template(Some(EarlyDefs(templateBody_, Some(withToken))), Some(templateParents_), templateBodyOpt_)
} else
Template(Some(EarlyDefs(templateBody_, withOpt = None)), templateParentsOpt = None, templateBodyOpt = None)
} else {
- val templateParents_ = templateParents(isTrait)
+ val templateParents_ = templateParents()
val templateBodyOpt_ = templateBodyOpt()
Template(earlyDefsOpt = None, Some(templateParents_), templateBodyOpt_)
}
@@ -1578,7 +1582,7 @@ class ScalaParser(tokens: Array[Token]) {
private def templateOpt(isTrait: Boolean): TemplateOpt = {
if (EXTENDS || SUBTYPE && isTrait) {
val extendsOrSubtypeToken = nextToken()
- template(isTrait) match {
+ template() match {
case Template(earlyDefsOpt, templateParentsOpt, templateBodyOpt) ⇒
TemplateOpt(Some(TemplateInheritanceSection(extendsOrSubtypeToken, earlyDefsOpt, templateParentsOpt)), templateBodyOpt)
}
diff --git a/scalariform/src/main/scala/scalariform/utils/Utils.scala b/scalariform/src/main/scala/scalariform/utils/Utils.scala
index 771b5106..4f796857 100644
--- a/scalariform/src/main/scala/scalariform/utils/Utils.scala
+++ b/scalariform/src/main/scala/scalariform/utils/Utils.scala
@@ -21,7 +21,7 @@ object Utils {
implicit def string2PimpedString(s: String) = new PimpedString(s)
class PimpedString(s: String) {
- def toIntOpt: Option[Int] = try Some(s.toInt) catch { case _: NumberFormatException => None }
+ def toIntOpt: Option[Int] = try Some(s.toInt) catch { case _: NumberFormatException ⇒ None }
}
def stagger[T](iterable: Iterable[T]) = iterable zip iterable.tail
diff --git a/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala
old mode 100644
new mode 100755
index a2e106a6..06b20136
--- a/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/CaseClausesFormatterTest.scala
@@ -306,4 +306,218 @@ class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
| case elem @ Multi(values @ _*) =>
|}"""
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+
+ """a match {
+ |case "once" =>
+ |println("einmal")
+ |println("nochmal")
+ |case "many times" =>
+ |println("again")
+ |println("multiline")
+ |case _ =>
+ |println("again")
+ |println("multiline")
+ |}""" ==>
+ """a match {
+ | case "once" =>
+ | println("einmal")
+ | println("nochmal")
+ | case "many times" =>
+ | println("again")
+ | println("multiline")
+ | case _ =>
+ | println("again")
+ | println("multiline")
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, false)
+
+ """a match {
+ |case "once" =>
+ |println("einmal")
+ |println("nochmal")
+ |case "many times" =>
+ |println("again")
+ |println("multiline")
+ |case _ =>
+ |println("again")
+ |println("multiline")
+ |
+ |case "after a newline" =>
+ |println("IntelliJ")
+ |println("formats")
+ |case "next lines" =>
+ |println("separately")
+ |}""" ==>
+ """a match {
+ | case "once" =>
+ | println("einmal")
+ | println("nochmal")
+ | case "many times" =>
+ | println("again")
+ | println("multiline")
+ | case _ =>
+ | println("again")
+ | println("multiline")
+ |
+ | case "after a newline" =>
+ | println("IntelliJ")
+ | println("formats")
+ | case "next lines" =>
+ | println("separately")
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true)
+
+ """a match {
+ |case "once" =>
+ |println("einmal")
+ |println("nochmal")
+ |case "many times" =>
+ |println("again")
+ |println("multiline")
+ |case _ =>
+ |println("again")
+ |println("multiline")
+ |
+ |case "after a newline" =>
+ |println("IntelliJ")
+ |println("formats")
+ |case "next lines" =>
+ |println("separately")
+ |}""" ==>
+ """a match {
+ | case "once" =>
+ | println("einmal")
+ | println("nochmal")
+ | case "many times" =>
+ | println("again")
+ | println("multiline")
+ | case _ =>
+ | println("again")
+ | println("multiline")
+ |
+ | case "after a newline" =>
+ | println("IntelliJ")
+ | println("formats")
+ | case "next lines" =>
+ | println("separately")
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 200)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true)
+
+ """x match {
+ |case 1 | 2 |
+ |3 | 4 |
+ |5 | 6 => 1
+ |case 7 | 8 => 1
+ |}""" ==>
+ """x match {
+ | case 1 | 2 |
+ | 3 | 4 |
+ | 5 | 6 => 1
+ | case 7 | 8 => 1
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+
+ """x match { case _: X => Y }""" ==>
+ """x match { case _: X => Y }"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 200)
+ .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true)
+
+ """|x match {
+ | case 1 => A
+ | case 1234 |
+ | 5678 => A
+ | case 5 => A
+ | case 12345678 => A
+ |}""" ==>
+ """|x match {
+ | case 1 => A
+ | case 1234 |
+ | 5678 => A
+ | case 5 => A
+ | case 12345678 => A
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 200)
+
+ """|x match {
+ |case AA => a
+ |case B => b
+ |}""" ==>
+ """|x match {
+ | case AA => a
+ | case B => b
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+
+ """|x match {
+ |case AA => (s: Int) => 1
+ |case B => (s: Int) => 2
+ |}""" ==>
+ """|x match {
+ | case AA => (s: Int) => 1
+ | case B => (s: Int) => 2
+ |}"""
+ }
+
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.AlignMultiLineCaseStatements, true)
+ .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 160)
+ .setPreference(AlignSingleLineCaseStatements.GroupByNewLine, true)
+ .setPreference(SpacesWithinPatternBinders, false)
+
+ """|pairs.flatMap {
+ | case (p1@(t1, MandatoryGridPoint(true) | ExtremalGridPoint),
+ | (t2, MandatoryGridPoint(true) | ExtremalGridPoint)) =>
+ | val fillPointTime = (t1 + t2) / 2
+ | val fillPoint = (fillPointTime, FillingGridPoint)
+ | Seq(p1, fillPoint)
+ | case (p1, p2) => Seq(p1)
+ |}""" ==>
+ """|pairs.flatMap {
+ | case (p1@(t1, MandatoryGridPoint(true) | ExtremalGridPoint),
+ | (t2, MandatoryGridPoint(true) | ExtremalGridPoint)) =>
+ | val fillPointTime = (t1 + t2) / 2
+ | val fillPoint = (fillPointTime, FillingGridPoint)
+ | Seq(p1, fillPoint)
+ | case (p1, p2) => Seq(p1)
+ |}"""
+ }
+
}
diff --git a/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala
old mode 100644
new mode 100755
index 0f319ad6..8b3427ad
--- a/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/MiscExpressionFormatterTest.scala
@@ -771,11 +771,44 @@ class MiscExpressionFormatterTest extends AbstractExpressionFormatterTest {
| b => c
|}"""
+ """|a map {
+ |q => {
+ |2 * q
+ |}
+ |}""" ==>
+ """|a map {
+ | q => {
+ | 2 * q
+ | }
+ |}"""
+
+ """|a map {
+ |q =>
+ |{
+ |2 * q
+ |}
+ |}""" ==>
+ """|a map {
+ | q => {
+ | 2 * q
+ | }
+ |}"""
+
"f()[Foo]" ==> "f()[Foo]"
"a [ b . C ] [ d . E ] [ f . G ] " ==> "a[b.C][d.E][f.G]"
"{ 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
}
diff --git a/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala
old mode 100644
new mode 100755
index 4634e8d5..6301657d
--- a/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/PackageFormatterTest.scala
@@ -63,5 +63,32 @@ class PackageFormatterTest extends AbstractFormatterTest {
}
+ {
+ implicit val formattingPreferences = FormattingPreferences.setPreference(ChainedPackageClauses, true)
+
+ """package a.b.c.d.e.f
+ |""" ==>
+ """package a.b.c.d
+ |package e
+ |package f
+ |"""
+
+ """package com.company.analytics.math.curves.interpolators
+ |""" ==>
+ """package com.company.analytics.math
+ |package curves
+ |package interpolators
+ |"""
+
+ """package a.b.c.d.e.f
+ |package g.h
+ |""" ==>
+ """package a.b.c.d
+ |package e
+ |package f
+ |package g
+ |package h
+ |"""
+ }
}
diff --git a/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala
index e36c9c59..cc0a2783 100644
--- a/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/TemplateFormatterTest.scala
@@ -195,6 +195,7 @@ class TemplateFormatterTest extends AbstractFormatterTest {
"class A(private val b: C)" ==> "class A(private val b: C)"
"class A(protected val b: C)" ==> "class A(protected val b: C)"
"class A(override val b: C)" ==> "class A(override val b: C)"
+ "class A(final val b: C)" ==> "class A(final val b: C)"
"""class C[T <: A {val n: Int
|val m :Int}]""" ==>
@@ -598,6 +599,15 @@ class TemplateFormatterTest extends AbstractFormatterTest {
| @D def e
|}"""
+ """class A extends B(42 , 43) with C(44 , 45) {
+ | foo()
+ | bar()
+ |}""" ==>
+ """class A extends B(42, 43) with C(44, 45) {
+ | foo()
+ | bar()
+ |}"""
+
// format: ON
override val debug = false
diff --git a/scalariform/src/test/scala/scalariform/formatter/TypeFormatterTest.scala b/scalariform/src/test/scala/scalariform/formatter/TypeFormatterTest.scala
index ce2d39a8..2906e8e0 100644
--- a/scalariform/src/test/scala/scalariform/formatter/TypeFormatterTest.scala
+++ b/scalariform/src/test/scala/scalariform/formatter/TypeFormatterTest.scala
@@ -63,6 +63,10 @@ class TypeFormatterTest extends AbstractFormatterTest {
"b[c# ::[d]]" ==> "b[c# ::[d]]"
+ """C ::
+ | D""" ==>
+ """C :: D""" // To check that this doesn't blow up -- we should maintain the newline
+
override val debug = false
type Result = Type
diff --git a/scalariform/src/test/scala/scalariform/lexer/NewlineInferencerTest.scala b/scalariform/src/test/scala/scalariform/lexer/NewlineInferencerTest.scala
index 2ecbd04f..6455dced 100644
--- a/scalariform/src/test/scala/scalariform/lexer/NewlineInferencerTest.scala
+++ b/scalariform/src/test/scala/scalariform/lexer/NewlineInferencerTest.scala
@@ -14,7 +14,7 @@ import java.io._
class NewlineInferencerTest extends FlatSpec with ShouldMatchers {
implicit def string2TestString(s: String)(implicit forgiveErrors: Boolean = false, scalaVersion: ScalaVersion = ScalaVersions.DEFAULT) =
- new TestString(s, forgiveErrors, scalaVersion)
+ new TestString(s, forgiveErrors, scalaVersion);
// See issue #60
"""
diff --git a/scalariform/src/test/scala/scalariform/parser/ParserTest.scala b/scalariform/src/test/scala/scalariform/parser/ParserTest.scala
index 0b000233..4a2063da 100644
--- a/scalariform/src/test/scala/scalariform/parser/ParserTest.scala
+++ b/scalariform/src/test/scala/scalariform/parser/ParserTest.scala
@@ -25,7 +25,7 @@ class ParserTest extends FlatSpec with ShouldMatchers {
parseExpression("{ case List[String]() => 12 }")
}
- // See issue #60
+ // See issue #60
"Parser" should "not throw an exception on case block ending with decl" in {
parseExpression("""
args(0) match {
@@ -36,7 +36,7 @@ class ParserTest extends FlatSpec with ShouldMatchers {
}
""")
}
-
+
"Parser" should "throw a parse exception in bad package blocks" in {
evaluating { parseCompilationUnit("package a {} package b {}") } should produce[ScalaParserException]
}