├── docs
├── source
│ ├── README.rst
│ └── conf.py
└── Makefile
├── project
├── build.properties
├── project
│ └── plugins.sbt
├── .project
├── plugins.sbt
├── .classpath
└── Build.scala
├── scalariform.feature
├── build.properties
├── compile.scalariform.feature.xml
├── .project
├── pom.xml
└── feature.xml
├── .travis.yml
├── scalariform
├── notes
│ ├── about.markdown
│ ├── 0.1.4.markdown
│ ├── 0.1.3.markdown
│ ├── 0.1.6.markdown
│ ├── 0.1.5.markdown
│ ├── 0.0.6.markdown
│ ├── 0.0.7.markdown
│ ├── 0.1.2.markdown
│ ├── 0.0.8.markdown
│ ├── 0.1.0.markdown
│ ├── 0.0.9.markdown
│ └── 0.1.1.markdown
├── build.properties
├── src
│ ├── main
│ │ └── scala
│ │ │ └── com
│ │ │ └── danieltrinh
│ │ │ └── scalariform
│ │ │ ├── lexer
│ │ │ ├── LexerResult.scala
│ │ │ ├── CharConstants.scala
│ │ │ ├── ScalaLexerException.scala
│ │ │ ├── TagState.scala
│ │ │ ├── TokenType.scala
│ │ │ ├── ScalaLexerReader.scala
│ │ │ ├── HiddenToken.scala
│ │ │ ├── LexerMode.scala
│ │ │ ├── Chars.scala
│ │ │ ├── Token.scala
│ │ │ ├── RedundantSemicolonDetector.scala
│ │ │ ├── ModeStack.scala
│ │ │ ├── HiddenTokens.scala
│ │ │ ├── WhitespaceAndCommentsGrouper.scala
│ │ │ ├── Keywords.scala
│ │ │ ├── Tokens.scala
│ │ │ ├── UnicodeEscapeReader.scala
│ │ │ └── NewlineInferencer.scala
│ │ │ ├── parser
│ │ │ └── ScalaParserException.scala
│ │ │ ├── utils
│ │ │ ├── BooleanLang.scala
│ │ │ ├── Trimmed.scala
│ │ │ ├── CaseClassReflector.scala
│ │ │ ├── Range.scala
│ │ │ ├── TextEdits.scala
│ │ │ └── Utils.scala
│ │ │ ├── formatter
│ │ │ ├── AnnotationFormatter.scala
│ │ │ ├── FormatterDirectiveParser.scala
│ │ │ ├── FormatterState.scala
│ │ │ ├── preferences
│ │ │ │ ├── IFormattingPreferences.scala
│ │ │ │ └── PreferencesImporterExporter.scala
│ │ │ ├── Alignment.scala
│ │ │ ├── CommentFormatter.scala
│ │ │ ├── TypeFormatter.scala
│ │ │ ├── FormatResult.scala
│ │ │ ├── SpecificFormatter.scala
│ │ │ └── TemplateFormatter.scala
│ │ │ └── ScalaVersions.scala
│ └── test
│ │ └── scala
│ │ └── com
│ │ └── danieltrinh
│ │ └── scalariform
│ │ ├── formatter
│ │ ├── AbstractExpressionFormatterTest.scala
│ │ ├── RewriteArrowsTest.scala
│ │ ├── ScriptFormatterTest.scala
│ │ ├── MiscFormatterTest.scala
│ │ ├── FunctionFormatterTest.scala
│ │ ├── StringInterpolationFormatterTest.scala
│ │ ├── PackageFormatterTest.scala
│ │ ├── FormatterDirectiveParserTest.scala
│ │ ├── ImportFormatterTest.scala
│ │ ├── BlockExprFormatterTest.scala
│ │ ├── CompactControlReadabilityTest.scala
│ │ ├── WhileExprFormatterTest.scala
│ │ ├── TypeFormatterTest.scala
│ │ ├── ForExprFormatterTest.scala
│ │ ├── TryExprFormatterTest.scala
│ │ ├── AbstractFormatterTest.scala
│ │ ├── IndentWithTabsTest.scala
│ │ ├── CommentFormatterTest.scala
│ │ ├── ParenAndBracketSpacingTest.scala
│ │ ├── XmlExpressionFormatterTest.scala
│ │ ├── CaseClausesFormatterTest.scala
│ │ └── DefOrDclFormatterTest.scala
│ │ ├── utils
│ │ ├── TrimmedTest.scala
│ │ └── TextEditTest.scala
│ │ ├── parser
│ │ ├── ScalaParserTest.scala
│ │ └── ParserTest.scala
│ │ └── lexer
│ │ ├── RedundantSemicolonDetectorTest.scala
│ │ └── NewlineInferencerTest.scala
├── .project
├── META-INF
│ └── MANIFEST.MF
├── pom.xml
└── .classpath
├── scripts
├── count-sloc.sh
├── update-version.sh
└── version-list.txt
├── notes
└── scala-sync.txt
├── .ensime
├── cli
├── .project
├── .classpath
└── src
│ └── main
│ └── scala
│ └── com
│ └── danieltrinh
│ └── scalariform
│ └── commandline
│ ├── ScalaFileWalker.scala
│ └── CommandLineOptionParser.scala
├── misc
├── .project
├── src
│ └── main
│ │ └── scala
│ │ └── com
│ │ └── danieltrinh
│ │ └── scalariform
│ │ ├── gui
│ │ ├── SwingUtils.scala
│ │ ├── Main.scala
│ │ ├── TokenTable.scala
│ │ └── ParseTreeModel.scala
│ │ ├── perf
│ │ └── LexerPerformanceTest.scala
│ │ └── corpusscan
│ │ └── CorpusScanner.scala
└── .classpath
├── .gitignore
├── scalariform.update
├── site.xml
├── .project
├── pom.xml
├── web
│ └── site.css
└── index.html
├── CONTRIBUTORS
├── formatterPreferences.properties
├── LICENCE
└── pom.xml
/docs/source/README.rst:
--------------------------------------------------------------------------------
1 | ../../README.rst
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=0.13.7
2 |
--------------------------------------------------------------------------------
/scalariform.feature/build.properties:
--------------------------------------------------------------------------------
1 | bin.includes = feature.xml
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: scala
2 | scala:
3 | - 2.11.7
4 | - 2.10.6
5 | - 2.9.3
6 | jdk:
7 | - oraclejdk7
8 | - openjdk7
--------------------------------------------------------------------------------
/scalariform/notes/about.markdown:
--------------------------------------------------------------------------------
1 | [Scalariform][1] is a source code formatter for Scala.
2 |
3 | [1]: http://github.com/mdr/scalariform
4 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.4.markdown:
--------------------------------------------------------------------------------
1 | * FIX: Allow declarations as last statement in case block (issue #60)
2 | * Update to build 2.10 final
3 |
4 |
--------------------------------------------------------------------------------
/scalariform/build.properties:
--------------------------------------------------------------------------------
1 | bin.includes = META-INF/,\
2 | .
3 | source.. = src/main/scala/
4 | jars.compile.order = .
5 | output.. = bin/
6 |
--------------------------------------------------------------------------------
/scripts/count-sloc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | cd `dirname $0`/..
3 | cloc --exclude-dir=src_managed,target,docs '--exclude-lang=XML,XSLT,HTML,CSS,Bourne Shell' .
4 |
--------------------------------------------------------------------------------
/project/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | resolvers += Classpaths.typesafeSnapshots
2 |
3 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.4.0")
4 |
5 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/LexerResult.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | trait LexerResult {
4 |
5 | def tokens: List[Token]
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/notes/scala-sync.txt:
--------------------------------------------------------------------------------
1 | scalac changes checked 26/April/2013
2 |
3 | Scanners.scala: cdffcf8962c9fa606c027fcb5a50a4273976a576
4 | Parsers.scala: cd148d97225fc7738f7a8ff9d4479cd46d632371
5 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/CharConstants.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | object CharConstants {
4 |
5 | final val SU = '\u001A'
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/parser/ScalaParserException.scala:
--------------------------------------------------------------------------------
1 | package scalariform.parser
2 |
3 | class ScalaParserException(message: String) extends RuntimeException(message)
4 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.3.markdown:
--------------------------------------------------------------------------------
1 | * Add `EOF` to `ComplilationUnit`, ensuring entire source is represented in the tree
2 | * Support `$this` references in String interpolation
3 | * Update build to sbt 0.12.0
4 |
--------------------------------------------------------------------------------
/scripts/update-version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | PREVIOUS=$1
3 | NEXT=$2
4 |
5 | cd `dirname $0`/..
6 |
7 | while read p; do
8 | echo "Changing $p"
9 | sed -i s/$PREVIOUS/$NEXT/g $p
10 | done < scripts/version-list.txt
11 |
12 | git diff
13 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/ScalaLexerException.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.parser.ScalaParserException
4 |
5 | class ScalaLexerException(message: String) extends ScalaParserException(message)
6 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/TagState.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | abstract sealed trait TagState
4 | case object InStartTag extends TagState
5 | case object InEndTag extends TagState
6 | case object Normal extends TagState
7 |
8 |
--------------------------------------------------------------------------------
/scalariform.feature/compile.scalariform.feature.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.ensime:
--------------------------------------------------------------------------------
1 | ;; This config was generated using ensime-config-gen. Feel free to customize its contents manually.
2 |
3 | (
4 |
5 | :project-package "scalariform"
6 |
7 | :use-sbt t
8 |
9 | :formatting-prefs (:rewriteArrowSymbols t :alignParameters t :alignSingleLineCaseStatements t)
10 |
11 | )
12 |
--------------------------------------------------------------------------------
/scripts/version-list.txt:
--------------------------------------------------------------------------------
1 | pom.xml
2 | project/Build.scala
3 | scalariform/pom.xml
4 | scalariform.feature/pom.xml
5 | scalariform.feature/feature.xml
6 | scalariform.update/pom.xml
7 | scalariform.update/site.xml
8 | docs/source/conf.py
9 | scalariform/META-INF/MANIFEST.MF
10 | scalariform/src/main/scala/scalariform/package.scala
11 | README.rst
12 |
--------------------------------------------------------------------------------
/cli/.project:
--------------------------------------------------------------------------------
1 |
2 | cli
3 |
4 |
5 | org.scala-ide.sdt.core.scalabuilder
6 |
7 |
8 |
9 | org.scala-ide.sdt.core.scalanature
10 | org.eclipse.jdt.core.javanature
11 |
12 |
--------------------------------------------------------------------------------
/misc/.project:
--------------------------------------------------------------------------------
1 |
2 | misc
3 |
4 |
5 | org.scala-ide.sdt.core.scalabuilder
6 |
7 |
8 |
9 | org.scala-ide.sdt.core.scalanature
10 | org.eclipse.jdt.core.javanature
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | lib_managed/
3 | src_managed/
4 | project/boot/
5 | bin/
6 | .scala_dependencies
7 | core/target/
8 | core/lib_managed/
9 | core/src_managed/
10 | gui/target/
11 | gui/lib_managed/
12 | gui/src_managed/
13 | corpusscan/target/
14 | corpusscan/lib_managed/
15 | corpusscan/src_managed/
16 | docs/build
17 | .settings
18 | nohup.out
19 | .history
20 | .cache
21 | .idea/
--------------------------------------------------------------------------------
/project/.project:
--------------------------------------------------------------------------------
1 |
2 | default-719b99
3 |
4 |
5 | org.scala-ide.sdt.core.scalabuilder
6 |
7 |
8 |
9 | org.scala-ide.sdt.core.scalanature
10 | org.eclipse.jdt.core.javanature
11 |
12 |
--------------------------------------------------------------------------------
/scalariform/.project:
--------------------------------------------------------------------------------
1 |
2 | scalariform
3 |
4 |
5 | org.scala-ide.sdt.core.scalabuilder
6 |
7 |
8 |
9 | org.scala-ide.sdt.core.scalanature
10 | org.eclipse.jdt.core.javanature
11 |
12 |
13 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/utils/BooleanLang.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | object BooleanLang {
4 |
5 | def not(b: Boolean) = !b
6 |
7 | class PimpedBoolean(b1: Boolean) {
8 | def and(b2: Boolean) = b1 && b2
9 | def or(b2: Boolean) = b1 || b2
10 | }
11 |
12 | implicit def boolean2PimpedBoolean(b: Boolean): PimpedBoolean = new PimpedBoolean(b)
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.6.markdown:
--------------------------------------------------------------------------------
1 | * FIX: Bug in parser prevented DOT characters inside type parameters (issue #44)
2 | * Newline no longer added for each function in `=> => =>` scenarios (issue #45)
3 | * Update build to sbt 0.13.7 and update java version validation (PR #42)
4 | * Rewrite -> into → when RewriteArrowSymbols is on (issue #34)
5 | * Sync maven build with sbt build (PR #22)
6 | * Add support for Scala 2.12 in the maven build (PR #20)
7 |
--------------------------------------------------------------------------------
/misc/src/main/scala/com/danieltrinh/scalariform/gui/SwingUtils.scala:
--------------------------------------------------------------------------------
1 | package scalariform.gui
2 |
3 | import javax.swing.event.ListSelectionListener
4 | import javax.swing.event.ListSelectionEvent
5 |
6 | object SwingUtils {
7 |
8 | implicit def fn2ListSelectionListener(handler: ListSelectionEvent ⇒ Unit): ListSelectionListener = new ListSelectionListener() {
9 | def valueChanged(e: ListSelectionEvent) = handler(e)
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/misc/src/main/scala/com/danieltrinh/scalariform/gui/Main.scala:
--------------------------------------------------------------------------------
1 | package scalariform.gui
2 |
3 | import scalariform.utils.Utils._
4 | import javax.swing.JFrame
5 |
6 | object Main {
7 |
8 | def main(args: Array[String]) {
9 | onSwingThread {
10 | val frame = new FormatterFrame
11 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
12 | frame.setSize(1280, 600)
13 | frame.setVisible(true)
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/scalariform.update/site.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Scalariform Update Site
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | resolvers += Classpaths.typesafeReleases
2 |
3 | resolvers += Classpaths.typesafeSnapshots
4 |
5 | addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.5.1")
6 |
7 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
8 |
9 | addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.3.0")
10 |
11 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.2.1")
12 |
13 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.13.0")
14 |
15 | retrieveManaged := true
--------------------------------------------------------------------------------
/scalariform.feature/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | scalariform.feature
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.pde.FeatureBuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.pde.FeatureNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/AbstractExpressionFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 |
5 | abstract class AbstractExpressionFormatterTest extends AbstractFormatterTest {
6 |
7 | type Result = Expr
8 |
9 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
10 |
11 | def parse(parser: ScalaParser) = parser.expr()
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/scalariform.update/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | scalariform.update
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.pde.UpdateSiteBuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.pde.UpdateSiteNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.5.markdown:
--------------------------------------------------------------------------------
1 | * FIX: Type formatter crash on multiline types
2 | * Track scalac parser -- allow trait-position parents to have parameter blocks
3 | * Sync changes to InferredSemicolonParser
4 | * FIX: Scaladoc formatting wasn't idempotent (issue #62)
5 | * Added "SpacesAroundMultiImports" option
6 | * Modified "AlignParameters" option to align by column -- see readme
7 | * Deprecated "PreserveDanglingCloseParenthesis" in favor of
8 | automatic parentheses level detection.
9 |
--------------------------------------------------------------------------------
/scalariform/notes/0.0.6.markdown:
--------------------------------------------------------------------------------
1 | * Lexer performance tweaks
2 | * FIX: whitespace in XML end tags (e.g. ``)
3 | * Tweak multiline case clause indentation
4 | * FIX: indentation problem with xml in StatSeq
5 | * Disallow staircase expression breaks before commas and colons
6 | * FIX: incorrect indentation within multiple param clauses
7 | * Improved formatting for case blocks
8 | * Command line tool learned `--encoding=` option
9 | * FIX: honour previously-ignored formatXml preference
10 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/utils/Trimmed.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | object Trimmed {
4 |
5 | def apply(prefix: String, infix: String, suffix: String): String = prefix + infix + suffix
6 |
7 | def unapply(s: String): Option[(String, String, String)] = {
8 | val (prefix, rest) = s span Character.isWhitespace
9 | val (revSuffix, revInfix) = rest.reverse span Character.isWhitespace
10 | Some(prefix, revInfix.reverse, revSuffix.reverse)
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/TokenType.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | case class TokenType(name: String, isXml: Boolean = false) {
4 |
5 | def isNewline = this == Tokens.NEWLINE || this == Tokens.NEWLINES
6 |
7 | def isKeyword = Tokens.KEYWORDS contains this
8 |
9 | def isComment = Tokens.COMMENTS contains this
10 |
11 | def isId = Tokens.IDS contains this
12 |
13 | def isLiteral = Tokens.LITERALS contains this
14 |
15 | override lazy val toString = name
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/scalariform/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Bundle-ManifestVersion: 2
3 | Bundle-Name: Scalariform
4 | Bundle-SymbolicName: scalariform
5 | Bundle-Version: 0.1.8.qualifier
6 | Require-Bundle: org.scala-lang.scala-library,
7 | org.scala-lang.modules.scala-xml
8 | Bundle-ClassPath: .
9 | Export-Package: scalariform,
10 | scalariform.astselect,
11 | scalariform.formatter,
12 | scalariform.formatter.preferences,
13 | scalariform.lexer,
14 | scalariform.parser,
15 | scalariform.utils
16 | Bundle-RequiredExecutionEnvironment: J2SE-1.5
17 |
--------------------------------------------------------------------------------
/scalariform/notes/0.0.7.markdown:
--------------------------------------------------------------------------------
1 | * Rewrite parser; formatter is now ~60% faster
2 | * Add IndentPackageBlocks formatting preference
3 | * Allow newline before self type declaration
4 | * FIX: avoid abutting `@` and an operator, otherwise it merges into a single identifer
5 | * FIX: formatting for newline between `private[foo]` and trait/class/def etc
6 | * Update parser to match changes from Scala trac #3672 (types on implicit parameters in function expressions)
7 | * FIX: avoid hash and operator merging (e.g. `b[c# ::[d]]`)
8 | * Tweaks to else clause formatting
9 |
--------------------------------------------------------------------------------
/CONTRIBUTORS:
--------------------------------------------------------------------------------
1 | Scalariform is maintained by Matt Russell (https://github.com/mdr/scalariform).
2 |
3 | * A command line option to read a list of files was contributed by Olivier Michallat (https://github.com/olim7t).
4 | * The Maven formatter plugin was written by Adam Crain (https://github.com/jadamcrain).
5 | * Better Vim integration via a command line option to return the input unchanged on parse error was contributed by Oliver Braun (https://github.com/obcode).
6 | * CompactControlReadability patch by Owein Reese (https://github.com/wheaties) and Rose Toomey (https://github.com/rktoomey)
7 |
--------------------------------------------------------------------------------
/scalariform.feature/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | scalariform.feature
7 | eclipse-feature
8 | 0.1.8-SNAPSHOT
9 |
10 | scalariform.parent
11 | org.scalariform
12 | 0.1.8-SNAPSHOT
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/scalariform.update/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | scalariform.update
7 | eclipse-update-site
8 | 0.1.8-SNAPSHOT
9 |
10 | scalariform.parent
11 | com.danieltrinh
12 | 0.1.8-SNAPSHOT
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.2.markdown:
--------------------------------------------------------------------------------
1 | * Revamp command-line tool with more intuitive behaviour
2 | * Add `--quiet`, `--recurse`, `--stdin`, `--stdout` options to command-line tool
3 | * FIX: Scaladoc comment formatting could break nested comments (issue #36)
4 | * Tidy up, optimise lexer code
5 | * FIX: Parse `5.f`, `5.d` as floating points, unless in Scala 2.11+ mode
6 | * FIX: Bug with line-per-annotation style
7 | * Add support for String interpolation
8 | * Add support for macros
9 | * Add `--scalaVersion=` flag to command-line tool
10 | * Support `expr[T1, T2][T3, T4]` and `g()[String]` syntaxes
11 | * Fix AST selection for prefix expression
12 |
--------------------------------------------------------------------------------
/formatterPreferences.properties:
--------------------------------------------------------------------------------
1 | #Scalariform formatter preferences
2 | #Fri Apr 01 21:09:37 BST 2011
3 | alignParameters=true
4 | compactStringConcatenation=false
5 | indentPackageBlocks=true
6 | formatXml=true
7 | preserveSpaceBeforeArguments=false
8 | doubleIndentClassDeclaration=false
9 | rewriteArrowSymbols=false
10 | alignSingleLineCaseStatements=true
11 | alignSingleLineCaseStatements.maxArrowIndent=40
12 | spaceBeforeColon=false
13 | spaceInsideBrackets=false
14 | spaceInsideParentheses=false
15 | preserveDanglingCloseParenthesis=false
16 | indentSpaces=2
17 | indentLocalDefs=false
18 | spacesWithinPatternBinders=true
19 | spacesAroundMultiImports=true
--------------------------------------------------------------------------------
/scalariform/notes/0.0.8.markdown:
--------------------------------------------------------------------------------
1 | * FIX: Correctly handle use of `+`/`-` as type parameters in defs
2 | * Add Maven formatter plugin (contributed by Adam Crain -- [Adam Crain][1])
3 | * FIX: Bug with lexing `"""` at end of text
4 | * Add `AlignSingleLineCaseStatements` preferences to align the arrows of consecutive single-line case statements
5 | * Add `IndentLocalDefs` preference to indent local methods an extra level
6 | * Track parser changes in Scala 2.9:
7 | * Type variables in a constructor pattern match
8 | * Generalised catch clause
9 | * Mirror code reorganisation of scala.tools.nsc.ast.parser.Parsers
10 |
11 | [1]: https://github.com/jadamcrain
12 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.0.markdown:
--------------------------------------------------------------------------------
1 | * Add forgiving mode to lexer
2 | * Add `SpaceInsideParentheses` and `SpaceInsideBrackets` preferences (issue #14)
3 | * Ability to import/export preferences as properties; `--preferencesFile=` command-line option
4 | * FIX: incorrect indent behaviour for finally block after a catch block
5 | * Add `SpacesWithinPatternBinders` preference (issue #15)
6 | * Add `MultilineScaladocCommentsStartOnFirstLine` preference (issue #16)
7 | * FIX: infinite loop in lexer on malformed XML processing instructions / unparsed
8 | * Add IndentWithTabs preference (issue #17)
9 | * FIX: Fix incorrectly parsed command line argument (issue #20)
10 | * Update for 2.9.0
11 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/RewriteArrowsTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class RewriteArrowsTest extends AbstractExpressionFormatterTest {
9 |
10 | {
11 | implicit val formattingPreferences = FormattingPreferences.setPreference(RewriteArrowSymbols, true)
12 |
13 | "(a: Int) => 3" ==> "(a: Int) ⇒ 3"
14 | "for (i <- 1 to 10) yield i" ==> "for (i ← 1 to 10) yield i"
15 | "cache += k -> f(k)" ==> "cache += k → f(k)"
16 | }
17 |
18 | override val debug = false
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/utils/CaseClassReflector.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | trait CaseClassReflector extends Product {
4 |
5 | def getFields: List[(String, Any)] = {
6 | val names = getClass.getDeclaredFields map { _.getName }
7 | names.toList zip productIterator.toList
8 | }
9 |
10 | private def getFieldsOld: List[(String, Any)] = {
11 | var fieldValueToName: Map[Any, String] = Map()
12 | for (field ← getClass.getDeclaredFields) {
13 | field.setAccessible(true)
14 | fieldValueToName += (field.get(this) -> field.getName)
15 | }
16 | productIterator.toList map { value ⇒ fieldValueToName(value) -> value }
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/ScriptFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 |
6 | // format: OFF
7 | class ScriptFormatterTest extends AbstractFormatterTest {
8 |
9 | """println("Hello world")""" ==> """println("Hello world")"""
10 |
11 | """def sayHi() { println("Hello")
12 | |}""" ==>
13 | """def sayHi() {
14 | | println("Hello")
15 | |}"""
16 |
17 | override val debug = false
18 |
19 | type Result = CompilationUnit
20 |
21 | def parse(parser: ScalaParser) = parser.scriptBody()
22 |
23 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/utils/TrimmedTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | import org.scalatest.FlatSpec
4 | import org.scalatest.matchers.ShouldMatchers
5 |
6 | // format: +preserveSpaceBeforeArguments
7 | class TrimmedTest extends FlatSpec with ShouldMatchers {
8 |
9 | it should "just work" in {
10 |
11 | Trimmed.unapply("").get should equal ("", "", "")
12 | Trimmed.unapply("foo").get should equal ("", "foo", "")
13 | Trimmed.unapply(" foo").get should equal (" ", "foo", "")
14 | Trimmed.unapply(" foo ").get should equal (" ", "foo", " ")
15 | Trimmed.unapply(" foo bar ").get should equal (" ", "foo bar", " ")
16 | Trimmed.unapply(" ").get should equal (" ", "", "")
17 |
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/scalariform.update/web/site.css:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/scalariform/notes/0.0.9.markdown:
--------------------------------------------------------------------------------
1 | * Add support for AST selection
2 | * Improve basic formatting of Scaladoc comments
3 | * Improve stairway indenting of argument lists, infix exprs
4 | * Add preference `PreserveDanglingCloseParenthesis` to keep newlines before a dangling right paren (issue #6)
5 | * Allow single-expression case clauses to be formatted adjacent to the case arrow (issue #7)
6 | * Improve formatting after a single-line comment (issue #8)
7 | * Allow missing param types for `-Yinfer-argument-types` (issue #9)
8 | * FIX: erroneous spaces after `type` (issue #10)
9 | * Add `--forceOutput` command-line argument to pass input through untouched if there is a parse error (#issue 11/12)
10 | * Pull out separate, non-`System.exit()`ing `process` method separate to `main()` (issue #13)
11 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/ScalaLexerReader.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.Tokens._
4 | import scala.util.parsing.input._
5 |
6 | class ScalaLexerReader(val tokens: List[Token]) extends Reader[Token] {
7 |
8 | def first: Token = tokens.head
9 |
10 | def rest: Reader[Token] = new ScalaLexerReader(tokens.tail)
11 |
12 | def pos: Position = new ScalaLexerPosition(first)
13 |
14 | def atEnd: Boolean = tokens.isEmpty || tokens.head.tokenType == EOF
15 |
16 | private class ScalaLexerPosition(token: Token) extends Position {
17 |
18 | def line: Int = -1
19 |
20 | def column: Int = -1
21 |
22 | protected def lineContents: String = token.rawText
23 |
24 | override def longString = lineContents
25 |
26 | }
27 |
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/HiddenToken.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | abstract sealed class HiddenToken(val token: Token) {
4 |
5 | lazy val newlineful = token.text contains '\n'
6 |
7 | def text = token.text
8 |
9 | def rawText = token.rawText
10 |
11 | }
12 |
13 | case class Whitespace(override val token: Token) extends HiddenToken(token)
14 |
15 | sealed abstract class Comment(token: Token) extends HiddenToken(token)
16 |
17 | object Comment {
18 |
19 | def unapply(comment: Comment) = Some(comment.token)
20 |
21 | }
22 |
23 | case class SingleLineComment(override val token: Token) extends Comment(token)
24 |
25 | case class MultiLineComment(override val token: Token) extends Comment(token)
26 |
27 | case class ScalaDocComment(override val token: Token) extends Comment(token)
28 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/utils/Range.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | import scala.math.Ordering
4 |
5 | case class Range(offset: Int, length: Int) {
6 |
7 | def contains(other: Range) = other.offset >= offset && other.offset + other.length <= offset + length
8 |
9 | def strictlyContains(other: Range) = (this contains other) && this.length > other.length
10 |
11 | /**
12 | * @return the smallest range that contains both this and other
13 | */
14 | def mergeWith(other: Range) = {
15 | val List(earliest, latest) = List(this, other) sortBy (_.offset)
16 | Range(earliest.offset, latest.offset - earliest.offset + latest.length)
17 | }
18 |
19 | def intersects(other: Range) =
20 | !(other.offset >= offset + length || other.offset + other.length - 1 < offset)
21 |
22 | def expandLeft(n: Int): Range = Range(offset - n, length + n)
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/parser/ScalaParserTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.parser
2 |
3 | import scalariform.lexer._
4 | import scalariform.parser._
5 |
6 | import org.scalatest.FlatSpec
7 | import org.scalatest.matchers.ShouldMatchers
8 |
9 | // format: +preserveSpaceBeforeArguments
10 | class ScalaParserTest extends FlatSpec with ShouldMatchers {
11 |
12 | "Parser" should "not throw exception" in {
13 | // parseExpression("class X")
14 | // parseExpression("class X { }")
15 | // parseExpression("class X { def method(n: Int) = 42 }")
16 | parseExpression {
17 | """
18 | class C(@annotation(foo = {1 + 2}) n: Int)
19 | """
20 | }
21 |
22 | }
23 |
24 | private def parseExpression(s: String) = {
25 | val tokens = ScalaLexer.tokenise(s)
26 | val scalaParser = new ScalaParser(tokens.toArray)
27 | scalaParser.compilationUnit()
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/cli/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/LexerMode.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | sealed trait LexerMode
4 |
5 | class ScalaMode extends LexerMode {
6 |
7 | private var braceNestLevel: Int = 0
8 |
9 | def nestBrace() { braceNestLevel += 1 }
10 |
11 | def unnestBrace(): Int = {
12 | braceNestLevel -= 1
13 | braceNestLevel
14 | }
15 |
16 | }
17 |
18 | class XmlMode extends LexerMode {
19 |
20 | var isTagMode: Boolean = false
21 |
22 | var tagState: TagState = Normal
23 |
24 | private var tagNestLevel: Int = 0
25 |
26 | def nestTag() { tagNestLevel += 1 }
27 |
28 | def unnestTag(): Int = {
29 | tagNestLevel -= 1
30 | tagNestLevel
31 | }
32 |
33 | def nestingLevel = tagNestLevel
34 |
35 | }
36 |
37 | class StringInterpolationMode(val multiLine: Boolean) extends LexerMode {
38 |
39 | var initialSegment = true
40 |
41 | var interpolationVariable = false
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/cli/src/main/scala/com/danieltrinh/scalariform/commandline/ScalaFileWalker.scala:
--------------------------------------------------------------------------------
1 | package scalariform.commandline
2 |
3 | import java.io.File
4 | import java.util.{ ArrayList, Collection }
5 | import scala.collection.JavaConversions._
6 | import scala.collection.mutable.Buffer
7 |
8 | import org.apache.commons.io._
9 | import org.apache.commons.io.filefilter._
10 |
11 | object ScalaFileWalker extends DirectoryWalker(TrueFileFilter.INSTANCE, FileFilterUtils.suffixFileFilter(".scala"), -1) {
12 |
13 | def findScalaFiles(path: String): List[File] = findScalaFiles(new File(path))
14 |
15 | def findScalaFiles(path: File): List[File] = {
16 | val results = new ArrayList[File]
17 | walk(path, results)
18 | results.toList
19 | }
20 |
21 | override protected def handleFile(file: File, depth: Int, results: Collection[_]) {
22 | val castResults = results.asInstanceOf[Collection[File]]
23 | castResults.add(file)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/scalariform/notes/0.1.1.markdown:
--------------------------------------------------------------------------------
1 | * FIX: Leave PCDATA whitespace untouched inside a single-line XML tag (issue #27)
2 | * FIX: indent for `indentLocalDefs` on first line of function block (issue #24)
3 | * `ParenExpr` now allows newline after opening paren (issue #18)
4 | * FIX: spurious indentation in staggered dot expressions (issue #25)
5 | * Preserve newline before annotations (issue #28)
6 | * Add option to support `CompactControlReadability` style (issue #22) (thanks to by Owein Reese (https://github.com/wheaties) and Rose Toomey (https://github.com/rktoomey) for the patch
7 | * Preserve newline before anonymous function argument (issue #21)
8 | * Allow one-line anonymous function blocks
9 | * Fix parser crash on argument-less constructor annotations
10 | * Add `PlaceScaladocAsterisksBeneathSecondAsterisk` preference to conform to recommended Scaladoc style (issue #30)
11 | * FIX: Removal of space causing token merge in varargs and unary ops (http://scala-ide-portfolio.assembla.com/spaces/scala-ide/tickets/1000601)
12 | * Switch to sbt 0.11 build
13 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/AnnotationFormatter.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.utils._
5 | import scalariform.lexer._
6 | import scalariform.formatter.preferences._
7 |
8 | trait AnnotationFormatter { self: HasFormattingPreferences with TypeFormatter with ExprFormatter ⇒
9 |
10 | def format(annotation: Annotation)(implicit formatterState: FormatterState): FormatResult = {
11 | val Annotation(atToken: Token, annotationType: Type, argumentExprss: List[ArgumentExprs], newlineOption: Option[Token]) = annotation
12 | var formatResult: FormatResult = NoFormatResult
13 |
14 | formatResult = formatResult.before(annotationType.firstToken, Compact)
15 | formatResult ++= format(annotationType)
16 | for (argumentExprs ← argumentExprss)
17 | formatResult ++= format(argumentExprs)._1
18 | for (newline ← newlineOption)
19 | formatResult = formatResult.formatNewline(newline, Compact) // TODO: rethink
20 | formatResult
21 | }
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/MiscFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser.{FullDefOrDcl, ScalaParser}
4 |
5 | class MiscFormatterTest extends AbstractFormatterTest {
6 |
7 | """class Foo(
8 | | bar: String,
9 | | baz: String
10 | |)""" ==>
11 | """class Foo(
12 | | bar: String,
13 | | baz: String
14 | |)"""
15 |
16 | """class Foo(
17 | | bar: String,
18 | | baz: String)""" ==>
19 | """class Foo(
20 | | bar: String,
21 | | baz: String
22 | |)"""
23 |
24 | """class Foo(
25 | |)""" ==>
26 | """class Foo()"""
27 |
28 | """class a()""" ==>
29 | """class a()"""
30 |
31 | """def a()""" ==>
32 | """def a()"""
33 |
34 | """class a(b: Int)""" ==>
35 | """class a(b: Int)"""
36 |
37 | """def a(b: Int)""" ==>
38 | """def a(b: Int)"""
39 |
40 | def parse(parser: ScalaParser) = parser.nonLocalDefOrDcl()
41 |
42 | type Result = FullDefOrDcl
43 |
44 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0))
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/scalariform/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | org.scalariform
6 | scalariform
7 | 0.1.8-SNAPSHOT
8 | eclipse-plugin
9 |
10 | scalariform.parent
11 | org.scalariform
12 | 0.1.8-SNAPSHOT
13 |
14 |
15 |
16 |
17 |
18 |
19 | org.eclipse.tycho
20 | tycho-compiler-plugin
21 | ${tycho.version}
22 |
23 |
24 | **/*.scala
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2010 Matthew D. Russell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and
10 | to permit persons to whom the Software is furnished to do so,
11 | subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
20 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/Chars.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scala.annotation.switch
4 |
5 | object Chars {
6 |
7 | /**
8 | * @see scala.reflect.internal.Chars.isOperatorPart
9 | */
10 | def isOperatorPart(c: Char): Boolean =
11 | (c: @switch) match {
12 | case '~' | '!' | '@' | '#' | '%' |
13 | '^' | '*' | '+' | '-' | '<' |
14 | '>' | '?' | ':' | '=' | '&' |
15 | '|' | '/' | '\\' ⇒ true
16 | case c ⇒ isSpecial(c)
17 | }
18 |
19 | /**
20 | * @see scala.reflect.internal.Chars.isSpecial
21 | */
22 | def isSpecial(c: Char) = {
23 | val chtp = Character.getType(c)
24 | chtp == Character.MATH_SYMBOL.toInt || chtp == Character.OTHER_SYMBOL.toInt
25 | }
26 |
27 | /**
28 | * @see scala.reflect.internal.Chars.isIdentifierStart
29 | */
30 | def isIdentifierStart(c: Char) =
31 | (c == '_') || (c == '$') || Character.isUnicodeIdentifierStart(c)
32 |
33 | /**
34 | * @see scala.reflect.internal.Chars.isIdentifierPart
35 | */
36 | def isIdentifierPart(c: Char) =
37 | (c == '$') || Character.isUnicodeIdentifierPart(c) && c != CharConstants.SU
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/FormatterDirectiveParser.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 | import scala.util.parsing.input._
3 | import scala.util.parsing.combinator._
4 |
5 | class FormatterDirectiveParser extends JavaTokenParsers {
6 |
7 | val directives: Parser[List[FormatterDirective]] = "format:" ~>
8 | ("ON" ^^^ List(ToggleFormatting(true)) | "OFF" ^^^ List(ToggleFormatting(false)) | repsep(toggle, ","))
9 |
10 | val plusOrMinus = "+" ^^^ true | "-" ^^^ false
11 |
12 | val toggle = plusOrMinus ~ ident ^^ { case onOrOff ~ optionName ⇒ ToggleOption(onOrOff, optionName) }
13 |
14 | def getDirectives(s: String) = parse(directives, s) getOrElse Nil
15 | }
16 |
17 | object FormatterDirectiveParser {
18 | def getDirectives(s: String): List[FormatterDirective] = {
19 | val index = s indexOf "format:"
20 | if (index == -1)
21 | Nil
22 | else
23 | new FormatterDirectiveParser().getDirectives(s.substring(index))
24 | }
25 | }
26 |
27 | sealed trait FormatterDirective
28 |
29 | case class ToggleOption(onOrOff: Boolean, optionName: String) extends FormatterDirective
30 | case class ToggleFormatting(onOrOff: Boolean) extends FormatterDirective
31 |
--------------------------------------------------------------------------------
/misc/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/FormatterState.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.lexer.Token
4 |
5 | case class FormatterState(
6 | indentLevel: Int = 0,
7 | indentRelativeToTokenOption: Option[Token] = None,
8 | val inSingleLineBlock: Boolean = false,
9 | val expressionBreakHappened: Boolean = false
10 | ) {
11 |
12 | private val nextIndentLevel = indentLevel + 1
13 |
14 | def indent: FormatterState = indent(1)
15 |
16 | def indent(n: Int): FormatterState = copy(indentLevel = indentLevel + n)
17 |
18 | def alignWithToken(token: Token): FormatterState = copy(indentLevel = 0, indentRelativeToTokenOption = Some(token))
19 |
20 | def nextIndentLevelInstruction = EnsureNewlineAndIndent(nextIndentLevel, relativeTo = indentRelativeToTokenOption)
21 |
22 | def currentIndentLevelInstruction = EnsureNewlineAndIndent(indentLevel, relativeTo = indentRelativeToTokenOption)
23 |
24 | def indentForExpressionBreak = indent.copy(expressionBreakHappened = true)
25 |
26 | def indentForExpressionBreakIfNeeded = if (expressionBreakHappened) this else indent.copy(expressionBreakHappened = true)
27 |
28 | def clearExpressionBreakHappened = copy(expressionBreakHappened = false)
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/FunctionFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser.{CompilationUnit, ScalaParser}
4 |
5 | // format: OFF
6 | class FunctionFormatterTest extends AbstractFormatterTest {
7 |
8 | "val f = x => x" ==> "val f = x => x"
9 | "val f: Int => Int => Unit = a => b => ()" ==> "val f: Int => Int => Unit = a => b => ()"
10 |
11 | "{ ctx => j => () }" ==> "{ ctx => j => () }"
12 | "fun { ctx => j => () }" ==> "fun { ctx => j => () }"
13 | "Thing() { ctx => j => () }" ==> "Thing() { ctx => j => () }"
14 |
15 | """{ ctx =>
16 | | ???
17 | |}""".stripMargin ==>
18 | """{ ctx =>
19 | | ???
20 | |}""".stripMargin
21 |
22 | """{ ctx => j =>
23 | | ???
24 | |}""".stripMargin ==>
25 | """{ ctx => j =>
26 | | ???
27 | |}""".stripMargin
28 |
29 | """val x = { ctx => j =>
30 | | one()
31 | | two()
32 | |}""".stripMargin ==>
33 | """val x = { ctx => j =>
34 | | one()
35 | | two()
36 | |}""".stripMargin
37 |
38 | override val debug = false
39 |
40 | type Result = CompilationUnit
41 |
42 | def parse(parser: ScalaParser) = parser.compilationUnitOrScript()
43 |
44 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/Token.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.Tokens._
4 | import scalariform.utils.Range
5 |
6 | /**
7 | * A token of Scala source.
8 | *
9 | * @param text -- the text associated with the token after unicode escaping
10 | * @param rawText -- the text associated with the token before unicode escaping
11 | */
12 | case class Token(tokenType: TokenType, text: String, offset: Int, rawText: String) {
13 |
14 | private[lexer] var associatedWhitespaceAndComments_ : HiddenTokens = null
15 |
16 | private[lexer] var containsUnicodeEscape = false
17 |
18 | def associatedWhitespaceAndComments: HiddenTokens = associatedWhitespaceAndComments_
19 |
20 | def length = rawText.length
21 |
22 | def range = Range(offset, length)
23 |
24 | def lastCharacterOffset = offset + length - 1
25 |
26 | def isScalaDocComment = tokenType == MULTILINE_COMMENT && text.startsWith("/**") && text != "/**/"
27 |
28 | def isNewline = tokenType.isNewline
29 |
30 | @deprecated(message = "Use text instead" /*, since = "0.1.2"*/ )
31 | def getText = text
32 |
33 | @deprecated(message = "Use offset instead" /*, since = "0.1.2"*/ )
34 | def startIndex = offset
35 |
36 | @deprecated(message = "Use lastCharacterOffset instead" /*, since = "0.1.2"*/ )
37 | def stopIndex = lastCharacterOffset
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/StringInterpolationFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class StringInterpolationFormatterTest extends AbstractExpressionFormatterTest {
9 |
10 | implicit val scalaVersion: String = "2.10.0"
11 |
12 | s"foo".text ==> s"foo".text
13 | s"".text ==> s"".text
14 | s"my name is $name".text ==> s"my name is $name".text
15 | s"my name is $this".text ==> s"my name is $this".text
16 | """s"my name is ${bob}"""" ==> """s"my name is ${bob}""""
17 | """s"my name is ${ person.name }"""" ==> """s"my name is ${person.name}""""
18 |
19 | """s"my name is ${
20 | |bob}"""" ==>
21 | """s"my name is ${
22 | | bob
23 | |}""""
24 |
25 | """s"my name is ${
26 | |val person = getPerson()
27 | |person.getName}"""" ==>
28 | """s"my name is ${
29 | | val person = getPerson()
30 | | person.getName
31 | |}""""
32 |
33 | s"""foo""".text ==> s"""foo""".text
34 | s"""""".text ==> s"""""".text
35 | s"""my name is $name""".text ==> s"""my name is $name""".text
36 | "s\"\"\"my name is ${bob}\"\"\"" ==> "s\"\"\"my name is ${bob}\"\"\""
37 | "s\"\"\"my name is ${ person.name }\"\"\"" ==> "s\"\"\"my name is ${person.name}\"\"\""
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/PackageFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class PackageFormatterTest extends AbstractFormatterTest {
9 |
10 | override val debug = false
11 |
12 | type Result = CompilationUnit
13 |
14 | def parse(parser: ScalaParser) = parser.compilationUnit()
15 |
16 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
17 |
18 | "" ==> ""
19 |
20 | "package foo . bar . baz" ==> "package foo.bar.baz"
21 |
22 | """package foo {
23 | |package bar {
24 | |class Baz
25 | |}
26 | |}""" ==>
27 | """package foo {
28 | | package bar {
29 | | class Baz
30 | | }
31 | |}"""
32 |
33 | "package foo" ==> "package foo"
34 |
35 | """/* foo */
36 | |package wibble""" ==>
37 | """/* foo */
38 | |package wibble"""
39 |
40 | """package a
41 | |{}""" ==>
42 | """package a {}"""
43 |
44 | """package a {}
45 | |""" ==>
46 | """package a {}
47 | |"""
48 |
49 | {
50 |
51 | implicit val formattingPreferences = FormattingPreferences.setPreference(IndentPackageBlocks, false)
52 |
53 | """package foo {
54 | |package bar {
55 | |class Baz
56 | |}
57 | |}""" ==>
58 | """package foo {
59 | |package bar {
60 | |class Baz
61 | |}
62 | |}"""
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/scalariform/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/ScalaVersions.scala:
--------------------------------------------------------------------------------
1 | package scalariform
2 |
3 | import scala.util.Properties
4 | import scalariform.utils.Utils._
5 | import scala.math.Ordering
6 |
7 | object ScalaVersion {
8 |
9 | private val VersionPattern = """(\d+)\.(\d+)\.(.*)""".r
10 |
11 | def parseOrDefault(s: String): ScalaVersion = parse(s).getOrElse(ScalaVersions.DEFAULT)
12 |
13 | def parse(s: String): Option[ScalaVersion] =
14 | s match {
15 | case VersionPattern(majorStr, minorStr, extra) ⇒
16 | for {
17 | major ← majorStr.toIntOpt
18 | minor ← minorStr.toIntOpt
19 | } yield ScalaVersion(major, minor, extra)
20 | case _ ⇒
21 | None
22 | }
23 |
24 | }
25 |
26 | case class ScalaVersion(major: Int, minor: Int, extra: String = "") extends Ordered[ScalaVersion] {
27 |
28 | private def majorMinor = (major, minor)
29 |
30 | def compare(that: ScalaVersion) = Ordering[(Int, Int)].compare(this.majorMinor, that.majorMinor)
31 |
32 | override def toString = major + "." + minor + "." + extra
33 |
34 | }
35 |
36 | object ScalaVersions {
37 |
38 | val Scala_2_11 = ScalaVersion.parse("2.11.0").get
39 | val Scala_2_10 = ScalaVersion.parse("2.10.0").get
40 | val Scala_2_9 = ScalaVersion.parse("2.9.2").get
41 | val Scala_2_8 = ScalaVersion.parse("2.8.1").get
42 |
43 | lazy val DEFAULT_VERSION = Properties.scalaPropOrElse("version.number", "2.9.2")
44 |
45 | lazy val DEFAULT = ScalaVersion.parse(DEFAULT_VERSION).get
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/RedundantSemicolonDetector.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.utils.Range
4 | import scalariform.utils.Utils._
5 | import scalariform.utils.TextEdit
6 | import scalariform.utils.TextEditProcessor
7 | import scalariform.ScalaVersions
8 |
9 | object RedundantSemicolonDetector {
10 |
11 | /**
12 | * @return all semicolons in the source that could safely be removed without changing the meaning
13 | * of the program.
14 | */
15 | def findRedundantSemis(source: String, scalaVersion: String = ScalaVersions.DEFAULT_VERSION): List[Token] = {
16 |
17 | def isRedundant(semi: Token, index: Int): Boolean = {
18 | val sourceWithoutSemi = deleteRange(source, semi.range)
19 | val tokensWithoutSemi = ScalaLexer.tokenise(sourceWithoutSemi, forgiveErrors = true, scalaVersion = scalaVersion)
20 | val replacementToken = tokensWithoutSemi(index)
21 | replacementToken.isNewline || replacementToken.tokenType == Tokens.EOF || replacementToken.tokenType == Tokens.RBRACE
22 | }
23 |
24 | ScalaLexer.tokenise(source, forgiveErrors = true, scalaVersion = scalaVersion).zipWithIndex.collect {
25 | case (token, index) if token.tokenType == Tokens.SEMI && isRedundant(token, index) ⇒ token
26 | }
27 |
28 | }
29 |
30 | def removeRedundantSemis(s: String): String =
31 | TextEditProcessor.runEdits(s, getEditsToRemoveRedundantSemis(s))
32 |
33 | def getEditsToRemoveRedundantSemis(s: String): List[TextEdit] =
34 | findRedundantSemis(s).map(_.range).map(TextEdit.delete)
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/ModeStack.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scala.collection.mutable.Stack
4 |
5 | /**
6 | * Keeping track of nesting level of XML within Scala.
7 | */
8 | trait ModeStack { self: ScalaLexer ⇒
9 |
10 | private val modeStack = new Stack[LexerMode]
11 |
12 | private var currentRegionStart: Int = 0
13 |
14 | modeStack.push(new ScalaMode)
15 |
16 | protected def popMode() {
17 | val mode = modeStack.pop()
18 | }
19 |
20 | protected def isRootMode = modeStack.size == 1
21 |
22 | protected def switchToScalaModeAndFetchToken() {
23 | switchToScalaMode()
24 | fetchScalaToken()
25 | }
26 |
27 | protected def switchToXmlModeAndFetchToken() {
28 | modeStack.push(new XmlMode)
29 | fetchXmlToken()
30 | }
31 |
32 | protected def switchToStringInterpolationMode(multiLine: Boolean) {
33 | modeStack.push(new StringInterpolationMode(multiLine))
34 | }
35 |
36 | protected def switchToScalaMode() {
37 | modeStack.push(new ScalaMode)
38 | }
39 |
40 | protected def isStringInterpolationMode = modeStack.head.isInstanceOf[StringInterpolationMode]
41 |
42 | protected def isXmlMode = modeStack.head.isInstanceOf[XmlMode]
43 |
44 | protected def isScalaMode = modeStack.head.isInstanceOf[ScalaMode]
45 |
46 | protected def xmlMode: XmlMode = modeStack.head.asInstanceOf[XmlMode]
47 |
48 | protected def scalaMode: ScalaMode = modeStack.head.asInstanceOf[ScalaMode]
49 |
50 | protected def stringInterpolationMode: StringInterpolationMode = modeStack.head.asInstanceOf[StringInterpolationMode]
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/HiddenTokens.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.Tokens._
4 | import scalariform.utils.Utils
5 |
6 | object NoHiddenTokens extends HiddenTokens(Nil)
7 |
8 | case class HiddenTokens(tokens: List[HiddenToken]) extends Iterable[HiddenToken] {
9 |
10 | def removeInitialWhitespace = new HiddenTokens(tokens.dropWhile(_.isInstanceOf[Whitespace]))
11 |
12 | def iterator: Iterator[HiddenToken] = tokens.iterator
13 |
14 | val comments: List[Comment] = tokens collect { case comment: Comment ⇒ comment }
15 |
16 | val scalaDocComments: List[ScalaDocComment] = tokens collect { case comment @ ScalaDocComment(_) ⇒ comment }
17 |
18 | val whitespaces: List[Whitespace] = tokens collect { case whitespace @ Whitespace(_) ⇒ whitespace }
19 |
20 | def firstTokenOption = tokens.headOption
21 |
22 | def lastTokenOption = tokens.lastOption
23 |
24 | def containsNewline = text contains '\n'
25 |
26 | def containsComment = comments.nonEmpty
27 |
28 | def containsUnicodeEscape: Boolean = {
29 | for (token ← tokens if token.token.containsUnicodeEscape)
30 | return true
31 | false
32 | }
33 |
34 | lazy val text: String = {
35 | val sb = new StringBuilder
36 | for (token ← tokens) sb.append(token.text)
37 | // tokens.flatMap(_.token.text)(scala.collection.breakOut)
38 | sb.toString
39 | }
40 | lazy val rawText = tokens.map(_.token.rawText).mkString
41 |
42 | def rawTokens = tokens.map(_.token)
43 |
44 | def offset = tokens.head.token.offset
45 |
46 | def lastCharacterOffset = tokens.last.token.lastCharacterOffset
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/lexer/RedundantSemicolonDetectorTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform._
4 | import scalariform.lexer.Tokens._
5 | import org.scalatest.FlatSpec
6 | import org.scalatest.matchers.ShouldMatchers
7 | import org.scalatest.TestFailedException
8 | import org.scalatest.TestPendingException
9 | import scalariform.utils.Utils._
10 |
11 | class RedundantSemicolonDetectorTest extends FlatSpec with ShouldMatchers {
12 |
13 | implicit def stringToCheckable(s: String)(implicit scalaVersion: String = ScalaVersions.DEFAULT_VERSION) =
14 | new { def check() = checkSemis(s, scalaVersion) }; // Expected redundant semicolons are indicated with <;>
15 |
16 | """
17 | class A {
18 | def foo = 42<;>
19 | def bar = 123; def baz = 1234
20 | }<;>
21 | """.check();
22 |
23 | """
24 | {
25 | println("Foo")<;>
26 | }
27 | """.check();
28 |
29 | """
30 | class A {
31 | for (
32 | x <- 1 to 10;
33 | y <- 1 to 10
34 | ) yield x + y<;>
35 | }
36 | """.check()
37 |
38 | {
39 | implicit val scalaVersion = "2.10.0";
40 | """
41 | s"my name is ${person.name<;>}"
42 | """.check
43 | }
44 |
45 | private def checkSemis(encodedSource: String, scalaVersion: String) {
46 | val ordinarySource = encodedSource.replace("<;>", ";")
47 | val semis = RedundantSemicolonDetector.findRedundantSemis(ordinarySource, scalaVersion)
48 | val encodedSourceAgain = semis.reverse.foldLeft(ordinarySource) { (s, semi) ⇒ replaceRange(s, semi.range, "<;>") }
49 | encodedSourceAgain should equal(encodedSource)
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/FormatterDirectiveParserTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import org.scalatest.FlatSpec
4 | import org.scalatest.matchers.ShouldMatchers
5 | import FormatterDirectiveParser.getDirectives
6 |
7 | // format: +preserveSpaceBeforeArguments
8 | class FormatterDirectiveParserTest extends FlatSpec with ShouldMatchers {
9 |
10 | it should "parse formatter ON/OFF instructions" in {
11 | "format: ON " ==> ToggleFormatting(true)
12 | "format: OFF" ==> ToggleFormatting(false)
13 | }
14 |
15 | it should "parse option toggle instructions" in {
16 | "format: +rewriteArrowSymbols" ==> ToggleOption(true, "rewriteArrowSymbols")
17 | "format: -rewriteArrowSymbols" ==> ToggleOption(false, "rewriteArrowSymbols")
18 | "format: -rewriteArrowSymbols, +spaceBeforeColon" ==> (ToggleOption(false, "rewriteArrowSymbols"), ToggleOption(true, "spaceBeforeColon"))
19 | }
20 |
21 | it should "parse despite surrounding junk" in {
22 | "// wibble wobble\nformat: OFF" ==> ToggleFormatting(false)
23 | "// wibble wobble\nformat: OFF\nwobblewobble" ==> ToggleFormatting(false)
24 | "// wibble wobble\nformat: OFFwobblewobble" ==> ToggleFormatting(false)
25 | "blahformat: -rewriteArrowSymbols, +spaceBeforeColon\nblah" ==> (ToggleOption(false, "rewriteArrowSymbols"), ToggleOption(true, "spaceBeforeColon"))
26 | }
27 |
28 | implicit def string2FormatTest(s: String): FormatTest = FormatTest(s.stripMargin)
29 |
30 | case class FormatTest(source: String) {
31 | def ==>(expectedDirectives: FormatterDirective*) {
32 | getDirectives(source) should be (expectedDirectives)
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/WhitespaceAndCommentsGrouper.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.Tokens._
4 | import scala.collection.mutable.ListBuffer
5 |
6 | class WhitespaceAndCommentsGrouper(lexer: ScalaLexer) extends Iterator[Token] {
7 |
8 | private var nextToken = lexer.next()
9 |
10 | private var ended = false
11 |
12 | private var hiddenTokens: HiddenTokens = _
13 |
14 | def getHiddenTokens = hiddenTokens
15 |
16 | def hasNext = !ended
17 |
18 | private[lexer] def text = lexer.text
19 |
20 | def next() = {
21 | require(hasNext)
22 | hiddenTokens = readHiddenTokens()
23 | val resultToken = nextToken
24 | resultToken.associatedWhitespaceAndComments_ = hiddenTokens
25 | if (nextToken.tokenType == EOF)
26 | ended = true
27 | nextToken = lexer.next()
28 | resultToken
29 | }
30 |
31 | private def readHiddenTokens(): HiddenTokens = {
32 | val hiddenTokens = new ListBuffer[HiddenToken]
33 | while (isCommentOrWhitespace(nextToken)) {
34 | hiddenTokens += makeHiddenToken(nextToken)
35 | nextToken = lexer.next()
36 | }
37 | new HiddenTokens(hiddenTokens.toList)
38 | }
39 |
40 | private def isCommentOrWhitespace(token: Token) = token.tokenType match {
41 | case WS | LINE_COMMENT | MULTILINE_COMMENT ⇒ true
42 | case _ ⇒ false
43 | }
44 |
45 | private def makeHiddenToken(token: Token) = token.tokenType match {
46 | case LINE_COMMENT ⇒ SingleLineComment(token)
47 | case MULTILINE_COMMENT if token.isScalaDocComment ⇒ ScalaDocComment(token)
48 | case MULTILINE_COMMENT ⇒ MultiLineComment(token)
49 | case WS ⇒ Whitespace(token)
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/Keywords.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.Tokens._
4 |
5 | object Keywords {
6 |
7 | def apply(s: String): Option[TokenType] = keywords get s
8 |
9 | private val keywords = Map(
10 | "abstract" -> ABSTRACT,
11 | "case" -> CASE,
12 | "catch" -> CATCH,
13 | "class" -> CLASS,
14 | "def" -> DEF,
15 | "do" -> DO,
16 | "else" -> ELSE,
17 | "extends" -> EXTENDS,
18 | "false" -> FALSE,
19 | "final" -> FINAL,
20 | "finally" -> FINALLY,
21 | "for" -> FOR,
22 | "forSome" -> FORSOME,
23 | "if" -> IF,
24 | "implicit" -> IMPLICIT,
25 | "import" -> IMPORT,
26 | "lazy" -> LAZY,
27 | "match" -> MATCH,
28 | "new" -> NEW,
29 | "null" -> NULL,
30 | "object" -> OBJECT,
31 | "override" -> OVERRIDE,
32 | "package" -> PACKAGE,
33 | "private" -> PRIVATE,
34 | "protected" -> PROTECTED,
35 | "return" -> RETURN,
36 | "sealed" -> SEALED,
37 | "super" -> SUPER,
38 | "this" -> THIS,
39 | "throw" -> THROW,
40 | "trait" -> TRAIT,
41 | "try" -> TRY,
42 | "true" -> TRUE,
43 | "type" -> TYPE,
44 | "val" -> VAL,
45 | "var" -> VAR,
46 | "while" -> WHILE,
47 | "with" -> WITH,
48 | "yield" -> YIELD,
49 | "_" -> USCORE,
50 | ":" -> COLON,
51 | "=" -> EQUALS,
52 | "=>" -> ARROW,
53 | "<-" -> LARROW,
54 | "->" -> RARROW,
55 | "<:" -> SUBTYPE,
56 | "<%" -> VIEWBOUND,
57 | ">:" -> SUPERTYPE,
58 | "#" -> HASH,
59 | "@" -> AT,
60 | "." -> DOT,
61 | "+" -> PLUS,
62 | "-" -> MINUS,
63 | "*" -> STAR,
64 | "|" -> PIPE,
65 | "~" -> TILDE,
66 | "!" -> EXCLAMATION
67 | )
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/ImportFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences.{SpacesAroundMultiImports, FormattingPreferences}
6 |
7 | // format: OFF
8 | class ImportFormatterTest extends AbstractFormatterTest {
9 |
10 | {
11 | implicit val formattingPreferences = FormattingPreferences.setPreference(
12 | SpacesAroundMultiImports, true)
13 |
14 | "import foo . _" ==> "import foo._"
15 | "import foo . bar" ==> "import foo.bar"
16 | "import foo.{bar=>baz}" ==> "import foo.{ bar => baz }"
17 | "import foo.{bar=>baz},baz.biz" ==> "import foo.{ bar => baz }, baz.biz"
18 | """import foo.{bar => baz,
19 | |wibble => wobble}""" ==>
20 | """import foo.{
21 | | bar => baz,
22 | | wibble => wobble
23 | |}"""
24 | }
25 |
26 | {
27 | implicit val formattingPreferences = FormattingPreferences.setPreference(
28 | SpacesAroundMultiImports, false)
29 |
30 | "import foo . _" ==> "import foo._"
31 | "import foo . bar" ==> "import foo.bar"
32 | "import foo.{bar=>baz}" ==> "import foo.{bar => baz}"
33 | "import foo.{bar=>baz},baz.biz" ==> "import foo.{bar => baz}, baz.biz"
34 | """import foo.{bar => baz,
35 | |wibble => wobble}""" ==>
36 | """import foo.{
37 | | bar => baz,
38 | | wibble => wobble
39 | |}"""
40 | }
41 |
42 | override val debug = false
43 |
44 | type Result = CompilationUnit
45 |
46 | def parse(parser: ScalaParser) = parser.compilationUnit()
47 |
48 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/misc/src/main/scala/com/danieltrinh/scalariform/gui/TokenTable.scala:
--------------------------------------------------------------------------------
1 | package scalariform.gui
2 |
3 | import scalariform.formatter.FormatResult
4 | import javax.swing.JTable
5 | import scalariform.lexer.Token
6 | import javax.swing.table.AbstractTableModel
7 | import scalariform.utils.Range
8 |
9 | class TokenTable extends JTable(new TokenTableModel(Nil, FormatResult.EMPTY)) {
10 |
11 | setCellSelectionEnabled(false)
12 | setRowSelectionAllowed(true)
13 | setColumnSelectionAllowed(false)
14 |
15 | def setTokens(tokens: List[Token], formatResult: FormatResult = FormatResult.EMPTY) {
16 | val tableModel = new TokenTableModel(tokens, formatResult)
17 | setModel(tableModel)
18 | }
19 |
20 | override def getModel = super.getModel.asInstanceOf[TokenTableModel]
21 |
22 | def getSelectedToken: Option[Token] =
23 | getSelectedRow() match {
24 | case -1 ⇒ None
25 | case n ⇒ Some(getModel.tokens(n))
26 | }
27 |
28 | }
29 |
30 | class TokenTableModel(val tokens: List[Token], formatResult: FormatResult) extends AbstractTableModel {
31 |
32 | def getColumnCount = 5
33 |
34 | def getRowCount = tokens.size
35 |
36 | def getValueAt(row: Int, col: Int): AnyRef = {
37 | val token = tokens(row)
38 | col match {
39 | case 0 ⇒ token.tokenType
40 | case 1 ⇒ token.text
41 | case 2 ⇒ token.offset.asInstanceOf[java.lang.Integer]
42 | case 3 ⇒ token.lastCharacterOffset.asInstanceOf[java.lang.Integer]
43 | case 4 ⇒ formatResult.predecessorFormatting.get(token) orElse formatResult.inferredNewlineFormatting.get(token) getOrElse ""
44 | }
45 | }
46 |
47 | override def getColumnName(col: Int) = col match {
48 | case 0 ⇒ "Type"
49 | case 1 ⇒ "Token text"
50 | case 2 ⇒ "Start"
51 | case 3 ⇒ "Finish"
52 | case 4 ⇒ "Instruction"
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/preferences/IFormattingPreferences.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter.preferences
2 |
3 | trait IFormattingPreferences {
4 |
5 | def apply[T](preference: PreferenceDescriptor[T]): T
6 |
7 | def setPreference[T](preference: PreferenceDescriptor[T], value: T): IFormattingPreferences
8 |
9 | def preferencesMap: Map[PreferenceDescriptor[_], Any]
10 |
11 | def indentStyle: IndentStyle
12 |
13 | }
14 |
15 | abstract sealed class IndentStyle {
16 | def indent(n: Int): String
17 | protected def repeat(s: String, n: Int) = 1 to n map { _ ⇒ s } mkString
18 | }
19 |
20 | case object Tabs extends IndentStyle {
21 | def indent(indentLevel: Int) = repeat("\t", indentLevel)
22 | }
23 |
24 | case class Spaces(n: Int) extends IndentStyle {
25 |
26 | def indent(indentLevel: Int) = repeat(repeat(" ", n), indentLevel)
27 |
28 | def length(indentLevel: Int) = indent(indentLevel).length
29 |
30 | }
31 |
32 | class FormattingPreferences(val preferencesMap: Map[PreferenceDescriptor[_], Any]) extends IFormattingPreferences {
33 |
34 | def apply[T](preference: PreferenceDescriptor[T]): T = preferencesMap.get(preference) map { _.asInstanceOf[T] } getOrElse preference.defaultValue
35 |
36 | def setPreference[T](preference: PreferenceDescriptor[T], value: T) = new FormattingPreferences(preferencesMap + (preference -> value))
37 |
38 | override def toString = getClass.getSimpleName + "(" + preferencesMap + ")"
39 |
40 | val indentStyle = if (this(IndentWithTabs)) Tabs else Spaces(this(IndentSpaces))
41 | }
42 |
43 | case object FormattingPreferences extends FormattingPreferences(Map()) {
44 |
45 | def apply() = new FormattingPreferences(Map())
46 |
47 | }
48 |
49 | trait HasFormattingPreferences {
50 |
51 | val formattingPreferences: IFormattingPreferences
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/preferences/PreferencesImporterExporter.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter.preferences
2 |
3 | import java.util.Properties
4 | import scala.collection.JavaConversions._
5 | import scalariform.utils.Utils._
6 | import java.io.IOException
7 |
8 | object PreferencesImporterExporter {
9 |
10 | /**
11 | * Pull preferences from a Properties store.
12 | * Errors are silently ignored. (TODO)
13 | */
14 | def getPreferences(properties: Properties): IFormattingPreferences = {
15 |
16 | var preferences = FormattingPreferences()
17 |
18 | def setPreference[T](preferenceDescriptor: PreferenceDescriptor[T], valueString: String) =
19 | preferenceDescriptor.preferenceType.parseValue(valueString) match {
20 | case Left(error) ⇒
21 | case Right(value) ⇒ preferences = preferences.setPreference(preferenceDescriptor, value)
22 | }
23 |
24 | for {
25 | key @ (dummy: String) ← properties.propertyNames
26 | descriptor ← AllPreferences.preferencesByKey.get(key)
27 | valueString = properties.getProperty(key)
28 | } setPreference(descriptor, valueString)
29 | preferences
30 |
31 | }
32 |
33 | def asProperties(preferences: IFormattingPreferences): Properties = {
34 | val properties = new Properties
35 | for (preference ← AllPreferences.preferences)
36 | properties.setProperty(preference.key, preferences(preference).toString)
37 | properties
38 | }
39 |
40 | @throws(classOf[IOException])
41 | def loadPreferences(path: String): IFormattingPreferences = {
42 | val properties = new Properties
43 | withFileInputStream(path) { stream ⇒
44 | properties.load(stream)
45 | }
46 | getPreferences(properties)
47 | }
48 |
49 | @throws(classOf[IOException])
50 | def savePreferences(path: String, preferences: IFormattingPreferences) {
51 | val properties = asProperties(preferences)
52 | withFileOutputStream(path) { stream ⇒
53 | properties.store(stream, "Scalariform formatter preferences")
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/BlockExprFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 |
6 | // format: OFF
7 | class BlockExprFormatterTest extends AbstractExpressionFormatterTest {
8 |
9 | override val debug = false
10 |
11 | """{
12 | | a();
13 | | b()
14 | |}""" ==>
15 | """{
16 | | a();
17 | | b()
18 | |}"""
19 |
20 | """{
21 | |a;b;c;
22 | |d;e;f//Foo
23 | |g/*h*/;i
24 | |/* j */
25 | |k
26 | |}""" ==>
27 | """{
28 | | a; b; c;
29 | | d; e; f //Foo
30 | | g /*h*/ ; i
31 | | /* j */
32 | | k
33 | |}"""
34 |
35 | """{
36 | |val x = {
37 | |a()
38 | |b()
39 | |}
40 | |}""" ==>
41 | """{
42 | | val x = {
43 | | a()
44 | | b()
45 | | }
46 | |}"""
47 |
48 | """{
49 | |1 +
50 | |2
51 | |}""" ==>
52 | """{
53 | | 1 +
54 | | 2
55 | |}"""
56 |
57 | "{ object A }" ==> "{ object A }"
58 |
59 | "{ class A }" ==> "{ class A }"
60 |
61 | """{
62 | |class A
63 | |class B
64 | |}""" ==>
65 | """{
66 | | class A
67 | | class B
68 | |}"""
69 |
70 | "{ case 42 => }" ==> "{ case 42 => }"
71 | "{ case -42 => }" ==> "{ case -42 => }"
72 |
73 | """{
74 | | println("foo")
75 | | (x: Int) => 42
76 | |}""" ==>
77 | """{
78 | | println("foo")
79 | | (x: Int) => 42
80 | |}"""
81 |
82 | """{
83 | |c !
84 | |val b
85 | |}""" ==>
86 | """{
87 | | c !
88 | | val b
89 | |}"""
90 |
91 | """{
92 | | if (b) { /**/}
93 | | false
94 | |}""" ==>
95 | """{
96 | | if (b) { /**/ }
97 | | false
98 | |}"""
99 |
100 | """{
101 | |}""" ==>
102 | """{
103 | |}"""
104 |
105 | """{
106 | |
107 | |}""" ==>
108 | """{
109 | |
110 | |}"""
111 |
112 | "{ ; a }" ==> "{ ; a }"
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/parser/ParserTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.parser
2 |
3 | import scalariform.lexer._
4 | import scalariform.parser._
5 |
6 | import org.scalatest.FlatSpec
7 | import org.scalatest.matchers.ShouldMatchers
8 |
9 | // format: +preserveSpaceBeforeArguments
10 | class ParserTest extends FlatSpec with ShouldMatchers {
11 |
12 | "Parser" should "throw a parse exception" in {
13 | evaluating { parseExpression("for {x <- b if }") } should produce[ScalaParserException]
14 | }
15 |
16 | "Parser" should "throw a parse exception for empty match " in {
17 | evaluating { parseExpression("a match { }") } should produce[ScalaParserException]
18 | }
19 |
20 | "Parser" should "produce a parse exception on a trailing close brace" in {
21 | evaluating { parseCompilationUnit("class A{}}") } should produce[ScalaParserException]
22 | }
23 |
24 | "Parser" should "not throw an exception" in {
25 | parseExpression("{ case List[String]() => 12 }")
26 | }
27 |
28 | // See issue #60
29 | "Parser" should "not throw an exception on case block ending with decl" in {
30 | parseExpression("""
31 | args(0) match {
32 | case "blah" =>
33 | val x = args(0)
34 | case _ =>
35 | println("not blah")
36 | }
37 | """)
38 | }
39 |
40 | "Parser" should "throw a parse exception in bad package blocks" in {
41 | evaluating { parseCompilationUnit("package a {} package b {}") } should produce[ScalaParserException]
42 | }
43 |
44 | // issue #44
45 | "Parser" should "allow qualified type parameter in pattern matching" in {
46 | parseExpression("""
47 | {
48 | case List[scala.Int]() => 1
49 | case _: List[scala.Int] => 2
50 | }
51 | """)
52 | }
53 |
54 | private def parser(s: String) = new ScalaParser(ScalaLexer.tokenise(s).toArray)
55 | private def parseExpression(s: String) = parser(s).expr
56 | private def parseCompilationUnit(s: String) = parser(s).compilationUnit
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/lexer/NewlineInferencerTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform._
4 | import scalariform.lexer.Tokens._
5 | import org.scalatest.FlatSpec
6 | import org.scalatest.matchers.ShouldMatchers
7 | import org.scalatest.TestFailedException
8 | import org.scalatest.TestPendingException
9 | import java.io._
10 |
11 | /**
12 | * Test full tokeniser, including newline inferencing.
13 | */
14 | class NewlineInferencerTest extends FlatSpec with ShouldMatchers {
15 |
16 | implicit def string2TestString(s: String)(implicit forgiveErrors: Boolean = false, scalaVersion: ScalaVersion = ScalaVersions.DEFAULT) =
17 | new TestString(s, forgiveErrors, scalaVersion);
18 |
19 | // See issue #60
20 | """
21 | a match {
22 | case b =>
23 | val c = d
24 | case e =>
25 | }""" shouldProduceTokens (
26 | VARID, MATCH, LBRACE,
27 | CASE, VARID, ARROW,
28 | VAL, VARID, EQUALS, VARID, NEWLINE,
29 | CASE, VARID, ARROW,
30 | RBRACE)
31 |
32 | class TestString(s: String, forgiveErrors: Boolean = false, scalaVersion: ScalaVersion = ScalaVersions.DEFAULT) {
33 |
34 | def shouldProduceTokens(toks: TokenType*)() {
35 | check(s.stripMargin, toks.toList)
36 | }
37 |
38 | private def check(s: String, expectedTokens: List[TokenType]) {
39 | it should ("tokenise >>>" + s + "<<< as >>>" + expectedTokens + "<<< forgiveErrors = " + forgiveErrors + ", scalaVersion = " + scalaVersion) in {
40 | val actualTokens: List[Token] = ScalaLexer.tokenise(s, forgiveErrors, scalaVersion.toString)
41 | val actualTokenTypes = actualTokens.map(_.tokenType)
42 | require(actualTokenTypes.last == EOF, "Last token must be EOF, but was " + actualTokens.last.tokenType)
43 | require(actualTokenTypes.count(_ == EOF) == 1, "There must only be one EOF token")
44 | val reconstitutedSource = actualTokens.init.map(_.rawText).mkString
45 | require(actualTokenTypes.init == expectedTokens, "Tokens do not match. Expected " + expectedTokens + ", but was " + actualTokenTypes.init)
46 | }
47 | }
48 |
49 | }
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/CompactControlReadabilityTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import preferences.FormattingPreferences._
4 | import scalariform.formatter.preferences._
5 | import scalariform.parser._
6 | import scalariform.formatter._
7 |
8 | // format: OFF
9 | class CompactControlReadabilityTest extends AbstractExpressionFormatterTest {
10 |
11 | implicit val formattingPreferences = FormattingPreferences.setPreference(CompactControlReadability, true)
12 |
13 | """if(a){
14 | |foo
15 | |} else {
16 | |bar }""" ==>
17 | """if (a) {
18 | | foo
19 | |}
20 | |else {
21 | | bar
22 | |}"""
23 |
24 | """if(a){
25 | |foo
26 | |}
27 | |else {
28 | |bar }""" ==>
29 | """if (a) {
30 | | foo
31 | |}
32 | |else {
33 | | bar
34 | |}"""
35 |
36 | """if(a){
37 | |foo
38 | |} else {
39 | |
40 | |bar }""" ==>
41 | """if (a) {
42 | | foo
43 | |}
44 | |else {
45 | |
46 | | bar
47 | |}"""
48 |
49 | """try{
50 | | foo
51 | |} catch {
52 | | bar
53 | |}""" ==>
54 | """try {
55 | | foo
56 | |}
57 | |catch {
58 | | bar
59 | |}"""
60 |
61 | """try{
62 | | foo
63 | |} finally {
64 | | bar
65 | |}""" ==>
66 | """try {
67 | | foo
68 | |}
69 | |finally {
70 | | bar
71 | |}"""
72 |
73 | """try{
74 | | foo
75 | |}
76 | |finally {
77 | | bar
78 | |}""" ==>
79 | """try {
80 | | foo
81 | |}
82 | |finally {
83 | | bar
84 | |}"""
85 |
86 | """try{
87 | | foo
88 | |} finally {
89 | |
90 | | bar
91 | |}""" ==>
92 | """try {
93 | | foo
94 | |}
95 | |finally {
96 | |
97 | | bar
98 | |}"""
99 |
100 | "if (y > 0) positive else if (y < 0) negative else zero" ==> "if (y > 0) positive else if (y < 0) negative else zero"
101 |
102 | "try x catch y finally z" ==> "try x catch y finally z"
103 |
104 |
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/scalariform.feature/feature.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Code formatter for Scala 2.8
9 |
10 |
11 |
12 | The MIT License
13 |
14 | Copyright (c) 2010 Matthew D. Russell
15 |
16 | Permission is hereby granted, free of charge, to any person obtaining
17 | a copy of this software and associated documentation files (the
18 | "Software"), to deal in the Software without restriction, including
19 | without limitation the rights to use, copy, modify, merge, publish,
20 | distribute, sublicense, and/or sell copies of the Software, and
21 | to permit persons to whom the Software is furnished to do so,
22 | subject to the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be
25 | included in all copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
29 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
30 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
31 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/WhileExprFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 |
6 | // format: OFF
7 | class WhileExprFormatterTest extends AbstractExpressionFormatterTest {
8 |
9 | "while( true ) run()" ==> "while (true) run()"
10 |
11 | """while( true )
12 | |run()""" ==>
13 | """while (true)
14 | | run()"""
15 |
16 | "while (true) { run() }" ==> "while (true) { run() }"
17 |
18 | """while (true) {
19 | |run() }""" ==>
20 | """while (true) {
21 | | run()
22 | |}"""
23 |
24 | "do run()while( true )" ==> "do run() while (true)"
25 |
26 | """do
27 | |run() while (true)""" ==>
28 | """do
29 | | run()
30 | |while (true)"""
31 |
32 | """do {
33 | |run()
34 | |}
35 | |while (true)""" ==>
36 | """do {
37 | | run()
38 | |} while (true)"""
39 |
40 | """do {
41 | |run()
42 | |};
43 | |while (true)""" ==>
44 | """do {
45 | | run()
46 | |}; while (true)"""
47 |
48 | """do run();
49 | |while (true)""" ==>
50 | """do run();
51 | |while (true)"""
52 |
53 | """do run()
54 | |while (true)""" ==>
55 | """do run()
56 | |while (true)"""
57 |
58 | """do
59 | |run()
60 | |while (true)""" ==>
61 | """do
62 | | run()
63 | |while (true)"""
64 |
65 | """do
66 | |run()
67 | |;
68 | |while (true)""" ==>
69 | """do
70 | | run();
71 | |while (true)"""
72 |
73 | """do { run() };
74 | |while (true)""" ==>
75 | """do { run() };
76 | |while (true)"""
77 |
78 | """do { run() }
79 | |while (true)""" ==>
80 | """do { run() }
81 | |while (true)"""
82 |
83 | """while(true){do { run(); };
84 | |while (if (true) {
85 | |a} else {
86 | |b})
87 | |}""" ==>
88 | """while (true) {
89 | | do { run(); };
90 | | while (if (true) {
91 | | a
92 | | } else {
93 | | b
94 | | })
95 | |}"""
96 |
97 | """a(while (b)
98 | |c())""" ==>
99 | """a(while (b)
100 | | c())"""
101 |
102 | }
103 |
104 |
105 |
--------------------------------------------------------------------------------
/scalariform.update/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | scalariform.update
4 |
5 |
6 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/utils/TextEdits.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | object TextEdit {
4 |
5 | def delete(range: Range): TextEdit = delete(range.offset, range.length)
6 |
7 | def delete(position: Int, length: Int): TextEdit = TextEdit(position = position, length = length, replacement = "")
8 |
9 | }
10 |
11 | case class TextEdit(position: Int, length: Int, replacement: String) {
12 |
13 | require(position >= 0, "position must be positive: " + position)
14 |
15 | require(length >= 0)
16 |
17 | override lazy val toString = {
18 | val replacementDisplay = replacement.replace("\n", """\n""").replace("\r", """\r""")
19 | getClass.getSimpleName + "(position = " + position + ", length = " + length + ", replacement = '" + replacementDisplay + "')"
20 | }
21 |
22 | def shift(n: Int) = copy(position = position + n)
23 |
24 | }
25 |
26 | object TextEditProcessor {
27 |
28 | /**
29 | * @param edits must be ordered and non-overlapping
30 | */
31 | def runEdits(s: String, edits: TextEdit*): String = runEdits(s, edits.toList)
32 |
33 | /**
34 | * @param edits must be ordered and non-overlapping
35 | */
36 | def runEdits(s: String, edits: List[TextEdit]): String = {
37 | val sb = new StringBuilder
38 | var pos = 0
39 | var editsRemaining = edits
40 | while (pos < s.length) {
41 | if (editsRemaining.isEmpty) {
42 | sb.append(s(pos))
43 | pos += 1
44 | } else {
45 | val edit = editsRemaining.head
46 | if (pos == edit.position) {
47 | editsRemaining = editsRemaining.tail
48 | pos += edit.length
49 | sb.append(edit.replacement)
50 | } else {
51 | sb.append(s(pos))
52 | pos += 1
53 | }
54 | }
55 | }
56 | var processEditsAtEnd = true
57 | while (processEditsAtEnd) {
58 | if (editsRemaining.isEmpty)
59 | processEditsAtEnd = false
60 | else {
61 | val edit = editsRemaining.head
62 | if (pos == edit.position) {
63 | editsRemaining = editsRemaining.tail
64 | pos += edit.length
65 | sb.append(edit.replacement)
66 | } else
67 | processEditsAtEnd = false
68 | }
69 | }
70 | require(editsRemaining.isEmpty)
71 | sb.toString
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/TypeFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 |
5 | // format: OFF
6 | class TypeFormatterTest extends AbstractFormatterTest {
7 |
8 | "Int" ==> "Int"
9 | "List [ String ] " ==> "List[String]"
10 | "Map[String,List[ Int]]" ==> "Map[String, List[Int]]"
11 |
12 | "A => B" ==> "A => B"
13 |
14 | "List/*b*/[/*c*/String/*d*/]" ==> "List /*b*/ [ /*c*/ String /*d*/ ]"
15 |
16 | "Int /*foo*/ Either String" ==> "Int /*foo*/ Either String"
17 |
18 | "List[_>:A<:B]" ==> "List[_ >: A <: B]"
19 |
20 | "List[_>:A_ <:B_]" ==> "List[_ >: A_ <: B_]"
21 | "A_ @Deprecated" ==> "A_ @Deprecated"
22 | "A Either B @Deprecated" ==> "A Either B @Deprecated"
23 |
24 | "A#B" ==> "A#B"
25 | "A_ #B" ==> "A_ #B"
26 | "A_# #B" ==> "A_# #B"
27 |
28 | "this . type" ==> "this.type"
29 | "List[a.type]" ==> "List[a.type]"
30 | "(a.type, b.type)" ==> "(a.type, b.type)"
31 |
32 | "(A)#X" ==> "(A)#X"
33 |
34 | "A @cps[A, C]" ==> "A @cps[A, C]"
35 |
36 | "Int @cps[Int,Int]" ==> "Int @cps[Int, Int]"
37 |
38 | "{def bar :Unit}" ==> "{ def bar: Unit }"
39 |
40 | "(A, B) => C" ==> "(A, B) => C"
41 |
42 | "(A*) => B" ==> "(A*) => B"
43 |
44 | "(=> A) => B" ==> "(=> A) => B"
45 |
46 | "(C, => A) => B" ==> "(C, => A) => B"
47 |
48 | "(C, A*) => B" ==> "(C, A*) => B"
49 |
50 | "(A*, B) => C" ==> "(A*, B) => C"
51 |
52 | "(=>A)" ==> "(=> A)"
53 | "(=> A#Inner[Int])" ==> "(=> A#Inner[Int])"
54 |
55 | "Int Either String" ==> "Int Either String"
56 |
57 | // TODO: forSome clause not valid
58 | "(=> A#Inner[Int] @Deprecated with B with (C) @Deprecated Either (B, A#Inner[_ <: B]) with C) => B forSome {}" ==>
59 | "(=> A#Inner[Int] @Deprecated with B with (C) @Deprecated Either (B, A#Inner[_ <: B]) with C) => B forSome {}"
60 |
61 | "(=> A with B Either (B, A)) => B" ==>
62 | "(=> A with B Either (B, A)) => B"
63 |
64 | "b[c# ::[d]]" ==> "b[c# ::[d]]"
65 |
66 | """C ::
67 | | D""" ==>
68 | """C :: D""" // To check that this doesn't blow up -- we should maintain the newline
69 |
70 | override val debug = false
71 |
72 | type Result = Type
73 |
74 | def parse(parser: ScalaParser) = parser.typ() // TODO: ensure EOF
75 |
76 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0))
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/misc/src/main/scala/com/danieltrinh/scalariform/perf/LexerPerformanceTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.perf
2 |
3 | import java.io.File
4 | import scala.io.Source
5 | import scalariform.parser._
6 | import scalariform.lexer.{ Token ⇒ _, _ }
7 | import scalariform.utils.Utils.time
8 | import scalariform.formatter._
9 |
10 | object LexerPerformanceTest {
11 |
12 | val ITERATIONS = 1000
13 |
14 | val WARMUP = 200
15 |
16 | def main(args: Array[String]) {
17 |
18 | val file = new File("/home/matt/coding/scala/src/compiler/scala/tools/nsc/typechecker/Typers.scala")
19 | // val file = new File("/home/matt/Downloads/scala/scala/src/compiler/scala/tools/nsc/typechecker/Typers.scala")
20 | val source = Source.fromFile(file).mkString
21 | println("Source: " + source.length + " chars")
22 | val tokens = ScalaLexer.rawTokenise(source)
23 | println("Tokens: " + tokens.size)
24 | 1 to WARMUP foreach { _ ⇒ doIt(source) }
25 |
26 | val start = System.currentTimeMillis
27 | val durations = 1 to ITERATIONS map { _ ⇒
28 | val start1 = System.nanoTime
29 | doIt(source)
30 | val duration = System.nanoTime - start1
31 | duration.toDouble / 1000000.0
32 | }
33 | val duration = System.currentTimeMillis - start
34 | val meanT = duration.toDouble / ITERATIONS
35 | println("Raw average: " + meanT)
36 | def compute(iterable: Iterable[Double]): (Double, Double) = {
37 | def square(x: Double) = x * x
38 | val size = iterable.size
39 | val mean = durations.sum / size
40 | (mean, math.sqrt(durations.map(n ⇒ square(n - mean)).sum / size))
41 | }
42 | val (mean, stdDev) = compute(durations)
43 | def isNormal(d: Double) = math.abs(d - mean) < 2 * stdDev
44 | val durations2 = durations.filter(isNormal)
45 | println("Original trials: " + ITERATIONS)
46 | println("Outliers removed: " + (ITERATIONS - durations2.size))
47 | val (mean2, stdDev2) = compute(durations2)
48 | println("Minimum: " + durations.min + " ms")
49 | println("Average: " + mean2 + " ms")
50 | println("Standard deviation: " + stdDev2 + " ms")
51 | println()
52 | durations.foreach(println)
53 | }
54 |
55 | private def doIt(s: String) = {
56 | // new WhitespaceAndCommentsGrouper(ScalaLexer.createRawLexer(s)).toList
57 | // ScalaLexer.tokenise(s)
58 | // UnicodeEscapeDecoder.decode(s)
59 | ScalaLexer.rawTokenise(s) // 8.13
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/Alignment.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import Math._
5 | import scalariform.formatter.preferences._
6 |
7 | // For now, this is just a place to store alignment related functionality.
8 | // TOOD: refactor duplicate behavior in here
9 | object Alignment {
10 | type EitherAlignableParam = Either[ConsecutiveSingleLineParams, Param]
11 | type EitherAlignableEqualsExpr = Either[ConsecutiveSingleLineEqualsExprs, CallExpr]
12 | type EitherAlignableCaseClause = Either[ConsecutiveSingleLineCaseClauses, CaseClause]
13 |
14 | case class ConsecutiveSingleLineParams(params: List[Param], maxSectionLengths: ParamSectionLengths, thisSectionLengths: ParamSectionLengths) {
15 | def prepend(param: Param, newLengths: ParamSectionLengths): ConsecutiveSingleLineParams = {
16 | ConsecutiveSingleLineParams(param :: params, maxSectionLengths.max(newLengths), thisSectionLengths)
17 | }
18 |
19 | // Splits the head param off, returning it and the remaining params.
20 | // This doesn't recalculate section lengths.
21 | def pop: (Option[Param], ConsecutiveSingleLineParams) = params match {
22 | case param :: remainingParams ⇒
23 | (Some(param), copy(params = remainingParams))
24 | case Nil ⇒
25 | (None, copy(params = Nil))
26 | }
27 | }
28 |
29 | case class ConsecutiveSingleLineEqualsExprs(
30 | equalsExprs: List[EqualsExpr],
31 | largestIdLength: Int
32 | ) {
33 |
34 | def prepend(equalsExpr: EqualsExpr, length: Int) = {
35 | ConsecutiveSingleLineEqualsExprs(equalsExpr :: equalsExprs, max(length, largestIdLength))
36 | }
37 | }
38 |
39 | case class ConsecutiveSingleLineCaseClauses(
40 | clauses: List[CaseClause],
41 | largestCasePatternLength: Int,
42 | smallestCasePatternLength: Int
43 | ) {
44 | def prepend(clause: CaseClause, length: Int) =
45 | ConsecutiveSingleLineCaseClauses(clause :: clauses, max(length, largestCasePatternLength), min(length, smallestCasePatternLength))
46 |
47 | def patternLengthRange = largestCasePatternLength - smallestCasePatternLength
48 |
49 | }
50 |
51 | case class ParamSectionLengths(prefixLength: Int, idLength: Int, prefixAndIdLength: Int, typeLength: Int) {
52 | def max(newParamSectionLength: ParamSectionLengths): ParamSectionLengths = {
53 | val ParamSectionLengths(newPrefixLength, newIdLength, newPrefixAndIdLength, newTypeLength) = newParamSectionLength
54 | ParamSectionLengths(
55 | math.max(prefixLength, newPrefixLength),
56 | math.max(idLength, newIdLength),
57 | math.max(prefixAndIdLength, newPrefixAndIdLength),
58 | math.max(typeLength, newTypeLength)
59 | )
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/cli/src/main/scala/com/danieltrinh/scalariform/commandline/CommandLineOptionParser.scala:
--------------------------------------------------------------------------------
1 | package scalariform.commandline
2 |
3 | import scala.util.parsing.input._
4 | import scala.util.parsing.combinator._
5 |
6 | class CommandLineOptionParser extends RegexParsers {
7 |
8 | lazy val option: Parser[CommandLineArgument] =
9 | phrase(help) | phrase(version) | phrase(scalaVersion) | phrase(stdin) | phrase(stdout) | phrase(recurse) |
10 | phrase(test) | phrase(forceOutput) | phrase(quiet) | phrase(fileList) | phrase(encoding) | phrase(toggle) |
11 | phrase(preferenceFile) | phrase(preferenceOption) | phrase(badOption)
12 |
13 | lazy val test = ("--test" | "-t") ^^^ Test
14 |
15 | lazy val forceOutput = ("--forceOutput" | "-f") ^^^ ForceOutput
16 |
17 | lazy val stdout = "--stdout" ^^^ Stdout
18 |
19 | lazy val stdin = "--stdin" ^^^ Stdin
20 |
21 | lazy val quiet = ("--quiet" | "-q") ^^^ Quiet
22 |
23 | lazy val recurse = ("--recurse" | "-r") ^^^ Recurse
24 |
25 | lazy val help = ("--help" | "-help" | "-h") ^^^ Help
26 |
27 | lazy val version = ("--version" | "-version") ^^^ Version
28 |
29 | lazy val scalaVersion = ("--scalaVersion=" | "-s=") ~> """(\d|\.)+""".r ^^ ScalaVersion
30 |
31 | lazy val fileList = ("--fileList=" | "-l=") ~> ".+".r ^^ FileList
32 |
33 | lazy val encoding = "--encoding=" ~> ".+".r ^^ Encoding
34 |
35 | lazy val toggle = plusOrMinus ~ preferenceKey ^^ { case onOrOff ~ key ⇒ PreferenceOption(key, onOrOff.toString) }
36 |
37 | lazy val plusOrMinus = "+" ^^^ true | "-" ^^^ false
38 |
39 | lazy val preferenceFile = ("--preferenceFile=" | "-p=") ~> ".+".r ^^ PreferenceFile
40 |
41 | lazy val preferenceOption = ("-" ~> preferenceKey <~ "=") ~ """(\w|\.)+""".r ^^ {
42 | case (key ~ value) ⇒ PreferenceOption(key, value)
43 | }
44 |
45 | lazy val preferenceKey: Parser[String] = """[a-zA-Z.]+""".r
46 |
47 | lazy val badOption = guard(plusOrMinus) ~> ".*".r ^^ BadOption
48 |
49 | def getArgument(s: String) = parse(option, s) getOrElse FileName(s)
50 | }
51 |
52 | sealed trait CommandLineArgument
53 |
54 | case class PreferenceOption(preferenceKey: String, value: String) extends CommandLineArgument
55 | case class PreferenceFile(name: String) extends CommandLineArgument
56 | case class FileName(name: String) extends CommandLineArgument
57 | case class FileList(name: String) extends CommandLineArgument
58 | case class Encoding(encoding: String) extends CommandLineArgument
59 | case object Test extends CommandLineArgument
60 | case object Stdout extends CommandLineArgument
61 | case object Stdin extends CommandLineArgument
62 | case object ForceOutput extends CommandLineArgument
63 | case object Quiet extends CommandLineArgument
64 | case object Help extends CommandLineArgument
65 | case object Version extends CommandLineArgument
66 | case object Recurse extends CommandLineArgument
67 | case class ScalaVersion(scalaVersion: String) extends CommandLineArgument
68 | case class BadOption(name: String) extends CommandLineArgument
69 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/utils/TextEditTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | import org.scalatest.FlatSpec
4 | import org.scalatest.matchers.ShouldMatchers
5 |
6 | // format: +preserveSpaceBeforeArguments
7 | class TextEditTest extends FlatSpec with ShouldMatchers {
8 |
9 | import TextEditProcessor.runEdits
10 |
11 | it should "do replace edits" in {
12 |
13 | runEdits("012345", TextEdit(position = 0, length = 2, replacement = "wibble")) should equal ("wibble2345")
14 |
15 | runEdits("012345", TextEdit(position = 2, length = 2, replacement = "23")) should equal ("012345")
16 |
17 | runEdits("012345",
18 | TextEdit(position = 0, length = 2, replacement = "foo"),
19 | TextEdit(position = 3, length = 2, replacement = "bar")) should equal ("foo2bar5")
20 | }
21 |
22 | it should "do delete edits" in {
23 |
24 | runEdits("012345", TextEdit(position = 0, length = 1, replacement = "")) should equal ("12345")
25 | runEdits("012345", TextEdit(position = 0, length = 6, replacement = "")) should equal ("")
26 | runEdits("012345", TextEdit(position = 5, length = 1, replacement = "")) should equal ("01234")
27 | runEdits("012345", TextEdit(position = 1, length = 4, replacement = "")) should equal ("05")
28 | runEdits("0", TextEdit(position = 0, length = 1, replacement = "")) should equal ("")
29 |
30 | runEdits("012345",
31 | TextEdit(position = 0, length = 2, replacement = ""),
32 | TextEdit(position = 4, length = 2, replacement = "")) should equal ("23")
33 |
34 | }
35 |
36 | it should "do insert edits" in {
37 |
38 | runEdits("012345", TextEdit(position = 0, length = 0, replacement = "")) should equal ("012345")
39 | runEdits("012345", TextEdit(position = 6, length = 0, replacement = "")) should equal ("012345")
40 | runEdits("012345", TextEdit(position = 0, length = 0, replacement = "X")) should equal ("X012345")
41 | runEdits("012345", TextEdit(position = 1, length = 0, replacement = "X")) should equal ("0X12345")
42 | runEdits("012345", TextEdit(position = 5, length = 0, replacement = "X")) should equal ("01234X5")
43 | runEdits("012345", TextEdit(position = 6, length = 0, replacement = "X")) should equal ("012345X")
44 | runEdits("", TextEdit(position = 0, length = 0, replacement = "X")) should equal ("X")
45 |
46 | runEdits("012345",
47 | TextEdit(position = 0, length = 0, replacement = "X"),
48 | TextEdit(position = 3, length = 0, replacement = "X")) should equal ("X012X345")
49 |
50 | }
51 |
52 | it should "do multiple insert edits at same position" in {
53 |
54 | runEdits("012345",
55 | TextEdit(position = 0, length = 0, replacement = "X"),
56 | TextEdit(position = 0, length = 0, replacement = "Y")) should equal ("XY012345")
57 |
58 | runEdits("012345",
59 | TextEdit(position = 0, length = 0, replacement = "X"),
60 | TextEdit(position = 6, length = 0, replacement = "X"),
61 | TextEdit(position = 6, length = 0, replacement = "Y")) should equal ("X012345XY")
62 |
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/CommentFormatter.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.utils._
5 | import scalariform.lexer._
6 | import scalariform.formatter.preferences._
7 | import scala.annotation.tailrec
8 |
9 | trait CommentFormatter { self: HasFormattingPreferences with ScalaFormatter ⇒
10 |
11 | private def getLines(comment: String): (String, List[String]) = {
12 | val prefix = List("/** ", "/**", "/* ", "/*").find(comment.startsWith).get
13 | val (start, rest) = comment.splitAt(prefix.length)
14 | val (contents, _) = rest.splitAt(rest.length - "*/".length)
15 | val firstLine :: otherLines = contents.split("""\r?\n([ \t]*(\*(?!/))?)?""", Integer.MAX_VALUE).toList
16 | val afterStarSpaces = if (formattingPreferences(MultilineScaladocCommentsStartOnFirstLine)) 2 else 1
17 | val initialSpaces = firstLine takeWhile (_.isWhitespace)
18 | val adjustedLines = dropInitialSpaces(firstLine, initialSpaces.size) :: (otherLines map { dropInitialSpaces(_, afterStarSpaces) })
19 | // val adjustedLines map { line ⇒ if (line startsWith "*/") "*" + line else line }
20 | (start, adjustedLines)
21 | }
22 |
23 | @tailrec
24 | private def dropInitialSpaces(s: String, maxSpacesToDrop: Int): String =
25 | if (maxSpacesToDrop > 0 && s.startsWith(" "))
26 | dropInitialSpaces(s drop 1, maxSpacesToDrop - 1)
27 | else
28 | s
29 |
30 | private def removeTrailingWhitespace(s: String) = s.reverse.dropWhile(_.isWhitespace).reverse
31 |
32 | private def pruneEmptyInitial(lines: List[String]) = lines match {
33 | case first :: rest if first.trim == "" ⇒ rest
34 | case _ ⇒ lines
35 | }
36 |
37 | private def pruneEmptyFinal(lines: List[String]) = pruneEmptyInitial(lines.reverse).reverse
38 |
39 | def formatComment(comment: HiddenToken, indentLevel: Int): String =
40 | if (comment.rawText contains '\n') {
41 | val sb = new StringBuilder
42 | val (start, rawLines) = getLines(comment.rawText)
43 |
44 | val lines = pruneEmptyFinal(pruneEmptyInitial(rawLines))
45 |
46 | val alignBeneathSecondAsterisk = formattingPreferences(PlaceScaladocAsterisksBeneathSecondAsterisk)
47 | val startOnFirstLine = formattingPreferences(MultilineScaladocCommentsStartOnFirstLine)
48 | val beforeStarSpaces = if (alignBeneathSecondAsterisk) " " else " "
49 | val afterStarSpaces = if (startOnFirstLine && !alignBeneathSecondAsterisk) " " else " "
50 | sb.append(start.trim)
51 | var firstLine = true
52 | for (line ← lines) {
53 | val trimmedLine = removeTrailingWhitespace(line)
54 | if (firstLine && startOnFirstLine) {
55 | if (trimmedLine.nonEmpty)
56 | sb.append(" ").append(trimmedLine)
57 | } else {
58 | sb.append(newlineSequence).indent(indentLevel).append(beforeStarSpaces).append("*")
59 | if (trimmedLine.nonEmpty)
60 | sb.append(afterStarSpaces).append(trimmedLine)
61 | }
62 | firstLine = false
63 | }
64 | sb.append(newlineSequence).indent(indentLevel).append(beforeStarSpaces).append("*/")
65 | sb.toString
66 | } else
67 | comment.rawText
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/project/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/TypeFormatter.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.lexer.Tokens._
4 | import scalariform.lexer.Token
5 | import scalariform.parser._
6 | import scalariform.utils._
7 | import scalariform.lexer.Tokens
8 | import scalariform.formatter.preferences._
9 | import scalariform.lexer.Chars
10 |
11 | trait TypeFormatter { self: HasFormattingPreferences with AnnotationFormatter with ExprFormatter with ScalaFormatter ⇒
12 |
13 | def format(type_ :Type)(implicit formatterState: FormatterState): FormatResult = format(type_.contents)
14 |
15 | def format(typeElements: List[TypeElement])(implicit formatterState: FormatterState): FormatResult = {
16 | var formatResult = format(typeElements.head)
17 | for ((previousElement, element) ← Utils.stagger(typeElements)) {
18 | if (previousElement.isInstanceOf[Annotation] ||
19 | previousElement.isInstanceOf[Refinement] ||
20 | previousElement.isInstanceOf[InfixTypeConstructor] ||
21 | element.isInstanceOf[Refinement] ||
22 | element.isInstanceOf[InfixTypeConstructor])
23 | formatResult = formatResult.formatNewlineOrOrdinary(element.firstToken, CompactEnsuringGap)
24 | else if (element.isInstanceOf[Annotation]) {
25 | val instruction =
26 | previousElement match {
27 | case GeneralTokens(tokens) if tokens.last.tokenType == Tokens.LBRACKET ⇒ Compact
28 | case _ ⇒ CompactEnsuringGap
29 | }
30 | formatResult = formatResult.before(element.firstToken, instruction)
31 | } else if (previousElement.isInstanceOf[VarianceTypeElement])
32 | formatResult = formatResult.before(element.firstToken, Compact)
33 | else if (element.isInstanceOf[VarargsTypeElement]) {
34 | val instruction = if (Chars.isOperatorPart(previousElement.lastToken.text.last)) CompactEnsuringGap else Compact
35 | formatResult = formatResult.before(element.firstToken, instruction)
36 | }
37 | // else if (previousElement.isInstanceOf[CallByNameTypeElement])
38 | // formatResult = formatResult.before(element.firstToken, Compact)
39 | formatResult ++= format(element)
40 | }
41 | formatResult
42 | }
43 |
44 | private def format(typeElement: TypeElement)(implicit formatterState: FormatterState): FormatResult = {
45 | typeElement match {
46 | case type_ @ Type(_) ⇒ format(type_)
47 | case refinement @ Refinement(_, _, _) ⇒ format(refinement)
48 | case annotation @ Annotation(_, _, _, _) ⇒ format(annotation)
49 | case TypeParamClause(contents) ⇒ format(contents)
50 | case TypeParam(contents) ⇒ format(contents)
51 | case VarianceTypeElement(id) ⇒ NoFormatResult
52 | case VarargsTypeElement(star) ⇒ NoFormatResult
53 | case _ ⇒ NoFormatResult
54 | }
55 | }
56 |
57 | private def format(refinement: Refinement)(implicit formatterState: FormatterState): FormatResult = {
58 | val Refinement(lbrace: Token, statSeq: StatSeq, rbrace: Token) = refinement
59 | val dummyBlock = BlockExpr(lbrace, Right(statSeq), rbrace)
60 | format(dummyBlock, indent = true)
61 | }
62 |
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 |
9 | # Internal variables.
10 | PAPEROPT_a4 = -D latex_paper_size=a4
11 | PAPEROPT_letter = -D latex_paper_size=letter
12 | ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
13 |
14 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
15 |
16 | help:
17 | @echo "Please use \`make ' where is one of"
18 | @echo " html to make standalone HTML files"
19 | @echo " dirhtml to make HTML files named index.html in directories"
20 | @echo " pickle to make pickle files"
21 | @echo " json to make JSON files"
22 | @echo " htmlhelp to make HTML files and a HTML help project"
23 | @echo " qthelp to make HTML files and a qthelp project"
24 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
25 | @echo " changes to make an overview of all changed/added/deprecated items"
26 | @echo " linkcheck to check all external links for integrity"
27 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
28 |
29 | clean:
30 | -rm -rf build/*
31 |
32 | html:
33 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
34 | @echo
35 | @echo "Build finished. The HTML pages are in build/html."
36 |
37 | dirhtml:
38 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml
39 | @echo
40 | @echo "Build finished. The HTML pages are in build/dirhtml."
41 |
42 | pickle:
43 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
44 | @echo
45 | @echo "Build finished; now you can process the pickle files."
46 |
47 | json:
48 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json
49 | @echo
50 | @echo "Build finished; now you can process the JSON files."
51 |
52 | htmlhelp:
53 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
54 | @echo
55 | @echo "Build finished; now you can run HTML Help Workshop with the" \
56 | ".hhp project file in build/htmlhelp."
57 |
58 | qthelp:
59 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp
60 | @echo
61 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
62 | ".qhcp project file in build/qthelp, like this:"
63 | @echo "# qcollectiongenerator build/qthelp/Scalariform.qhcp"
64 | @echo "To view the help file:"
65 | @echo "# assistant -collectionFile build/qthelp/Scalariform.qhc"
66 |
67 | latex:
68 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
69 | @echo
70 | @echo "Build finished; the LaTeX files are in build/latex."
71 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
72 | "run these through (pdf)latex."
73 |
74 | changes:
75 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
76 | @echo
77 | @echo "The overview file is in build/changes."
78 |
79 | linkcheck:
80 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
81 | @echo
82 | @echo "Link check complete; look for any errors in the above output " \
83 | "or in build/linkcheck/output.txt."
84 |
85 | doctest:
86 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/doctest
87 | @echo "Testing of doctests in the sources finished, look at the " \
88 | "results in build/doctest/output.txt."
89 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/FormatResult.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.lexer.Tokens._
4 | import scalariform.lexer._
5 | import scalariform.parser._
6 | import scalariform.utils._
7 |
8 | object FormatResult {
9 |
10 | val EMPTY = FormatResult(Map(), Map(), Map())
11 |
12 | }
13 |
14 | case class FormatResult(
15 | predecessorFormatting: Map[Token, IntertokenFormatInstruction],
16 | inferredNewlineFormatting: Map[Token, IntertokenFormatInstruction],
17 | xmlRewrites: Map[Token, String]
18 | ) {
19 |
20 | def replaceXml(token: Token, replacement: String) = {
21 | require(token.tokenType.isXml)
22 | copy(xmlRewrites = xmlRewrites + (token -> replacement))
23 | }
24 |
25 | def before(token: Token, formatInstruction: IntertokenFormatInstruction) = {
26 | require(!token.isNewline, " cannot do 'before' formatting for NEWLINE* tokens: " + token + ", " + formatInstruction)
27 | copy(predecessorFormatting = predecessorFormatting + (token -> formatInstruction))
28 | }
29 |
30 | def formatNewline(token: Token, formatInstruction: IntertokenFormatInstruction) = {
31 | require(token.isNewline, " cannot do 'newline' formatting for non-NEWLINE tokens: " + token + ", " + formatInstruction)
32 | copy(inferredNewlineFormatting = inferredNewlineFormatting + (token -> formatInstruction))
33 | }
34 |
35 | def formatNewlineOrOrdinary(token: Token, formatInstruction: IntertokenFormatInstruction) =
36 | if (token.isNewline) formatNewline(token, formatInstruction)
37 | else before(token, formatInstruction)
38 |
39 | def tokenWillHaveNewline(token: Token): Boolean = {
40 | val hasNewlineInstruction = predecessorFormatting.get(token) map {
41 | PartialFunction.cond(_) { case newlineInstruction: EnsureNewlineAndIndent ⇒ true }
42 | }
43 | hasNewlineInstruction.getOrElse(false)
44 | }
45 |
46 | def mergeWith(other: FormatResult): FormatResult =
47 | FormatResult(
48 | this.predecessorFormatting ++ other.predecessorFormatting,
49 | this.inferredNewlineFormatting ++ other.inferredNewlineFormatting,
50 | this.xmlRewrites ++ other.xmlRewrites
51 | )
52 |
53 | def ++(other: FormatResult) = mergeWith(other)
54 | }
55 |
56 | object NoFormatResult extends FormatResult(Map(), Map(), Map())
57 |
58 | abstract sealed class IntertokenFormatInstruction
59 |
60 | /**
61 | * Packs the comments together as compactly as possible, eliminating
62 | * as much non-comment whitespace as possible while ensuring that the
63 | * lexer produces the same tokens.
64 | */
65 | case object Compact extends IntertokenFormatInstruction
66 |
67 | /** Like "Compact", but ensures there is either some comment or a single space. */
68 | case object CompactEnsuringGap extends IntertokenFormatInstruction
69 |
70 | /** Like "Compact", but will keep at least a single space if there was whitespace before */
71 | case object CompactPreservingGap extends IntertokenFormatInstruction
72 |
73 | /** Ensures that the interttoken region ends with NEWLINE INDENT. */
74 | case class EnsureNewlineAndIndent(indentLevel: Int, relativeTo: Option[Token] = None) extends IntertokenFormatInstruction
75 |
76 | /** Places the token at spaces number of spaces after the indent level, padding with spaces if necessary */
77 | case class PlaceAtColumn(indentLevel: Int, spaces: Int, relativeTo: Option[Token] = None) extends IntertokenFormatInstruction
78 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/SpecificFormatter.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.lexer.Tokens._
4 | import scalariform.lexer._
5 | import scalariform.parser._
6 | import scalariform.utils._
7 | import scalariform.formatter.preferences._
8 | import scalariform.ScalaVersions
9 |
10 | trait SpecificFormatter {
11 |
12 | def debug = false
13 |
14 | type Result <: AstNode
15 |
16 | def parse(parser: ScalaParser): Result
17 |
18 | def format(formatter: ScalaFormatter, result: Result): FormatResult
19 |
20 | @throws(classOf[ScalaParserException])
21 | def format(source: String, lineDelimiter: Option[String] = None, scalaVersion: String = ScalaVersions.DEFAULT_VERSION)(baseFormattingPreferences: IFormattingPreferences): String = {
22 | val (edits, _) = fullFormat(source, lineDelimiter, scalaVersion)(baseFormattingPreferences)
23 | TextEditProcessor.runEdits(source, edits)
24 | }
25 |
26 | @throws(classOf[ScalaParserException])
27 | def fullFormat(source: String, lineDelimiter: Option[String] = None, scalaVersion: String = ScalaVersions.DEFAULT_VERSION)(baseFormattingPreferences: IFormattingPreferences): (List[TextEdit], FormatResult) = {
28 | import scalariform.parser._
29 |
30 | val startTime = System.currentTimeMillis
31 | val tokens = ScalaLexer.tokenise(source, scalaVersion = scalaVersion)
32 | if (debug) {
33 | println
34 | println(source)
35 | println("Tokens:")
36 | tokens foreach println
37 | }
38 |
39 | val parser = new ScalaParser(tokens.toArray)
40 |
41 | val parseResult = parse(parser)
42 |
43 | var actualFormattingPreferences = baseFormattingPreferences
44 | for {
45 | token ← tokens
46 | hiddenToken ← token.associatedWhitespaceAndComments
47 | ToggleOption(onOrOff, optionName) ← FormatterDirectiveParser.getDirectives(hiddenToken.text)
48 | rawPreference ← AllPreferences.preferencesByKey.get(optionName)
49 | if rawPreference.preferenceType == BooleanPreference
50 | preference = BooleanPreference.cast(rawPreference)
51 | } actualFormattingPreferences = actualFormattingPreferences.setPreference(preference, onOrOff)
52 |
53 | val parsedTokens = parseResult.tokens.filter(_.tokenType != EOF)
54 | require(parsedTokens == tokens.init /* <-- drop EOF */ , "Parse tokens differ from expected.\n Actual = \n" +
55 | parsedTokens.mkString("\n") + "\n expected = \n" + tokens.init.mkString("\n") + "\n parseResult = \n" +
56 | parseResult)
57 |
58 | if (debug) { println("Parse result: " + parseResult) }
59 | val elapsedTime = System.currentTimeMillis - startTime
60 | // if (debug)
61 | // println("Parse time = " + elapsedTime + "ms")
62 | val newlineSequence_ = lineDelimiter.getOrElse(if (source contains "\r\n") "\r\n" else "\n")
63 |
64 | val formatter = new ScalaFormatter() {
65 |
66 | def isInferredNewline(token: Token): Boolean = token.isNewline
67 |
68 | /** requires isInferredNewline(token) == true */
69 | def inferredNewlines(token: Token): HiddenTokens = token.associatedWhitespaceAndComments
70 |
71 | def hiddenPredecessors(token: Token): HiddenTokens = token.associatedWhitespaceAndComments
72 |
73 | val formattingPreferences: IFormattingPreferences = actualFormattingPreferences
74 |
75 | val newlineSequence = newlineSequence_
76 |
77 | }
78 |
79 | val formatResult = format(formatter, parseResult)
80 | if (debug) println("Format result: " + formatResult)
81 | val edits = formatter.writeTokens(source, tokens, formatResult)
82 | (edits, formatResult)
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/ForExprFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 |
6 | // format: OFF
7 | class ForExprFormatterTest extends AbstractExpressionFormatterTest {
8 |
9 | // override val debug = true
10 |
11 | "for (x <- xs) yield x" ==> "for (x <- xs) yield x"
12 |
13 | "for (x <- xs) println(x)" ==> "for (x <- xs) println(x)"
14 |
15 | """for (x <- 1 to 10)
16 | | println("hello")""" ==>
17 | """for (x <- 1 to 10)
18 | | println("hello")"""
19 |
20 | """for (x <- 1 to 10) {
21 | | println("hello")
22 | |}""" ==>
23 | """for (x <- 1 to 10) {
24 | | println("hello")
25 | |}"""
26 |
27 | """for { x <- xs
28 | | y <- ys
29 | | if x > y } yield x + y""" ==>
30 | """for {
31 | | x <- xs
32 | | y <- ys
33 | | if x > y
34 | |} yield x + y"""
35 |
36 | "for (x <- xs) a()" ==> "for (x <- xs) a()"
37 |
38 | """for (x <- xs)
39 | |a()""" ==>
40 | """for (x <- xs)
41 | | a()"""
42 |
43 | """for(x <- xs)
44 | |{
45 | |a()
46 | |}""" ==>
47 | """for (x <- xs) {
48 | | a()
49 | |}"""
50 |
51 | """for(x <- xs) { a() }""" ==>
52 | """for (x <- xs) { a() }"""
53 |
54 | """for(x <- xs)
55 | |{ a() }""" ==>
56 | """for (x <- xs) { a() }"""
57 |
58 | """for(x <- xs) yield
59 | |{
60 | | a + b
61 | |}""" ==>
62 | """for (x <- xs) yield {
63 | | a + b
64 | |}"""
65 |
66 | "for(x <- xs) yield 3" ==> "for (x <- xs) yield 3"
67 |
68 | "for(x <- xs) yield { 3 }" ==> "for (x <- xs) yield { 3 }"
69 |
70 | """for(x <- xs) yield
71 | |{ a + b
72 | |}""" ==>
73 | """for (x <- xs) yield {
74 | | a + b
75 | |}"""
76 |
77 | """for(x <- xs)
78 | |yield
79 | |{
80 | |z } """ ==>
81 | """for (x <- xs) yield {
82 | | z
83 | |}"""
84 |
85 | "for{x<-xs if(true)}yield( if (true) 1 else 2)" ==> "for { x <- xs if (true) } yield (if (true) 1 else 2)"
86 |
87 | """for {
88 | |val x <- xs
89 | |val y <- ys
90 | |x > y
91 | |val z = x + y
92 | |} yield 2""" ==>
93 | """for {
94 | | val x <- xs
95 | | val y <- ys
96 | | x > y
97 | | val z = x + y
98 | |} yield 2"""
99 |
100 | """for (
101 | | val x <- xs;
102 | | val y <- ys;
103 | | x > y;
104 | | val z = x + y
105 | | ) yield z""" ==>
106 | """for (
107 | | val x <- xs;
108 | | val y <- ys;
109 | | x > y;
110 | | val z = x + y
111 | |) yield z"""
112 |
113 | """for {
114 | |x <- xs
115 | |y <- ys
116 | |}
117 | |yield
118 | |2""" ==>
119 | """for {
120 | | x <- xs
121 | | y <- ys
122 | |} yield 2"""
123 |
124 | """for {
125 | |x <- xs
126 | |y <- ys
127 | |}
128 | |println(x + y)""" ==>
129 | """for {
130 | | x <- xs
131 | | y <- ys
132 | |} println(x + y)"""
133 |
134 | "for (n <- 1 to 10 if n > 4 if n < 10) yield n" ==> "for (n <- 1 to 10 if n > 4 if n < 10) yield n"
135 |
136 | "for {n <- 1 to 10 if n > (4)if n < 10} yield n" ==> "for { n <- 1 to 10 if n > (4) if n < 10 } yield n"
137 |
138 | """Some(
139 | |for (n <- 1 to 10)
140 | |yield n)""" ==>
141 | """Some(
142 | | for (n <- 1 to 10)
143 | | yield n
144 | |)"""
145 |
146 | """Some(
147 | |for (n <- 1 to 10)
148 | |proc())""" ==>
149 | """Some(
150 | | for (n <- 1 to 10)
151 | | proc()
152 | |)"""
153 |
154 | }
155 |
156 |
157 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/TryExprFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 |
6 | // format: OFF
7 | class TryExprFormatterTest extends AbstractExpressionFormatterTest {
8 |
9 | override val debug = false
10 |
11 | "try println()" ==> "try println()"
12 |
13 | """try
14 | |println()""" ==>
15 | """try
16 | | println()"""
17 |
18 | """try
19 | | {
20 | |println()
21 | | }""" ==>
22 | """try {
23 | | println()
24 | |}"""
25 |
26 | """try{println()
27 | | }""" ==>
28 | """try {
29 | | println()
30 | |}"""
31 |
32 | "try{println()}" ==> "try { println() }"
33 |
34 | """try {
35 | |println()
36 | |}
37 | |catch { case e => }""" ==>
38 | """try {
39 | | println()
40 | |} catch { case e => }"""
41 |
42 | "try { foo() }catch{ case e => }" ==> "try { foo() } catch { case e => }"
43 |
44 | """try { foo() }
45 | |catch{ case e => }""" ==>
46 | """try { foo() }
47 | |catch { case e => }"""
48 |
49 | """try {
50 | |foo() }
51 | |catch{ case e => }""" ==>
52 | """try {
53 | | foo()
54 | |} catch { case e => }"""
55 |
56 | """try {
57 | |} catch { case e => }finally
58 | |{
59 | |println("foo") }""" ==>
60 | """try {
61 | |} catch { case e => } finally {
62 | | println("foo")
63 | |}"""
64 |
65 | "try {} catch { case e => } finally {}" ==> "try {} catch { case e => } finally {}"
66 |
67 | """try {}
68 | |catch { case e => }
69 | |finally {}""" ==>
70 | """try {}
71 | |catch { case e => }
72 | |finally {}"""
73 |
74 | """try {} catch { case e => }
75 | |finally{
76 | |resource.close()
77 | |}""" ==>
78 | """try {} catch { case e => }
79 | |finally {
80 | | resource.close()
81 | |}"""
82 |
83 | """try {} catch { case e => }
84 | |finally resource.close()""" ==>
85 | """try {} catch { case e => }
86 | |finally resource.close()"""
87 |
88 | """try
89 | |resource.useIt()
90 | |catch { case e => }
91 | |finally
92 | |resource.close()""" ==>
93 | """try
94 | | resource.useIt()
95 | |catch { case e => }
96 | |finally
97 | | resource.close()"""
98 |
99 | """try {
100 | | foo()
101 | |} catch {
102 | | case _ => bar()
103 | |}""" ==>
104 | """try {
105 | | foo()
106 | |} catch {
107 | | case _ => bar()
108 | |}"""
109 |
110 | """try {
111 | |println("bar")
112 | |} finally {
113 | |println("foo")
114 | |}""" ==>
115 | """try {
116 | | println("bar")
117 | |} finally {
118 | | println("foo")
119 | |}"""
120 |
121 | """try {
122 | |
123 | | } catch {
124 | | case _ =>
125 | | }
126 | | finally {
127 | | close()
128 | | }""" ==>
129 | """try {
130 | |
131 | |} catch {
132 | | case _ =>
133 | |} finally {
134 | | close()
135 | |}"""
136 |
137 | // 2.9 generalised catch tests:
138 |
139 | "try body catch implicitly[Handler[T]]" ==> "try body catch implicitly[Handler[T]]"
140 |
141 | """try a catch {
142 | |b
143 | |}""" ==>
144 | """try a catch {
145 | | b
146 | |}"""
147 |
148 | """try a catch
149 | | {
150 | |b
151 | |}""" ==>
152 | """try a catch {
153 | | b
154 | |}"""
155 |
156 | """try a catch
157 | |b""" ==>
158 | """try a catch
159 | | b"""
160 |
161 | """try a
162 | |catch b""" ==>
163 | """try a
164 | |catch b"""
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/AbstractFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.lexer._
5 | import scalariform.formatter.preferences._
6 | import scala.util.parsing.input._
7 | import scala.util.parsing.combinator._
8 | import org.scalatest.FlatSpec
9 | import org.scalatest.matchers.ShouldMatchers
10 | import org.scalatest.TestFailedException
11 | import org.scalatest.TestPendingException
12 | import scalariform.ScalaVersions
13 |
14 | abstract class AbstractFormatterTest extends FlatSpec with ShouldMatchers with SpecificFormatter {
15 |
16 | def prettyPrint(s: String): String =
17 | //s.replaceAll("\n", "↵\n").replaceAll("\t", "↦" ).replaceAll(" ", "▵")
18 | s.replaceAll("\n", "¶\n").replaceAll("\t", "↦") //.replaceAll(" ", "▲")
19 |
20 | implicit def string2FormatTest(s: String)(implicit formattingPreferences: IFormattingPreferences = FormattingPreferences(), scalaVersion: String = ScalaVersions.DEFAULT_VERSION): FormatTest =
21 | FormatTest(s.stripMargin, formattingPreferences, scalaVersion)
22 |
23 | def testFailedException(message: String) = new TestFailedException(message = Some(message), cause = None, failedCodeStackDepth = 2)
24 |
25 | case class FormatTest(source: String, formattingPreferences: IFormattingPreferences, scalaVersion: String) {
26 |
27 | require(formattingPreferences != null)
28 |
29 | def ==>(expectedRaw: String) {
30 | it should ("format >>>" + prettyPrint(source) + "<<< as >>>" + prettyPrint(expectedRaw) + "<<< with preferences " + formattingPreferences + " in version " + scalaVersion) in {
31 | val expected = expectedRaw.stripMargin
32 | val actual = format(source, scalaVersion = scalaVersion)(formattingPreferences)
33 | if (debug) println("Actual = " + actual)
34 | if (expected != actual)
35 | throw testFailedException("Format failure:\n ---- Expected ---- \n" + prettyPrint(expected) + "<<<\n ---- but was----- \n" + prettyPrint(actual) + "<<<\n ---- Original: ----- \n" + prettyPrint(source) + "<<<.")
36 | val beforeTokens = ScalaLexer.tokenise(source, scalaVersion = scalaVersion)
37 | val afterTokens = ScalaLexer.tokenise(actual, scalaVersion = scalaVersion)
38 | val newlineTokenTypes = Set(Tokens.NEWLINE, Tokens.NEWLINES)
39 | if (beforeTokens.map(_.tokenType).find(!newlineTokenTypes.contains(_)) != afterTokens.map(_.tokenType).find(!newlineTokenTypes.contains(_)))
40 | throw testFailedException("Text as expected, but actual and expected tokens differ:\n ---- Before ---- \n" + beforeTokens + "\n ---- After ---- \n" + afterTokens + "\n")
41 |
42 | val actual2 = format(actual, scalaVersion = scalaVersion)(formattingPreferences)
43 | if (actual2 != actual) {
44 | throw testFailedException("Idempotency failure:\n ---- Expected ---- \n" + prettyPrint(actual) + "<<<\n ---- but was----- \n" + prettyPrint(actual2) + "<<<.")
45 | }
46 | val afterTokens2 = ScalaLexer.tokenise(actual2, scalaVersion = scalaVersion)
47 | if (afterTokens2.map(_.tokenType) != afterTokens.map(_.tokenType)) {
48 | throw testFailedException("Idempotency token inconsistency:\n ---- One ---- \n" + afterTokens2 + "\n ---- Twice ---- \n" + afterTokens2 + "\n")
49 | }
50 | }
51 | }
52 |
53 | def =/=>(expected: String): Because = {
54 | //println("Warning -- skipped test:\n" + source)
55 | new Because(expected)
56 | }
57 |
58 | class Because(expected: String) {
59 | def because(reason: String) = {
60 | //println("because " + reason)
61 | it should ("format >>>" + prettyPrint(source) + "<<< as >>>" + prettyPrint(expected) + "<<<, but did not because " + reason) in {
62 | throw new TestPendingException
63 | }
64 | }
65 | }
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/misc/src/main/scala/com/danieltrinh/scalariform/corpusscan/CorpusScanner.scala:
--------------------------------------------------------------------------------
1 | package scalariform.corpusscan
2 |
3 | import java.io.File
4 |
5 | import scala.io.Source
6 |
7 | import org.apache.commons.io.FileUtils
8 |
9 | import scalariform.commandline.ScalaFileWalker
10 | import scalariform.formatter._
11 | import scalariform.formatter.preferences.FormattingPreferences
12 | import scalariform.lexer._
13 | import scalariform.parser._
14 | import scalariform.utils.Utils.writeText
15 |
16 | sealed trait ParseFault
17 | case object TokensDoNotCoverSource extends ParseFault
18 | case object UnsuccessfulParse extends ParseFault
19 | case object BadAstTokens extends ParseFault
20 | case class ParseException(e: Throwable) extends ParseFault
21 |
22 | object CorpusScanner extends SpecificFormatter {
23 |
24 | def attemptToParse(file: File): Option[ParseFault] = {
25 | val source = getText(file)
26 | val sourceAgain = ScalaLexer.rawTokenise(source).map(_.rawText).mkString
27 | if (source != sourceAgain) {
28 | FileUtils.writeStringToFile(new File("source"), source)
29 | FileUtils.writeStringToFile(new File("sourceAgain"), sourceAgain)
30 | return Some(TokensDoNotCoverSource)
31 | }
32 | val tokens = ScalaLexer.tokenise(source)
33 | try {
34 | val result = new ScalaParser(tokens.toArray).compilationUnitOrScript()
35 | if (result.tokens != tokens) {
36 | Some(BadAstTokens)
37 | } else
38 | None
39 | } catch {
40 | case e: ScalaParserException ⇒ Some(UnsuccessfulParse)
41 | }
42 | }
43 |
44 | private def getText(file: File) = Source.fromFile(file).mkString
45 |
46 | val prefs = FormattingPreferences() //.setPreference(AlignSingleLineCaseStatements, true)
47 |
48 | def formatFile(file: File) {
49 | val source = getText(file)
50 | val formatted = format(source)(prefs)
51 | val formatted2 = format(formatted)(prefs)
52 | if (formatted != formatted2) {
53 | FileUtils.writeStringToFile(new File("formatted"), formatted)
54 | FileUtils.writeStringToFile(new File("formatted2"), formatted2)
55 | require(formatted == formatted2, "Idempotency failure")
56 | }
57 | writeText(file, formatted)
58 | // for (parseFault <- attemptToParse(file))
59 | // throw new RuntimeException(parseFault.toString)
60 | }
61 |
62 | type Result = CompilationUnit
63 |
64 | def parse(parser: ScalaParser) = parser.compilationUnitOrScript()
65 |
66 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0))
67 |
68 | }
69 |
70 | object Runner {
71 |
72 | val corpusDir = "/home/matthew/coding/scala-corpus/repos2"
73 | // val corpusDir = "/home/matt/scala-corpus"
74 |
75 | def main(args: Array[String]) {
76 | formatInPlace()
77 | }
78 |
79 | def checkParser() {
80 | val files = ScalaFileWalker.findScalaFiles(corpusDir)
81 | var count = 0
82 | var parsedCount = 0
83 | for (file ← files) {
84 | val parsed = CorpusScanner.attemptToParse(file).isEmpty
85 | if (parsed)
86 | parsedCount += 1
87 | if (!parsed)
88 | println((if (parsed) "OK " else "FAIL!") + " -- " + file)
89 | count += 1
90 | }
91 | println("Total scanned: " + count)
92 | println("Number parsed successfully: " + parsedCount)
93 | println("Parse failures: " + (count - parsedCount))
94 | }
95 |
96 | def formatInPlace() {
97 | var count = 0
98 | for (file ← ScalaFileWalker.findScalaFiles(corpusDir)) {
99 | print("Formatting: " + file)
100 | CorpusScanner.formatFile(file)
101 | val parseFaultOpt = CorpusScanner.attemptToParse(file)
102 | require(parseFaultOpt == None, parseFaultOpt.toString)
103 | println()
104 | count += 1
105 | }
106 | println(count + " files formatted.")
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/misc/src/main/scala/com/danieltrinh/scalariform/gui/ParseTreeModel.scala:
--------------------------------------------------------------------------------
1 | package scalariform.gui
2 |
3 | import javax.swing.event.TreeModelListener
4 | import javax.swing.tree._
5 | import scalariform.lexer.Token
6 | import scalariform.parser.AstNode
7 | import scalariform.utils.Range
8 |
9 | class ParseTreeModel(rootAstNode: AstNode) extends TreeModel {
10 |
11 | def getDocumentRange(obj: AnyRef): Option[Range] = obj.asInstanceOf[TreeNode].range
12 |
13 | abstract sealed class TreeNode(name: String) {
14 |
15 | def children: List[TreeNode]
16 |
17 | lazy val range: Option[Range] = {
18 | val childRanges = children.flatMap(_.range)
19 | if (childRanges.isEmpty)
20 | None
21 | else
22 | Some(childRanges.reduceLeft(_ mergeWith _))
23 | }
24 |
25 | override def toString = name
26 |
27 | }
28 |
29 | case class AstNodeNode(name: String, astNode: AstNode) extends TreeNode(name) {
30 |
31 | val fields = astNode.getFields
32 |
33 | lazy val children = fields flatMap {
34 | case (_, None) | (_, Nil) ⇒ None
35 | case (fieldName, value) ⇒ Some(makeTreeNode(value.asInstanceOf[AnyRef], fieldName))
36 | }
37 |
38 | override def toString = {
39 | val typeName = astNode.getClass.getSimpleName
40 | (if (name != "") name + ": " else "") + typeName
41 | }
42 |
43 | }
44 |
45 | case class TokenNode(name: String, token: Token) extends TreeNode(name) {
46 |
47 | val children = Nil
48 |
49 | override lazy val range = Some(token.range)
50 |
51 | override def toString = name + ": " + token
52 |
53 | }
54 |
55 | case class ListNode(name: String, list: List[Any]) extends TreeNode(name) {
56 |
57 | lazy val children = list.zipWithIndex map { case (x, i) ⇒ makeTreeNode(x, i.toString) }
58 |
59 | }
60 |
61 | case class OptionNode(name: String, opt: Option[Any]) extends TreeNode(name) {
62 |
63 | lazy val children = opt map { x ⇒ makeTreeNode(x, "Some") } toList
64 |
65 | }
66 |
67 | case class EitherNode(name: String, either: Either[Any, Any]) extends TreeNode(name) {
68 |
69 | lazy val children = either match {
70 | case Left(obj) ⇒ List(makeTreeNode(obj, "Left"))
71 | case Right(obj) ⇒ List(makeTreeNode(obj, "Right"))
72 | }
73 |
74 | }
75 |
76 | case class PairNode(name: String, pair: (Any, Any)) extends TreeNode(name) {
77 |
78 | lazy val children = List(makeTreeNode(pair._1, "_1"), makeTreeNode(pair._2, "_2"))
79 |
80 | }
81 |
82 | case class TodoNode(name: String, obj: Any) extends TreeNode(name) {
83 |
84 | val children = Nil
85 |
86 | override def toString = name + ": " + obj
87 |
88 | }
89 |
90 | def makeTreeNode(obj: Any, name: String = ""): TreeNode = obj match {
91 | case astNode: AstNode ⇒
92 | AstNodeNode(name, astNode)
93 | case token: Token ⇒
94 | TokenNode(name, token)
95 | case list: List[_] ⇒
96 | ListNode(name, list)
97 | case Some(x) ⇒
98 | makeTreeNode(x, name)
99 | case None ⇒
100 | OptionNode(name, None)
101 | case either: Either[_, _] ⇒
102 | EitherNode(name, either)
103 | case pair: (_, _) ⇒
104 | PairNode(name, pair)
105 | case _ ⇒
106 | TodoNode(name, obj)
107 | }
108 |
109 | lazy val getRoot = AstNodeNode("root", rootAstNode)
110 |
111 | def getChildCount(obj: AnyRef) = getChildren(obj).length
112 |
113 | def getChild(parent: AnyRef, index: Int): AnyRef = getChildren(parent)(index)
114 |
115 | def getIndexOfChild(parent: AnyRef, child: AnyRef) = getChildren(parent).indexOf(child)
116 |
117 | def isLeaf(obj: AnyRef): Boolean = getChildCount(obj) == 0
118 |
119 | def addTreeModelListener(l: TreeModelListener) {}
120 |
121 | def removeTreeModelListener(l: TreeModelListener) {}
122 |
123 | def valueForPathChanged(path: TreePath, newValue: Any) {}
124 |
125 | private def getChildren(obj: AnyRef) = obj.asInstanceOf[TreeNode].children
126 |
127 | }
128 |
129 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/IndentWithTabsTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class IndentWithTabsTest extends AbstractFormatterTest {
9 |
10 | implicit val formattingPreferences = FormattingPreferences.setPreference(IndentWithTabs, true)
11 |
12 | """class A {
13 | |
14 | |def meth() {
15 | |
16 | |println("42") // wibble
17 | |println("wobble")
18 | |
19 | |}
20 | |
21 | |}""" ==>
22 | """class A {
23 | |
24 | | def meth() {
25 | |
26 | | println("42") // wibble
27 | | println("wobble")
28 | |
29 | | }
30 | |
31 | |}"""
32 |
33 | """val n = 42 +
34 | |3""" ==>
35 | """val n = 42 +
36 | | 3"""
37 |
38 | """val xml =
39 | |bar
40 | |""" ==>
41 | """val xml =
42 | | bar
43 | |"""
44 |
45 | """foo(
46 | |alpha = "foo",
47 | |beta = "bar",
48 | |gamma = false)""" ==>
49 | """foo(
50 | | alpha = "foo",
51 | | beta = "bar",
52 | | gamma = false
53 | |)"""
54 |
55 | """foo(
56 | |"foo",
57 | |"bar",
58 | |false)""" ==>
59 | """foo(
60 | | "foo",
61 | | "bar",
62 | | false
63 | |)"""
64 |
65 | {
66 | implicit val formattingPreferences = FormattingPreferences
67 | .setPreference(IndentWithTabs, true)
68 | .setPreference(DanglingCloseParenthesis, Force)
69 |
70 | """foo(
71 | |alpha = "foo",
72 | |beta = "bar",
73 | |gamma = false)""" ==>
74 | """foo(
75 | | alpha = "foo",
76 | | beta = "bar",
77 | | gamma = false
78 | |)"""
79 |
80 | """foo(
81 | |"foo",
82 | |"bar",
83 | |false)""" ==>
84 | """foo(
85 | | "foo",
86 | | "bar",
87 | | false
88 | |)"""
89 |
90 | """foo(
91 | | "foo",
92 | | "bar",
93 | | false)""" ==>
94 | """foo(
95 | | "foo",
96 | | "bar",
97 | | false
98 | |)"""
99 | }
100 |
101 | {
102 | implicit val formattingPreferences = FormattingPreferences
103 | .setPreference(IndentWithTabs, true)
104 | .setPreference(DanglingCloseParenthesis, Preserve)
105 |
106 | """foo(
107 | |alpha = "foo",
108 | |beta = "bar",
109 | |gamma = false)""" ==>
110 | """foo(
111 | | alpha = "foo",
112 | | beta = "bar",
113 | | gamma = false)"""
114 |
115 | """foo(
116 | |"foo",
117 | |"bar",
118 | |false)""" ==>
119 | """foo(
120 | | "foo",
121 | | "bar",
122 | | false)"""
123 |
124 | """foo(
125 | | "foo",
126 | | "bar",
127 | | false)""" ==>
128 | """foo(
129 | | "foo",
130 | | "bar",
131 | | false)"""
132 | }
133 |
134 | {
135 | implicit val formattingPreferences = FormattingPreferences
136 | .setPreference(IndentWithTabs, true)
137 | .setPreference(DanglingCloseParenthesis, Prevent)
138 |
139 | """foo(
140 | |alpha = "foo",
141 | |beta = "bar",
142 | |gamma = false
143 | |)""" ==>
144 | """foo(
145 | | alpha = "foo",
146 | | beta = "bar",
147 | | gamma = false)"""
148 |
149 | """foo(
150 | |"foo",
151 | |"bar",
152 | |false
153 | |)""" ==>
154 | """foo(
155 | | "foo",
156 | | "bar",
157 | | false)"""
158 |
159 | """foo(
160 | | "foo",
161 | | "bar",
162 | | false
163 | |)""" ==>
164 | """foo(
165 | | "foo",
166 | | "bar",
167 | | false)"""
168 | }
169 |
170 |
171 | override val debug = false
172 |
173 | type Result = CompilationUnit
174 |
175 | def parse(parser: ScalaParser) = parser.compilationUnitOrScript
176 |
177 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/CommentFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class CommentFormatterTest extends AbstractFormatterTest {
9 |
10 | type Result = CompilationUnit
11 |
12 | def parse(parser: ScalaParser) = parser.scriptBody()
13 |
14 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState())
15 |
16 | override val debug = false
17 |
18 | """/**
19 | |*a
20 | |b
21 | | */c""" ==>
22 | """/**
23 | | * a
24 | | * b
25 | | */
26 | |c"""
27 |
28 | """/**
29 | |*a
30 | |b
31 | | */""" ==>
32 | """/**
33 | | * a
34 | | * b
35 | | */
36 | |"""
37 |
38 | """/**
39 | | *
40 | | *Wibble*/
41 | |class X""" ==>
42 | """/**
43 | | *
44 | | * Wibble
45 | | */
46 | |class X"""
47 |
48 | """/***/
49 | |class A""" ==>
50 | """/***/
51 | |class A"""
52 |
53 | """/** */
54 | |class A""" ==>
55 | """/** */
56 | |class A"""
57 |
58 | """/** a */
59 | |class A""" ==>
60 | """/** a */
61 | |class A"""
62 |
63 | """/**
64 | | * {{
65 | | * wibble
66 | | * }}
67 | | */
68 | |class A""" ==>
69 | """/**
70 | | * {{
71 | | * wibble
72 | | * }}
73 | | */
74 | |class A"""
75 |
76 | """/**
77 | |*
78 | |*/""" ==>
79 | """/**
80 | | *
81 | | */
82 | |"""
83 |
84 | """/** a
85 | | * b */""" ==>
86 | """/**
87 | | * a
88 | | * b
89 | | */
90 | |"""
91 |
92 | // nested comments
93 | """/**
94 | |/*
95 | |*/
96 | |*/""" ==>
97 | """/**
98 | | * /*
99 | | * */
100 | | */
101 | |"""
102 |
103 | {
104 | implicit val formattingPreferences = FormattingPreferences.setPreference(MultilineScaladocCommentsStartOnFirstLine, true)
105 |
106 | """/** This method applies f to each
107 | | * element of the given list.
108 | | */""" ==>
109 | """/** This method applies f to each
110 | | * element of the given list.
111 | | */
112 | |"""
113 |
114 | """/** Foo
115 | |Bar
116 | |*Baz */""" ==>
117 | """/** Foo
118 | | * Bar
119 | | * Baz
120 | | */
121 | |"""
122 |
123 | """/** Foo
124 | |*/""" ==>
125 | """/** Foo
126 | | */
127 | |"""
128 |
129 | """/**
130 | |*/""" ==>
131 | """/**
132 | | */
133 | |"""
134 | }
135 |
136 | {
137 | implicit val formattingPreferences = FormattingPreferences.setPreference(PlaceScaladocAsterisksBeneathSecondAsterisk, true)
138 |
139 | """/** This method applies f to each
140 | | * element of the given list.
141 | | */""" ==>
142 | """/**
143 | | * This method applies f to each
144 | | * element of the given list.
145 | | */
146 | |"""
147 |
148 | """/** Foo
149 | |Bar
150 | |*Baz */""" ==>
151 | """/**
152 | | * Foo
153 | | * Bar
154 | | * Baz
155 | | */
156 | |"""
157 |
158 | """/** Foo
159 | |*/""" ==>
160 | """/**
161 | | * Foo
162 | | */
163 | |"""
164 |
165 | """/**
166 | |*/""" ==>
167 | """/**
168 | | */
169 | |"""
170 | }
171 |
172 | {
173 | implicit val formattingPreferences = FormattingPreferences
174 | .setPreference(MultilineScaladocCommentsStartOnFirstLine, true)
175 | .setPreference(PlaceScaladocAsterisksBeneathSecondAsterisk, true)
176 | """/** This method applies f to each
177 | | * element of the given list.
178 | | */""" ==>
179 | """/** This method applies f to each
180 | | * element of the given list.
181 | | */
182 | |"""
183 |
184 | """/** Foo
185 | |Bar
186 | |*Baz */""" ==>
187 | """/** Foo
188 | | * Bar
189 | | * Baz
190 | | */
191 | |"""
192 |
193 | """/** Foo
194 | |*/""" ==>
195 | """/** Foo
196 | | */
197 | |"""
198 |
199 | """/**
200 | |*/""" ==>
201 | """/**
202 | | */
203 | |"""
204 |
205 | """/** This method applies f to each
206 | | * element of the given list.
207 | | */""" ==>
208 | """/** This method applies f to each
209 | | * element of the given list.
210 | | */
211 | |"""
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/ParenAndBracketSpacingTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.formatter.preferences._
4 |
5 | class ParenAndBracketSpacingTest extends AbstractExpressionFormatterTest {
6 |
7 | {
8 | implicit val formattingPreferences = FormattingPreferences.setPreference(SpaceInsideParentheses, true)
9 | "()" ==> "()"
10 | "(a: Int) => 3" ==> "( a: Int ) => 3"
11 | "(3)" ==> "( 3 )"
12 | "(3, 4)" ==> "( 3, 4 )"
13 | "for (n <- 1 to 10) yield foo(n, n)" ==> "for ( n <- 1 to 10 ) yield foo( n, n )"
14 | }
15 |
16 | {
17 | implicit val formattingPreferences = FormattingPreferences.setPreference(SpaceInsideBrackets, true)
18 | "x: List[String]" ==> "x: List[ String ]"
19 | "foo[Bar](baz)" ==> "foo[ Bar ](baz)"
20 | "{ class A[B] { private[this] val bob } }" ==> "{ class A[ B ] { private[ this ] val bob } }"
21 | "super[X].y" ==> "super[ X ].y"
22 | "foo[Bar](baz)[Biz]" ==> "foo[ Bar ](baz)[ Biz ]"
23 | "foo[Bar][Baz][Buz]" ==> "foo[ Bar ][ Baz ][ Buz ]"
24 |
25 | """foo(
26 | |alpha = "foo",
27 | |beta = bar match {
28 | | case _ => "bar"
29 | |},
30 | |gamma = false)""" ==>
31 | """foo(
32 | | alpha = "foo",
33 | | beta = bar match {
34 | | case _ => "bar"
35 | | },
36 | | gamma = false
37 | |)"""
38 |
39 | """foo(
40 | |alpha = "foo",
41 | |beta = bar(
42 | |a = 1
43 | |),
44 | |gamma = false)""" ==>
45 | """foo(
46 | | alpha = "foo",
47 | | beta = bar(
48 | | a = 1
49 | | ),
50 | | gamma = false
51 | |)"""
52 |
53 | """foo(
54 | |arg = bar(
55 | |baz = "a"
56 | |).xyz
57 | |)""" ==>
58 | """foo(
59 | | arg = bar(
60 | | baz = "a"
61 | | ).xyz
62 | |)"""
63 | }
64 |
65 | {
66 | implicit val formattingPreferences = FormattingPreferences.setPreference(DanglingCloseParenthesis, Force)
67 | """foo(
68 | |alpha = "foo",
69 | |beta = "bar",
70 | |gamma = false)""" ==>
71 | """foo(
72 | | alpha = "foo",
73 | | beta = "bar",
74 | | gamma = false
75 | |)"""
76 |
77 | """foo(
78 | |"foo",
79 | |"bar",
80 | |false)""" ==>
81 | """foo(
82 | | "foo",
83 | | "bar",
84 | | false
85 | |)"""
86 | }
87 |
88 | {
89 | implicit val formattingPreferences = FormattingPreferences.setPreference(DanglingCloseParenthesis, Preserve)
90 | """foo(
91 | |alpha = "foo",
92 | |beta = "bar",
93 | |gamma = false)""" ==>
94 | """foo(
95 | | alpha = "foo",
96 | | beta = "bar",
97 | | gamma = false)"""
98 |
99 | """foo(
100 | |alpha = "foo",
101 | |beta = "bar",
102 | |gamma = false
103 | |)""" ==>
104 | """foo(
105 | | alpha = "foo",
106 | | beta = "bar",
107 | | gamma = false
108 | |)"""
109 |
110 | """foo(
111 | |"foo",
112 | |"bar",
113 | |false)""" ==>
114 | """foo(
115 | | "foo",
116 | | "bar",
117 | | false)"""
118 |
119 | """foo(
120 | |"foo",
121 | |"bar",
122 | |false
123 | |)""" ==>
124 | """foo(
125 | | "foo",
126 | | "bar",
127 | | false
128 | |)"""
129 | }
130 |
131 | {
132 | implicit val formattingPreferences = FormattingPreferences.setPreference(DanglingCloseParenthesis, Prevent)
133 | """foo(
134 | |alpha = "foo",
135 | |beta = "bar",
136 | |gamma = false)""" ==>
137 | """foo(
138 | | alpha = "foo",
139 | | beta = "bar",
140 | | gamma = false)"""
141 |
142 | """foo(
143 | |alpha = "foo",
144 | |beta = "bar",
145 | |gamma = false
146 | |)""" ==>
147 | """foo(
148 | | alpha = "foo",
149 | | beta = "bar",
150 | | gamma = false)"""
151 |
152 | """foo(
153 | |"foo",
154 | |"bar",
155 | |false)""" ==>
156 | """foo(
157 | | "foo",
158 | | "bar",
159 | | false)"""
160 |
161 | """foo(
162 | |"foo",
163 | |"bar",
164 | |false
165 | |)""" ==>
166 | """foo(
167 | | "foo",
168 | | "bar",
169 | | false)"""
170 |
171 | """foo(
172 | |alpha = "foo",
173 | |beta = "bar",
174 | |gamma = false // comment
175 | |)""" ==>
176 | """foo(
177 | | alpha = "foo",
178 | | beta = "bar",
179 | | gamma = false // comment
180 | |)"""
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/Tokens.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | object Tokens {
4 |
5 | val PACKAGE = TokenType("PACKAGE")
6 | val STAR = TokenType("STAR")
7 | val WHILE = TokenType("WHILE")
8 | val CASE = TokenType("CASE")
9 | val NEW = TokenType("NEW")
10 | val DO = TokenType("DO")
11 | val EQUALS = TokenType("EQUALS")
12 | val SUBTYPE = TokenType("SUBTYPE")
13 | val EOF = TokenType("EOF")
14 | val SEALED = TokenType("SEALED")
15 | val TYPE = TokenType("TYPE")
16 | val LBRACKET = TokenType("LBRACKET")
17 | val FINAL = TokenType("FINAL")
18 | val RPAREN = TokenType("RPAREN")
19 | val IMPORT = TokenType("IMPORT")
20 | val STRING_LITERAL = TokenType("STRING_LITERAL")
21 | val STRING_PART = TokenType("STRING_PART")
22 | val FLOATING_POINT_LITERAL = TokenType("FLOATING_POINT_LITERAL")
23 | val EXCLAMATION = TokenType("EXCLAMATION")
24 | val NEWLINES = TokenType("NEWLINES")
25 | val THIS = TokenType("THIS")
26 | val RETURN = TokenType("RETURN")
27 | val VAL = TokenType("VAL")
28 | val VAR = TokenType("VAR")
29 | val SUPER = TokenType("SUPER")
30 | val RBRACE = TokenType("RBRACE")
31 | val LINE_COMMENT = TokenType("LINE_COMMENT")
32 | val PRIVATE = TokenType("PRIVATE")
33 | val NULL = TokenType("NULL")
34 | val ELSE = TokenType("ELSE")
35 | val CHARACTER_LITERAL = TokenType("CHARACTER_LITERAL")
36 | val MATCH = TokenType("MATCH")
37 | val TRY = TokenType("TRY")
38 | val WS = TokenType("WS")
39 | val SUPERTYPE = TokenType("SUPERTYPE")
40 | val INTEGER_LITERAL = TokenType("INTEGER_LITERAL")
41 | val OP = TokenType("OP")
42 | val USCORE = TokenType("USCORE")
43 | val LOWER = TokenType("LOWER")
44 | val CATCH = TokenType("CATCH")
45 | val FALSE = TokenType("FALSE")
46 | val VARID = TokenType("VARID")
47 | val THROW = TokenType("THROW")
48 | val UPPER = TokenType("UPPER")
49 | val PROTECTED = TokenType("PROTECTED")
50 | val CLASS = TokenType("CLASS")
51 | val DEF = TokenType("DEF")
52 | val LBRACE = TokenType("LBRACE")
53 | val FOR = TokenType("FOR")
54 | val LARROW = TokenType("LARROW")
55 | val RARROW = TokenType("RARROW")
56 | val ABSTRACT = TokenType("ABSTRACT")
57 | val LPAREN = TokenType("LPAREN")
58 | val IF = TokenType("IF")
59 | val AT = TokenType("AT")
60 | val MULTILINE_COMMENT = TokenType("MULTILINE_COMMENT")
61 | val SYMBOL_LITERAL = TokenType("SYMBOL_LITERAL")
62 | val OBJECT = TokenType("OBJECT")
63 | val COMMA = TokenType("COMMA")
64 | val YIELD = TokenType("YIELD")
65 | val TILDE = TokenType("TILDE")
66 | val PLUS = TokenType("PLUS")
67 | val PIPE = TokenType("PIPE")
68 | val VIEWBOUND = TokenType("VIEWBOUND")
69 | val RBRACKET = TokenType("RBRACKET")
70 | val DOT = TokenType("DOT")
71 | val WITH = TokenType("WITH")
72 | val IMPLICIT = TokenType("IMPLICIT")
73 | val LAZY = TokenType("LAZY")
74 | val TRAIT = TokenType("TRAIT")
75 | val HASH = TokenType("HASH")
76 | val FORSOME = TokenType("FORSOME")
77 | val MINUS = TokenType("MINUS")
78 | val TRUE = TokenType("TRUE")
79 | val SEMI = TokenType("SEMI")
80 | val COLON = TokenType("COLON")
81 | val OTHERID = TokenType("OTHERID")
82 | val NEWLINE = TokenType("NEWLINE")
83 | val FINALLY = TokenType("FINALLY")
84 | val OVERRIDE = TokenType("OVERRIDE")
85 | val ARROW = TokenType("ARROW")
86 | val EXTENDS = TokenType("EXTENDS")
87 | val INTERPOLATION_ID = TokenType("INTERPOLATION_ID")
88 | val XML_START_OPEN = TokenType("XML_START_OPEN", isXml = true)
89 | val XML_EMPTY_CLOSE = TokenType("XML_EMPTY_CLOSE", isXml = true)
90 | val XML_TAG_CLOSE = TokenType("XML_TAG_CLOSE", isXml = true)
91 | val XML_END_OPEN = TokenType("XML_END_OPEN", isXml = true)
92 | val XML_WHITESPACE = TokenType("XML_WHITESPACE", isXml = true)
93 | val XML_ATTR_EQ = TokenType("XML_ATTR_EQ", isXml = true)
94 | val XML_ATTR_VALUE = TokenType("XML_ATTR_VALUE", isXml = true)
95 | val XML_NAME = TokenType("XML_NAME", isXml = true)
96 | val XML_PCDATA = TokenType("XML_PCDATA", isXml = true)
97 | val XML_COMMENT = TokenType("XML_COMMENT", isXml = true)
98 | val XML_CDATA = TokenType("XML_CDATA", isXml = true)
99 | val XML_UNPARSED = TokenType("XML_UNPARSED", isXml = true)
100 | val XML_PROCESSING_INSTRUCTION = TokenType("XML_PROCESSING_INSTRUCTION", isXml = true)
101 |
102 | val KEYWORDS = Set(
103 | ABSTRACT, CASE, CATCH, CLASS, DEF,
104 | DO, ELSE, EXTENDS, FINAL,
105 | FINALLY, FOR, FORSOME, IF, IMPLICIT,
106 | IMPORT, LAZY, MATCH, NEW,
107 | OBJECT, OVERRIDE, PACKAGE, PRIVATE, PROTECTED,
108 | RETURN, SEALED, SUPER, THIS,
109 | THROW, TRAIT, TRY, TYPE,
110 | VAL, VAR, WHILE, WITH, YIELD
111 | )
112 |
113 | val COMMENTS = Set(LINE_COMMENT, MULTILINE_COMMENT, XML_COMMENT)
114 |
115 | val IDS = Set(VARID, PLUS, MINUS, STAR, PIPE, TILDE, EXCLAMATION)
116 |
117 | val LITERALS = Set(CHARACTER_LITERAL, INTEGER_LITERAL, FLOATING_POINT_LITERAL, STRING_LITERAL, STRING_PART, SYMBOL_LITERAL, TRUE, FALSE, NULL)
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/utils/Utils.scala:
--------------------------------------------------------------------------------
1 | package scalariform.utils
2 |
3 | import java.io.FileOutputStream
4 | import java.io.FileInputStream
5 | import java.io.IOException
6 |
7 | object Utils {
8 |
9 | def when[T](b: Boolean)(x: ⇒ T): Option[T] = if (b) Some(x) else None
10 |
11 | def asInstanceOf[T](o: Any) = if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None
12 |
13 | def checkNotNull[T](item: T): T = { require(item != null); item }
14 |
15 | implicit def boolean2ImpliesWrapper(b: Boolean): ImpliesWrapper = new ImpliesWrapper(b)
16 |
17 | class ImpliesWrapper(b: Boolean) {
18 | def implies(b2: ⇒ Boolean) = if (!b) true else b2
19 | }
20 |
21 | implicit def string2PimpedString(s: String) = new PimpedString(s)
22 |
23 | class PimpedString(s: String) {
24 | def toIntOpt: Option[Int] = try Some(s.toInt) catch { case _: NumberFormatException ⇒ None }
25 | }
26 |
27 | def stagger[T](iterable: Iterable[T]) = iterable zip iterable.tail
28 |
29 | def pairWithPrevious[T](iterable: Iterable[T]): List[(Option[T], T)] = {
30 | if (iterable.isEmpty)
31 | Nil
32 | else {
33 | val previous = None :: (iterable.init map Some[T]).toList
34 | previous zip iterable
35 | }
36 | }
37 |
38 | def withPreviousAndNext[T](iterable: Iterable[T]): List[(Option[T], T, Option[T])] = {
39 | if (iterable.isEmpty)
40 | Nil
41 | else {
42 | val previous = None :: (iterable.init map Some[T]).toList
43 | val next = (iterable.tail map Some[T]).toList ::: List(None)
44 | previous zip iterable zip next map { case ((a, b), c) ⇒ (a, b, c) }
45 | }
46 | }
47 |
48 | import scala.reflect.Manifest
49 | implicit def any2optionable(x: AnyRef) = new {
50 | def matchInstance[B](implicit m: Manifest[B]): Option[B] =
51 | if (Manifest.singleType(x) <:< m)
52 | Some(x.asInstanceOf[B])
53 | else
54 | None
55 | }
56 |
57 | def groupBy[A](eq: (A, A) ⇒ Boolean, lst: List[A]): List[List[A]] =
58 | lst match {
59 | case Nil ⇒ Nil
60 | case (x :: xs) ⇒ {
61 | val (ys, zs) = xs span { eq(x, _) }
62 | (x :: ys) :: groupBy(eq, zs)
63 | }
64 | }
65 |
66 | // Swing ---------------------
67 |
68 | def onSwingThread(proc: ⇒ Unit) = javax.swing.SwingUtilities.invokeLater(new Runnable() { def run() = proc })
69 |
70 | import javax.swing.JTree
71 | import javax.swing.tree._
72 |
73 | def expandAll(tree: JTree) {
74 | val root = tree.getModel().getRoot()
75 | expandAll(tree, new TreePath(root))
76 | }
77 |
78 | private def expandAll(tree: JTree, parent: TreePath) {
79 | val node = parent.getLastPathComponent()
80 | val model = tree.getModel
81 | val children = 0 until model.getChildCount(node) map { model.getChild(node, _) }
82 | for (child ← children) {
83 | val path = parent.pathByAddingChild(child)
84 | expandAll(tree, path)
85 | }
86 | tree.expandPath(parent)
87 | }
88 |
89 | // File ------------------
90 |
91 | def writeText(file: java.io.File, text: String, encodingOpt: Option[String] = None) {
92 | import java.io.{ OutputStreamWriter, FileOutputStream }
93 | val encoding = encodingOpt getOrElse (System getProperty "file.encoding")
94 | val writer = new OutputStreamWriter(new FileOutputStream(file), encoding)
95 | try
96 | writer.write(text)
97 | finally
98 | writer.close()
99 | }
100 |
101 | @throws(classOf[IOException])
102 | def withFileInputStream[T](fileName: String)(p: FileInputStream ⇒ T): T = {
103 | var fis: FileInputStream = null
104 | try {
105 | fis = new FileInputStream(fileName)
106 | p(fis)
107 | } finally
108 | if (fis != null)
109 | fis.close()
110 | }
111 |
112 | @throws(classOf[IOException])
113 | def withFileOutputStream[T](fileName: String)(p: FileOutputStream ⇒ T): T = {
114 | var fis: FileOutputStream = null
115 | try {
116 | fis = new FileOutputStream(fileName)
117 | p(fis)
118 | } finally
119 | if (fis != null)
120 | fis.close()
121 | }
122 |
123 | def time[T](s: String)(f: ⇒ T): T = {
124 | val start = System.currentTimeMillis
125 | val result = f
126 | val duration = System.currentTimeMillis - start
127 | println(s + ": " + duration + "ms")
128 | result
129 | }
130 |
131 | def digit2int(ch: Char, base: Int): Int =
132 | if ('0' <= ch && ch <= '9' && ch < '0' + base)
133 | ch - '0'
134 | else if ('A' <= ch && ch < 'A' + base - 10)
135 | ch - 'A' + 10
136 | else if ('a' <= ch && ch < 'a' + base - 10)
137 | ch - 'a' + 10
138 | else
139 | -1
140 |
141 | def deleteRange(text: String, range: Range): String =
142 | replaceRange(text, range, replacement = "")
143 |
144 | def replaceRange(text: String, range: Range, replacement: String): String =
145 | text.take(range.offset) + replacement + text.drop(range.offset + range.length)
146 |
147 | }
148 |
149 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/UnicodeEscapeReader.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.CharConstants.SU
4 | import scalariform.utils.Utils._
5 |
6 | object UnicodeEscapeDecoder {
7 |
8 | /**
9 | * Decode unicode escapes of the form "\u0061" in the given text.
10 | * If forgiveErrors is true, then no exception will be thrown on malformed escapes.
11 | */
12 | @throws(classOf[ScalaLexerException])
13 | def decode(text: String, forgiveErrors: Boolean = false): String =
14 | new UnicodeEscapeReader(text, forgiveErrors).mkString
15 |
16 | }
17 |
18 | trait IUnicodeEscapeReader extends Iterator[Char] {
19 |
20 | val text: String
21 |
22 | /**
23 | * @return true if all the available characters have been read.
24 | */
25 | def isEof: Boolean
26 |
27 | /**
28 | * @return the next character from the post-decoded text
29 | */
30 | @throws(classOf[ScalaLexerException])
31 | def read(): Char
32 |
33 | /**
34 | * @return the corresponding unicode escape sequence if the last character read was decoded, otherwise None.
35 | */
36 | def unicodeEscapeOpt: Option[String]
37 |
38 | def next() = read()
39 |
40 | def hasNext = !isEof
41 |
42 | /**
43 | * Return a clone of this reader initialised to the current state
44 | */
45 | def copy: IUnicodeEscapeReader
46 |
47 | }
48 |
49 | class UnicodeEscapeReader(val text: String, forgiveErrors: Boolean = false) extends IUnicodeEscapeReader {
50 |
51 | private var pos: Int = 0
52 |
53 | private var unicodeEscapeSequence: String = null
54 |
55 | /**
56 | * To distinguish cases like "\\u" from unicode escape sequences.
57 | */
58 | private var consecutiveBackslashCount = 0
59 |
60 | def copy: UnicodeEscapeReader = {
61 | val reader = new UnicodeEscapeReader(text, forgiveErrors)
62 | reader.pos = pos
63 | reader.unicodeEscapeSequence = unicodeEscapeSequence
64 | reader.consecutiveBackslashCount = consecutiveBackslashCount
65 | reader
66 | }
67 |
68 | def isEof = pos >= text.length
69 |
70 | @throws(classOf[ScalaLexerException])
71 | def read(): Char = {
72 | val ch = consumeNextCharacter()
73 | unicodeEscapeSequence = null
74 | if (ch == '\\')
75 | if (nextChar == 'u' && consecutiveBackslashCount % 2 == 0) {
76 | consecutiveBackslashCount = 0
77 | readUnicodeChar(pos - 1)
78 | } else {
79 | consecutiveBackslashCount += 1
80 | ch
81 | }
82 | else {
83 | consecutiveBackslashCount = 0
84 | ch
85 | }
86 | }
87 |
88 | def unicodeEscapeOpt: Option[String] = Option(unicodeEscapeSequence)
89 |
90 | private def consumeNextCharacter(): Char = {
91 | val result = safeGet(pos)
92 | pos += 1
93 | result
94 | }
95 |
96 | private def nextChar = safeGet(pos)
97 |
98 | private def safeGet(pos: Int): Char = if (pos >= text.length) SU else text(pos)
99 |
100 | private def readUnicodeChar(startPos: Int): Char = {
101 | this.unicodeEscapeSequence = consumeUnicodeEscape()
102 | val decodedChar = decodeUnicodeChar(unicodeEscapeSequence takeRight 4 toList, unicodeEscapeSequence, startPos)
103 | decodedChar
104 | }
105 |
106 | private def consumeUnicodeEscape(): String = {
107 | val sb = new StringBuilder
108 | sb.append('\\')
109 |
110 | // Repeating u's are allowed in Unicode escapes (bizarrely enough):
111 | do sb.append(consumeNextCharacter())
112 | while (nextChar == 'u')
113 |
114 | for (n ← 1 to 4)
115 | sb.append(consumeNextCharacter())
116 |
117 | sb.toString
118 | }
119 |
120 | private def decodeUnicodeChar(digits: List[Char], unicodeEscapeSequence: String, startPos: Int): Char = {
121 | val List(digit1, digit2, digit3, digit4) = digits.map(digit2int(_, base = 16))
122 | if (digit1 < 0 || digit2 < 0 || digit3 < 0 || digit4 < 0)
123 | if (forgiveErrors)
124 | ' '
125 | else {
126 | val (line, column) = lineAndColumn(startPos)
127 | throw new ScalaLexerException("[" + line + ":" + column + "] error in unicode escape: '" + unicodeEscapeSequence + "'")
128 | }
129 | else
130 | (digit1 << 12 | digit2 << 8 | digit3 << 4 | digit4).toChar
131 | }
132 |
133 | private def lineAndColumn(offset: Int): (Int, Int) = {
134 | var line = 1
135 | var column = 1
136 | for (i ← 0 until offset) {
137 | if (text(i) == '\n') {
138 | line += 1
139 | column = 1
140 | } else
141 | column += 1
142 | }
143 | (line, column)
144 | }
145 |
146 | }
147 |
148 | class NoUnicodeEscapeReader(val text: String) extends IUnicodeEscapeReader {
149 |
150 | private var pos = 0
151 |
152 | def copy = {
153 | val reader = new NoUnicodeEscapeReader(text)
154 | reader.pos = pos
155 | reader
156 | }
157 |
158 | def isEof: Boolean = pos >= text.length
159 |
160 | def read(): Char = {
161 | val result = if (isEof) SU else text(pos)
162 | pos += 1
163 | result
164 | }
165 |
166 | def unicodeEscapeOpt: Option[String] = None
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/XmlExpressionFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class XmlExpressionFormatterTest extends AbstractExpressionFormatterTest {
9 |
10 | "" ==> ""
11 |
12 | "" ==> ""
13 | "" ==> ""
14 |
15 | "{foo}" ==> "{ foo }"
16 | "{foo}{bar}" ==> "{ foo }{ bar }"
17 |
18 | "1" ==> "1"
19 | " 1 " ==> " 1 "
20 | " b {c} d {e} f " ==> " b { c } d { e } f "
21 | "ABORT: { msg }" ==> "ABORT: { msg }" // See issue #27
22 | " {b} " ==> " { b } "
23 |
24 | """
25 | |{foo}
26 | |""" ==>
27 | """
28 | | { foo }
29 | |"""
30 |
31 | """
32 | |foo
33 | |{bar}
34 | |baz
35 | |""" ==>
36 | """
37 | | foo
38 | | { bar }
39 | | baz
40 | |"""
41 |
42 | """42
43 | |""" ==>
44 | """
45 | | 42
46 | |"""
47 |
48 | """b()""" ==>
50 | """b()"""
54 |
55 | """b()""" ==>
57 | """b()"""
61 |
62 | """
63 | |1""" ==>
64 | """
65 | | 1
66 | |"""
67 |
68 | """1
69 | |2
70 | |3
71 | |""" ==>
72 | """
73 | | 1
74 | | 2
75 | | 3
76 | |"""
77 |
78 | """{
79 | |{
80 | |println("Foo")
81 | |}
82 | |}""" ==>
83 | """{
84 | | {
85 | | println("Foo")
86 | | }
87 | |}"""
88 |
89 | """{
90 | |
91 | | { name.get }
92 | | { version.get }
93 | |}""" ==>
94 | """{
95 | |
96 | | { name.get }
97 | | { version.get }
98 | |
99 | |}"""
100 |
101 | """{
102 | |val b =
103 | |
104 | |}""" ==>
105 | """{
106 | | val b =
107 | |
108 | |
109 | |}"""
110 |
111 | """{
112 | |
113 | | { 1 } { 1 }
;
114 | |
115 | | { 1 }{ 1 }
116 | |
117 | |}""" ==>
118 | """{
119 | |
120 | | { 1 } { 1 }
;
121 | |
122 | | { 1 }{ 1 }
123 | |
124 | |}"""
125 |
126 |
127 | """{
128 | |{ }
129 | | {
130 | |
131 | | }
132 | |}""" ==>
133 | """{
134 | | { }
135 | | {
136 | |
137 | |
138 | |
139 | | }
140 | |}"""
141 |
142 | """
143 | |{
144 | |42
145 | |}
146 | |""" ==>
147 | """
148 | | {
149 | | 42
150 | | }
151 | |"""
152 |
153 | """
154 | |42
155 | |{
156 | |234
157 | |}
158 | |""" ==>
159 | """
160 | | 42
161 | | {
162 | | 234
163 | | }
164 | |"""
165 |
166 | """
167 | |{
168 | |println("wibble")
169 | |}
170 | |""" ==>
171 | """
172 | | {
173 | | println("wibble")
174 | | }
175 | |"""
176 |
177 | """42{
178 | |println("foo")}""" ==>
179 | """42{
180 | | println("foo")
181 | |}"""
182 |
183 | """{
184 | |
185 | |val x =
186 | |
187 | |
188 | |42
189 | |
190 | |
191 | |}""" ==>
192 | """{
193 | |
194 | | val x =
195 | |
196 | |
197 | | 42
198 | |
199 | |
200 | |}"""
201 |
202 | """{
203 | |
204 | |val x =
205 | |
206 | |
207 | |
208 | |42
209 | |
210 | |
211 | |}""" ==>
212 | """{
213 | |
214 | | val x =
215 | |
216 | |
217 | |
218 | | 42
219 | |
220 | |
221 | |}"""
222 |
223 | """{
224 | |a
225 | |
226 | |}""" ==>
227 | """{
228 | | a
229 | |
230 | |}"""
231 |
232 | """a match {
233 | |
234 | | case c
235 | | =>
236 | |
237 | |}""" ==>
238 | """a match {
239 | |
240 | | case
241 | | c
242 | | =>
243 | |
244 | |}"""
245 |
246 | {
247 | implicit val formattingPreferences = FormattingPreferences.setPreference(FormatXml, false)
248 |
249 | """
250 | |b""" ==>
251 | """
252 | |b"""
253 |
254 | """a match {
255 | |
256 | | case c
257 | | =>
258 | |
259 | |}""" ==>
260 | """a match {
261 | |
262 | | case c
263 | | =>
264 | |
265 | |}"""
266 |
267 | }
268 |
269 | "{ }" ==> "{ }"
270 |
271 | "a match { case {_*} => }" ==> "a match { case { _* } => }"
272 |
273 | override val debug = false
274 |
275 | }
276 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/lexer/NewlineInferencer.scala:
--------------------------------------------------------------------------------
1 | package scalariform.lexer
2 |
3 | import scalariform.lexer.Tokens._
4 |
5 | /**
6 | * Logic for promoting intertoken whitespace/comments to a NEWLINE or NEWLINES token as required.
7 | */
8 | class NewlineInferencer(delegate: WhitespaceAndCommentsGrouper) extends Iterator[Token] {
9 |
10 | import NewlineInferencer._
11 |
12 | /**
13 | * Contains the next unprocessed token from the delegate, or null if we've processed them all.
14 | */
15 | private var nextToken: Token = if (delegate.hasNext) delegate.next() else null
16 |
17 | private var previousToken: Token = _
18 |
19 | /**
20 | * If not null, we emit this token rather than looking at nextToken (used for inserting NEWLINE or NEWLINES
21 | * into the stream).
22 | */
23 | private var tokenToEmitNextTime: Token = _
24 |
25 | /**
26 | * Keeps track of the nested regions which allow multiple statements or not. An item in the stack indicates the
27 | * expected closing token type for that region.
28 | */
29 | private var regionMarkerStack: List[TokenType] = Nil
30 |
31 | def hasNext = nextToken != null || tokenToEmitNextTime != null
32 |
33 | def next(): Token = {
34 | val token =
35 | if (tokenToEmitNextTime == null)
36 | fetchNextToken()
37 | else {
38 | val result = tokenToEmitNextTime
39 | tokenToEmitNextTime = null
40 | result
41 | }
42 | updateRegionStack(token.tokenType, nextToken)
43 | previousToken = token
44 | token
45 | }
46 |
47 | /**
48 | * Multiple statements are allowed immediately inside "{..}" regions, but disallowed immediately inside "[..]", "(..)"
49 | * and "case ... =>" regions.
50 | */
51 | private def updateRegionStack(tokenType: TokenType, nextToken: Token) =
52 | tokenType match {
53 | case LBRACE ⇒
54 | regionMarkerStack ::= RBRACE
55 | case LPAREN ⇒
56 | regionMarkerStack ::= RPAREN
57 | case LBRACKET ⇒
58 | regionMarkerStack ::= RBRACKET
59 | case CASE if nextToken != null ⇒
60 | val followingTokenType = nextToken.tokenType
61 | // "case class" and "case object" are excluded from the usual "case .. =>" region.
62 | if (followingTokenType != CLASS && followingTokenType != OBJECT)
63 | regionMarkerStack ::= ARROW
64 | case tokenType if regionMarkerStack.headOption == Some(tokenType) ⇒
65 | regionMarkerStack = regionMarkerStack.tail
66 | case _ ⇒
67 | }
68 |
69 | private def fetchNextToken(): Token = {
70 | val token = nextToken
71 | if (delegate.hasNext)
72 | nextToken = delegate.next()
73 | else
74 | nextToken = null
75 | if (shouldTranslateToNewline(previousToken, token, nextToken))
76 | translateToNewline(token)
77 | else
78 | token
79 | }
80 |
81 | private def translateToNewline(currentToken: Token): Token = {
82 | val currentHiddenTokens = currentToken.associatedWhitespaceAndComments
83 | val rawText = delegate.text.substring(currentHiddenTokens.offset, currentHiddenTokens.lastCharacterOffset + 1)
84 | val text = if (currentHiddenTokens.containsUnicodeEscape) currentHiddenTokens.text else rawText
85 | val tokenType = if (containsBlankLine(text)) NEWLINES else NEWLINE
86 | val newlineToken = Token(tokenType, text, currentHiddenTokens.offset, rawText)
87 | currentToken.associatedWhitespaceAndComments_ = NoHiddenTokens
88 | newlineToken.associatedWhitespaceAndComments_ = currentHiddenTokens
89 | tokenToEmitNextTime = currentToken
90 | newlineToken
91 | }
92 |
93 | private def containsNewline(hiddenTokens: HiddenTokens) =
94 | hiddenTokens.exists(_.text contains '\n')
95 |
96 | private def shouldTranslateToNewline(previousToken: Token, currentToken: Token, nextToken: Token): Boolean = {
97 | val hiddenTokens = currentToken.associatedWhitespaceAndComments
98 | val currentTokenType = currentToken.tokenType
99 | if (!containsNewline(hiddenTokens))
100 | false
101 | else if (TOKENS_WHICH_CANNOT_BEGIN_A_STATEMENT contains currentTokenType)
102 | false
103 | // else if (currentTokenType == CASE && !followingTokenIsClassOrObject(nextToken))
104 | // false
105 | else if (regionMarkerStack.nonEmpty && regionMarkerStack.head != RBRACE)
106 | false
107 | else
108 | return previousToken != null && (TOKENS_WHICH_CAN_END_A_STATEMENT contains previousToken.tokenType)
109 | }
110 |
111 | private def followingTokenIsClassOrObject(nextToken: Token): Boolean =
112 | nextToken != null && (nextToken.tokenType == CLASS || nextToken.tokenType == OBJECT)
113 |
114 | private def containsBlankLine(s: String): Boolean = {
115 | var i = 0
116 | var inBlankLine = false
117 | while (i < s.length) {
118 | val c = s(i)
119 | if (inBlankLine) {
120 | if (c == '\n' || c == '\f')
121 | return true
122 | else if (c > ' ')
123 | inBlankLine = false
124 | } else if (c == '\n' || c == '\f')
125 | inBlankLine = true
126 | i += 1
127 | }
128 | false
129 | }
130 |
131 | }
132 |
133 | object NewlineInferencer {
134 |
135 | private val TOKENS_WHICH_CAN_END_A_STATEMENT: Set[TokenType] = Set(
136 | INTEGER_LITERAL, FLOATING_POINT_LITERAL, CHARACTER_LITERAL, STRING_LITERAL, SYMBOL_LITERAL, VARID, OTHERID, PLUS,
137 | MINUS, STAR, PIPE, TILDE, EXCLAMATION, THIS, NULL, TRUE, FALSE, RETURN, TYPE, XML_EMPTY_CLOSE, XML_TAG_CLOSE,
138 | XML_COMMENT, XML_CDATA, XML_UNPARSED, XML_PROCESSING_INSTRUCTION, USCORE, RPAREN, RBRACKET, RBRACE
139 | )
140 |
141 | private val TOKENS_WHICH_CANNOT_BEGIN_A_STATEMENT: Set[TokenType] = Set(
142 | CATCH, ELSE, EXTENDS, FINALLY, FORSOME, MATCH, WITH, YIELD, COMMA, DOT, SEMI, COLON, /* USCORE, */ EQUALS,
143 | ARROW, LARROW, RARROW, SUBTYPE, VIEWBOUND, SUPERTYPE, HASH, LBRACKET, RPAREN, RBRACKET, RBRACE
144 | )
145 |
146 | private val BLANK_LINE_PATTERN = """(?s).*\n\s*\n.*"""
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | org.scalariform
6 | scalariform.parent
7 | 0.1.8-SNAPSHOT
8 | pom
9 |
10 |
11 |
12 | scm:git://github.com/daniel-trinh/scalariform.git
13 | https://github.com/daniel-trinh/scalariform
14 |
15 |
16 |
17 | 0.20.0
18 | 2.10.4
19 | UTF-8
20 | 3.0.4
21 | 2.11
22 | 1.0.2
23 | 2_10
24 |
25 |
26 |
27 | ${maven.version}
28 |
29 |
30 |
31 |
32 | scalariform
33 | scalariform.feature
34 | scalariform.update
35 |
36 |
37 |
38 | org.scala-lang
39 | scala-library
40 | ${scala.version}
41 |
42 |
43 |
44 |
45 |
46 | org.eclipse.tycho
47 | tycho-maven-plugin
48 | ${tycho.version}
49 | true
50 |
51 |
52 | org.eclipse.tycho
53 | target-platform-configuration
54 | ${tycho.version}
55 |
56 | p2
57 | consider
58 |
59 |
60 |
61 |
62 |
63 | org.codehaus.mojo
64 | buildnumber-maven-plugin
65 | 1.1
66 |
67 |
68 | validate
69 |
70 | create
71 |
72 |
73 |
74 |
75 | false
76 | false
77 | 7
78 |
79 |
80 |
81 |
82 | org.eclipse.tycho
83 | tycho-packaging-plugin
84 | ${tycho.version}
85 |
86 | '${version.suffix}-'yyyyMMddHHmm'-${buildNumber}'
87 | true
88 |
89 |
90 |
91 | net.alchim31.maven
92 | scala-maven-plugin
93 | 3.1.5
94 |
95 |
96 |
97 | add-source
98 | compile
99 |
100 |
101 |
102 |
103 | ${scala.version}
104 |
105 | -Xmx1024m
106 | -Xss4m
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | kepler
115 | p2
116 | http://download.eclipse.org/releases/kepler
117 |
118 |
119 | sonatype.release
120 | Sonatype maven release repository
121 | https://oss.sonatype.org/content/repositories/releases/
122 | false
123 |
124 |
125 | sonatype.snapshot
126 | Sonatype maven snapshot repository
127 | https://oss.sonatype.org/content/repositories/snapshots
128 |
129 | daily
130 |
131 |
132 |
133 |
134 |
135 | scala-2.10.x
136 |
137 | 2_10
138 |
139 |
140 |
141 | scala-2.11.x
142 |
143 | 2.11.1
144 | 2_11
145 |
146 |
147 |
148 | org.scala-lang.modules
149 | scala-xml_${scala.binary.version}
150 | ${scala.xml.version}
151 |
152 |
153 |
154 |
155 | scala-2.12.x
156 |
157 | 2.12.0-SNAPSHOT
158 | 2_12
159 |
160 |
161 |
162 | org.scala-lang.modules
163 | scala-xml_${scala.binary.version}
164 | ${scala.xml.version}
165 |
166 |
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/scalariform/src/main/scala/com/danieltrinh/scalariform/formatter/TemplateFormatter.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.lexer.Tokens._
4 | import scalariform.lexer.Token
5 |
6 | import scalariform.parser._
7 | import scalariform.utils._
8 | import scalariform.formatter.preferences._
9 |
10 | trait TemplateFormatter { self: HasFormattingPreferences with AnnotationFormatter with HasHiddenTokenInfo with TypeFormatter with ExprFormatter with ScalaFormatter ⇒
11 |
12 | def format(tmplDef: TmplDef)(implicit formatterState: FormatterState): FormatResult = {
13 | val TmplDef(markerTokens, name, typeParamClauseOpt, annotations, accessModifierOpt, paramClausesOpt, templateInheritanceSectionOpt, templateBodyOption) = tmplDef
14 | var formatResult: FormatResult = NoFormatResult
15 | for (typeParamClause ← typeParamClauseOpt)
16 | formatResult ++= format(typeParamClause.contents)
17 |
18 | for (annotation ← annotations) {
19 | formatResult = formatResult.before(annotation.firstToken, CompactEnsuringGap)
20 | formatResult ++= format(annotation)
21 | }
22 |
23 | for {
24 | accessModifier ← accessModifierOpt
25 | astNode ← (paramClausesOpt orElse templateInheritanceSectionOpt orElse templateBodyOption)
26 | firstToken ← astNode.firstTokenOption
27 | } formatResult = formatResult.formatNewlineOrOrdinary(firstToken, CompactEnsuringGap)
28 |
29 | for {
30 | paramClauses ← paramClausesOpt
31 | firstToken ← paramClauses.firstTokenOption
32 | } {
33 | if (annotations.size > 0)
34 | formatResult = formatResult.formatNewlineOrOrdinary(firstToken, CompactEnsuringGap)
35 | val doubleIndentParams = formattingPreferences(DoubleIndentClassDeclaration) &&
36 | !templateInheritanceSectionOpt.exists { section ⇒ containsNewline(section) || hiddenPredecessors(section.firstToken).containsNewline } &&
37 | templateBodyOption.exists(containsNewline(_))
38 | formatResult ++= formatParamClauses(paramClauses, doubleIndentParams)
39 | }
40 | for (TemplateInheritanceSection(extendsOrSubtype, earlyDefsOpt, templateParentsOpt) ← templateInheritanceSectionOpt) {
41 | val doubleIndentTemplateInheritance = formattingPreferences(DoubleIndentClassDeclaration) &&
42 | (templateBodyOption.exists(containsNewline(_)) || paramClausesOpt.exists(containsNewline(_)))
43 | val inheritanceIndent = if (doubleIndentTemplateInheritance) 2 else 1
44 | var currentFormatterState = formatterState
45 | if (hiddenPredecessors(extendsOrSubtype).containsNewline) {
46 | currentFormatterState = formatterState.indent(inheritanceIndent)
47 | formatResult = formatResult.before(extendsOrSubtype, currentFormatterState.currentIndentLevelInstruction)
48 | }
49 | for (EarlyDefs(earlyBody: TemplateBody, withOpt) ← earlyDefsOpt)
50 | formatResult ++= format(earlyBody)(currentFormatterState)
51 |
52 | for (templateParents ← templateParentsOpt) {
53 | val TemplateParents((type1: Type, argumentExprss: List[ArgumentExprs]), withTypes: List[(Token, Type, List[ArgumentExprs])]) = templateParents
54 |
55 | formatResult ++= format(type1)(currentFormatterState)
56 | for (argumentExprs ← argumentExprss)
57 | formatResult ++= format(argumentExprs)(currentFormatterState)._1
58 |
59 | for ((withToken, type_, argumentExprss2) ← withTypes) {
60 | if (hiddenPredecessors(withToken).containsNewline) {
61 | currentFormatterState = formatterState.indent(inheritanceIndent)
62 | formatResult = formatResult.before(withToken, currentFormatterState.currentIndentLevelInstruction)
63 | }
64 | formatResult ++= format(type_)(currentFormatterState)
65 | for (argumentExprs2 ← argumentExprss2)
66 | formatResult ++= format(argumentExprs2)(currentFormatterState)._1
67 | }
68 | }
69 | }
70 |
71 | for (templateBody ← templateBodyOption)
72 | formatResult ++= format(templateBody)
73 |
74 | formatResult
75 | }
76 |
77 | // TODO: Copy and pasted below
78 | private def format(templateBody: TemplateBody)(implicit formatterState: FormatterState): FormatResult = {
79 | val TemplateBody(newlineOpt, lbrace, statSeq, rbrace) = templateBody
80 | var formatResult: FormatResult = NoFormatResult
81 | newlineOpt match {
82 | case Some(newline) ⇒
83 | formatResult = formatResult.formatNewline(newline, CompactEnsuringGap)
84 | case None ⇒
85 | }
86 |
87 | val dummyBlock = BlockExpr(lbrace, Right(statSeq), rbrace)
88 | formatResult ++= format(dummyBlock, indent = true)
89 | formatResult
90 | }
91 |
92 | def format(template: Template)(implicit formatterState: FormatterState): FormatResult = {
93 | val Template(earlyDefsOpt: Option[EarlyDefs], templateParentsOpt: Option[TemplateParents], templateBodyOpt: Option[TemplateBody]) = template
94 | var formatResult: FormatResult = NoFormatResult
95 |
96 | for (EarlyDefs(earlyBody: TemplateBody, withOpt) ← earlyDefsOpt)
97 | formatResult ++= format(earlyBody)
98 |
99 | for (templateParents ← templateParentsOpt)
100 | formatResult ++= format(templateParents)
101 |
102 | // TODO: Copy and paste from above
103 | for (templateBody @ TemplateBody(newlineOpt, lbrace, statSeq, rbrace) ← templateBodyOpt) {
104 | newlineOpt match {
105 | case Some(newline) ⇒
106 | formatResult = formatResult.formatNewline(newline, CompactEnsuringGap)
107 | case None ⇒
108 | formatResult = formatResult.before(lbrace, CompactEnsuringGap)
109 | }
110 |
111 | val dummyBlock = BlockExpr(lbrace, Right(statSeq), rbrace)
112 | formatResult ++= format(dummyBlock, indent = true)
113 | }
114 |
115 | formatResult
116 | }
117 |
118 | private def format(templateParents: TemplateParents)(implicit formatterState: FormatterState): FormatResult = {
119 | var formatResult: FormatResult = NoFormatResult
120 | val TemplateParents((type1: Type, argumentExprss: List[ArgumentExprs]), withTypes: List[(Token, Type, List[ArgumentExprs])]) = templateParents
121 | formatResult ++= format(type1)
122 | for (argumentExprs ← argumentExprss)
123 | formatResult ++= format(argumentExprs)._1
124 |
125 | // TODO: Unify with TmplDef code
126 |
127 | val currentFormatterState = formatterState
128 | for ((withToken, type_, argumentExprss2) ← withTypes) {
129 | formatResult ++= format(type_)(currentFormatterState)
130 | for (argumentExprs2 ← argumentExprss2)
131 | formatResult ++= format(argumentExprs2)(currentFormatterState)._1
132 | }
133 |
134 | formatResult
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/project/Build.scala:
--------------------------------------------------------------------------------
1 | import sbt._
2 | import sbt.Keys._
3 | import com.typesafe.sbt.SbtScalariform
4 | import com.typesafe.sbt.SbtScalariform.ScalariformKeys
5 | import scalariform.formatter.preferences._
6 | import xerial.sbt.Sonatype._
7 | import xerial.sbt.Sonatype.SonatypeKeys._
8 | import sbtassembly.AssemblyPlugin.autoImport._
9 |
10 | object ScalariformBuild extends Build {
11 |
12 | // This is to make sure nobody tries to compile with 1.6 as the target JDK.
13 | // Not clear if this will actually work on 1.8, needs to be tested when that is out.
14 | val validateJavaVersion = taskKey[Unit]("Check if we are running using required Java version")
15 | val mismatchedSpecificationMessage =
16 | """|Java 1.7 is required for building the `misc` subproject of Scalariform.
17 | |
18 | |This is due to a dependency on the javax.swing library, which
19 | |had an API change from 1.6 to 1.7.
20 | |
21 | |Using 1.7 to build requires setting SBT to use JDK 1.7 or higher -- if SBT is
22 | |booting on JDK 1.6, you will get a javax.swing related compilation error.""".stripMargin
23 |
24 | lazy val commonSettings = Defaults.defaultSettings ++ SbtScalariform.defaultScalariformSettings ++ sonatypeSettings ++ Seq(
25 | organization := "org.scalariform",
26 | profileName := "org.scalariform",
27 | version := "0.1.8",
28 | scalaVersion := "2.10.6",
29 | crossScalaVersions := Seq(
30 | "2.11.7",
31 | "2.10.6",
32 | "2.9.3", "2.9.2" //"2.9.1-1", "2.9.1", "2.9.0-1", "2.9.0"
33 | ),
34 | exportJars := true, // Needed for cli oneJar
35 | retrieveManaged := true,
36 | scalacOptions += "-deprecation"
37 | )
38 |
39 | lazy val subprojectSettings = commonSettings ++ Seq(
40 | ScalariformKeys.preferences <<= baseDirectory.apply(getScalariformPreferences))
41 |
42 | def getScalariformPreferences(dir: File) =
43 | PreferencesImporterExporter.loadPreferences((dir / ".." / "formatterPreferences.properties").getPath)
44 |
45 | lazy val root: Project = Project("root", file("."), settings = commonSettings ++ Seq(
46 | publish := (),
47 | publishLocal := ())
48 | ) aggregate (scalariform, cli, misc)
49 |
50 |
51 | implicit class Regex(sc: StringContext) {
52 | def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
53 | }
54 |
55 | def getScalaTestDependency(scalaVersion: String) = scalaVersion match {
56 | case r"2.11.\d+[-\w]*" | r"2.10.\d+[-\w]*" => "org.scalatest" %% "scalatest" % "2.2.4" % "test"
57 | case "2.9.3" => "org.scalatest" %% "scalatest" % "1.9.1" % "test"
58 | case _ => "org.scalatest" %% "scalatest" % "1.7.2" % "test"
59 | }
60 |
61 | def get2_11Dependencies(scalaVersion: String): List[ModuleID] = scalaVersion match {
62 | case r"2.11.\d+[-\w]*" => List(
63 | "org.scala-lang.modules" %% "scala-xml" % "1.0.1",
64 | "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.1"
65 | )
66 | case _ => Nil
67 | }
68 |
69 | def publishSettings(projectName: String) = Seq(
70 | pomExtra := pomExtraXml,
71 | publishMavenStyle := true,
72 | publishArtifact in Test := false,
73 | publishArtifact in (Compile, packageDoc) := true,
74 | publishArtifact in (Compile, packageSrc) := true,
75 | pomIncludeRepository := { _ ⇒ false },
76 | sbtbuildinfo.Plugin.buildInfoKeys := Seq[sbtbuildinfo.Plugin.BuildInfoKey](version),
77 | sourceGenerators in Compile <+= sbtbuildinfo.Plugin.buildInfo,
78 | sbtbuildinfo.Plugin.buildInfoPackage := projectName
79 | )
80 |
81 | lazy val scalariform: Project = Project("scalariform", file("scalariform"), settings =
82 | subprojectSettings ++ sbtbuildinfo.Plugin.buildInfoSettings ++ publishSettings("scalariform") ++
83 | Seq(
84 | libraryDependencies <<= (scalaVersion, libraryDependencies) { (sv, deps) ⇒
85 | deps ++ get2_11Dependencies(sv) :+ getScalaTestDependency(sv)
86 | },
87 | testOptions in Test += Tests.Argument("-oI"),
88 | publishTo <<= isSnapshot(getPublishToRepo)))
89 |
90 | def getPublishToRepo(isSnapshot: Boolean) =
91 | if (isSnapshot)
92 | Some("snapshots" at "https://oss.sonatype.org/content/repositories/snapshots")
93 | else
94 | Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2")
95 |
96 | lazy val cli = Project("cli", file("cli"), settings = subprojectSettings ++ publishSettings("cli") ++
97 | sbtbuildinfo.Plugin.buildInfoSettings ++
98 | Seq(
99 | libraryDependencies += "commons-io" % "commons-io" % "1.4",
100 | mainClass in (Compile, packageBin) := Some("scalariform.commandline.Main"),
101 | mainClass in assembly := Some("scalariform.commandline.Main"),
102 | publishTo <<= isSnapshot(getPublishToRepo),
103 | artifact in (Compile, assembly) := {
104 | val art = (artifact in (Compile, assembly)).value
105 | art.copy(`classifier` = Some("assembly"))
106 | }
107 | ) ++ addArtifact(artifact in (Compile, assembly), assembly)
108 | ) dependsOn (scalariform)
109 |
110 | lazy val misc: Project = Project("misc", file("misc"), settings = subprojectSettings ++
111 | Seq(
112 | libraryDependencies ++= Seq(
113 | "commons-io" % "commons-io" % "1.4",
114 | "com.miglayout" % "miglayout" % "3.7.4"),
115 | publish := (),
116 | publishLocal := (),
117 | validateJavaVersion := {
118 | val specJavaVersion = sys.props("java.specification.version")
119 | val compatibleJavaVersion = specJavaVersion == "1.7" || specJavaVersion == "1.8"
120 | if (!compatibleJavaVersion)
121 | sys.error(mismatchedSpecificationMessage)
122 | },
123 | // this means we'll validate required Java version only _right before_ running the compile
124 | // command in misc subproject. In particular, build won't fail if user is not interested
125 | // in building `misc` subproject.
126 | compile in Compile := ((compile in Compile) dependsOn validateJavaVersion).value,
127 | mainClass in (Compile, run) := Some("scalariform.gui.Main"))) dependsOn (scalariform, cli)
128 |
129 | def pomExtraXml =
130 | 2010
131 | http://github.com/mdr/scalariform
132 |
133 |
134 | MIT License
135 | http://www.opensource.org/licenses/mit-license.php
136 | repo
137 |
138 |
139 |
140 | git@github.com:daniel-trinh/scalariform.git
141 | scm:git:git@github.com:daniel-trinh/scalariform
142 |
143 |
144 |
145 | mdr
146 | Matt Russell
147 | https://github.com/mdr/
148 |
149 |
150 | daniel-trinh
151 | Daniel Trinh
152 | https://github.com/daniel-trinh/
153 |
154 |
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Scalariform documentation build configuration file, created by
4 | # sphinx-quickstart on Sat Apr 10 15:15:49 2010.
5 | #
6 | # This file is execfile()d with the current directory set to its containing dir.
7 | #
8 | # Note that not all possible configuration values are present in this
9 | # autogenerated file.
10 | #
11 | # All configuration values have a default; values that are commented out
12 | # serve to show the default.
13 |
14 | import sys, os
15 |
16 | # If extensions (or modules to document with autodoc) are in another directory,
17 | # add these directories to sys.path here. If the directory is relative to the
18 | # documentation root, use os.path.abspath to make it absolute, like shown here.
19 | #sys.path.append(os.path.abspath('.'))
20 |
21 | # -- General configuration -----------------------------------------------------
22 |
23 | # Add any Sphinx extension module names here, as strings. They can be extensions
24 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
25 | extensions = ['github.tools.sphinx']
26 |
27 | # Add any paths that contain templates here, relative to this directory.
28 | templates_path = ['_templates']
29 |
30 | # The suffix of source filenames.
31 | source_suffix = '.rst'
32 |
33 | # The encoding of source files.
34 | #source_encoding = 'utf-8'
35 |
36 | # The master toctree document.
37 | master_doc = 'README'
38 |
39 | # General information about the project.
40 | project = u'Scalariform'
41 | copyright = u'2010, Matt Russell'
42 |
43 | # The version info for the project you're documenting, acts as replacement for
44 | # |version| and |release|, also used in various other places throughout the
45 | # built documents.
46 | #
47 | # The short X.Y version.
48 | version = '0.1.5-SNAPSHOT'
49 | # The full version, including alpha/beta/rc tags.
50 | release = '0.1.5-SNAPSHOT'
51 |
52 | # The language for content autogenerated by Sphinx. Refer to documentation
53 | # for a list of supported languages.
54 | #language = None
55 |
56 | # There are two options for replacing |today|: either, you set today to some
57 | # non-false value, then it is used:
58 | #today = ''
59 | # Else, today_fmt is used as the format for a strftime call.
60 | #today_fmt = '%B %d, %Y'
61 |
62 | # List of documents that shouldn't be included in the build.
63 | #unused_docs = []
64 |
65 | # List of directories, relative to source directory, that shouldn't be searched
66 | # for source files.
67 | exclude_trees = []
68 |
69 | # The reST default role (used for this markup: `text`) to use for all documents.
70 | #default_role = None
71 |
72 | # If true, '()' will be appended to :func: etc. cross-reference text.
73 | #add_function_parentheses = True
74 |
75 | # If true, the current module name will be prepended to all description
76 | # unit titles (such as .. function::).
77 | #add_module_names = True
78 |
79 | # If true, sectionauthor and moduleauthor directives will be shown in the
80 | # output. They are ignored by default.
81 | #show_authors = False
82 |
83 | highlight_language = 'scala'
84 |
85 | # The name of the Pygments (syntax highlighting) style to use.
86 | pygments_style = 'sphinx'
87 |
88 | # A list of ignored prefixes for module index sorting.
89 | #modindex_common_prefix = []
90 |
91 |
92 | # -- Options for HTML output ---------------------------------------------------
93 |
94 | # The theme to use for HTML and HTML Help pages. Major themes that come with
95 | # Sphinx are currently 'default' and 'sphinxdoc'.
96 | html_theme = 'default'
97 |
98 | # Theme options are theme-specific and customize the look and feel of a theme
99 | # further. For a list of options available for each theme, see the
100 | # documentation.
101 | html_theme_options = {
102 | "nosidebar": "true"
103 | }
104 |
105 | # Add any paths that contain custom themes here, relative to this directory.
106 | #html_theme_path = []
107 |
108 | # The name for this set of Sphinx documents. If None, it defaults to
109 | # " v documentation".
110 | #html_title = None
111 |
112 | # A shorter title for the navigation bar. Default is the same as html_title.
113 | #html_short_title = None
114 |
115 | # The name of an image file (relative to this directory) to place at the top
116 | # of the sidebar.
117 | #html_logo = None
118 |
119 | # The name of an image file (within the static path) to use as favicon of the
120 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
121 | # pixels large.
122 | #html_favicon = None
123 |
124 | # Add any paths that contain custom static files (such as style sheets) here,
125 | # relative to this directory. They are copied after the builtin static files,
126 | # so a file named "default.css" will overwrite the builtin "default.css".
127 | html_static_path = ['_static']
128 |
129 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
130 | # using the given strftime format.
131 | #html_last_updated_fmt = '%b %d, %Y'
132 |
133 | # If true, SmartyPants will be used to convert quotes and dashes to
134 | # typographically correct entities.
135 | #html_use_smartypants = True
136 |
137 | # Custom sidebar templates, maps document names to template names.
138 | #html_sidebars = {}
139 |
140 | # Additional templates that should be rendered to pages, maps page names to
141 | # template names.
142 | #html_additional_pages = {}
143 |
144 | # If false, no module index is generated.
145 | #html_use_modindex = True
146 |
147 | # If false, no index is generated.
148 | #html_use_index = True
149 |
150 | # If true, the index is split into individual pages for each letter.
151 | #html_split_index = False
152 |
153 | # If true, links to the reST sources are added to the pages.
154 | #html_show_sourcelink = True
155 |
156 | # If true, an OpenSearch description file will be output, and all pages will
157 | # contain a tag referring to it. The value of this option must be the
158 | # base URL from which the finished HTML is served.
159 | #html_use_opensearch = ''
160 |
161 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
162 | #html_file_suffix = ''
163 |
164 | # Output file base name for HTML help builder.
165 | htmlhelp_basename = 'Scalariformdoc'
166 |
167 |
168 | # -- Options for LaTeX output --------------------------------------------------
169 |
170 | # The paper size ('letter' or 'a4').
171 | #latex_paper_size = 'letter'
172 |
173 | # The font size ('10pt', '11pt' or '12pt').
174 | #latex_font_size = '10pt'
175 |
176 | # Grouping the document tree into LaTeX files. List of tuples
177 | # (source start file, target name, title, author, documentclass [howto/manual]).
178 | latex_documents = [
179 | ('README', 'Scalariform.tex', u'Scalariform Documentation',
180 | u'Matt Russell', 'manual'),
181 | ]
182 |
183 | # The name of an image file (relative to this directory) to place at the top of
184 | # the title page.
185 | #latex_logo = None
186 |
187 | # For "manual" documents, if this is true, then toplevel headings are parts,
188 | # not chapters.
189 | #latex_use_parts = False
190 |
191 | # Additional stuff for the LaTeX preamble.
192 | #latex_preamble = ''
193 |
194 | # Documents to append as an appendix to all manuals.
195 | #latex_appendices = []
196 |
197 | # If false, no module index is generated.
198 | #latex_use_modindex = True
199 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/CaseClausesFormatterTest.scala:
--------------------------------------------------------------------------------
1 | package scalariform.formatter
2 |
3 | import scalariform.parser._
4 | import scalariform.formatter._
5 | import scalariform.formatter.preferences._
6 |
7 | // format: OFF
8 | class CaseClausesFormatterTest extends AbstractExpressionFormatterTest {
9 |
10 | override val debug = false
11 |
12 | """{
13 | | case x => x * x
14 | | case y => y * 2
15 | |}""" ==>
16 | """{
17 | | case x => x * x
18 | | case y => y * 2
19 | |}"""
20 |
21 | """{
22 | |case 1 => // comment
23 | |2
24 | |}""" ==>
25 | """{
26 | | case 1 => // comment
27 | | 2
28 | |}"""
29 |
30 | """{
31 | |case x =>
32 | |while (true) {
33 | |1
34 | |}
35 | |}""" ==>
36 | """{
37 | | case x =>
38 | | while (true) {
39 | | 1
40 | | }
41 | |}"""
42 |
43 | """a match {
44 | | case b => c();
45 | |d()
46 | | }""" ==>
47 | """a match {
48 | | case b =>
49 | | c();
50 | | d()
51 | |}"""
52 |
53 | """a match {
54 | |case b => {
55 | |c
56 | |}
57 | |}""" ==>
58 | """a match {
59 | | case b => {
60 | | c
61 | | }
62 | |}"""
63 |
64 | """a match {
65 | |case b => {
66 | |c
67 | |}
68 | |d
69 | |}""" ==>
70 | """a match {
71 | | case b =>
72 | | {
73 | | c
74 | | }
75 | | d
76 | |}"""
77 |
78 | """a match { case a => b; c; d }""" ==>
79 | """a match { case a => b; c; d }"""
80 |
81 | """a match { case a => b; c;
82 | |d }""" ==>
83 | """a match {
84 | | case a =>
85 | | b; c;
86 | | d
87 | |}"""
88 |
89 | "a match { case b => ; c }" ==> "a match { case b => ; c }"
90 |
91 | // See issue #60
92 | """a match {
93 | |case b =>
94 | |val c = d
95 | |case e =>
96 | |}""" ==>
97 | """a match {
98 | | case b =>
99 | | val c = d
100 | | case e =>
101 | |}"""
102 |
103 | """a match {
104 | |/* foo*/
105 | |case x if z=> 1
106 | |/* bar*/
107 | |case yy => 2
108 | |/* baz*/
109 | |case zzz => 3
110 | |}""" ==>
111 | """a match {
112 | | /* foo*/
113 | | case x if z => 1
114 | | /* bar*/
115 | | case yy => 2
116 | | /* baz*/
117 | | case zzz => 3
118 | |}"""
119 |
120 | """a match {
121 | |case x => x
122 | |a =>
123 | |x
124 | |case y => b =>
125 | |b + 1
126 | |}""" ==>
127 | """a match {
128 | | case x =>
129 | | x
130 | | a =>
131 | | x
132 | | case y => b =>
133 | | b + 1
134 | |}"""
135 |
136 | """a match {
137 | |case x => a =>
138 | |x
139 | |case y => b =>
140 | |b + 1
141 | |}""" ==>
142 | """a match {
143 | | case x => a =>
144 | | x
145 | | case y => b =>
146 | | b + 1
147 | |}"""
148 |
149 | {
150 | implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, false)
151 |
152 | """a match {
153 | | case b(c @ ~()) =>
154 | | case b(c@ ~()) =>
155 | |}""" ==>
156 | """a match {
157 | | case b(c@ ~()) =>
158 | | case b(c@ ~()) =>
159 | |}"""
160 | }
161 |
162 | {
163 |
164 | implicit val formattingPreferences = FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true)
165 |
166 | """a match {
167 | |case x => 1
168 | |case yy => 2
169 | |case zzz => 3
170 | |}""" ==>
171 | """a match {
172 | | case x => 1
173 | | case yy => 2
174 | | case zzz => 3
175 | |}"""
176 |
177 | """a match {
178 | |/* foo*/
179 | |case x if z=> 1
180 | |/* bar*/
181 | |case yy => 2
182 | |/* baz*/
183 | |case zzz => 3
184 | |}""" ==>
185 | """a match {
186 | | /* foo*/
187 | | case x if z => 1
188 | | /* bar*/
189 | | case yy => 2
190 | | /* baz*/
191 | | case zzz => 3
192 | |}"""
193 |
194 | """a match {
195 | |case b => 1; case c => 2
196 | |}""" ==>
197 | """a match {
198 | | case b => 1; case c => 2
199 | |}"""
200 |
201 | """a match { case b => 1;
202 | |case ccc => 2}""" ==>
203 | """a match {
204 | | case b => 1;
205 | | case ccc => 2
206 | |}"""
207 |
208 | """a match {
209 | | case b /* comment */ => 1
210 | | case c => 2
211 | |}""" ==>
212 | """a match {
213 | | case b /* comment */ => 1
214 | | case c => 2
215 | |}"""
216 |
217 | """a match {
218 | | case b
219 | |=> 1
220 | | case ccc => 2
221 | |}""" ==>
222 | """a match {
223 | | case b => 1
224 | | case ccc => 2
225 | |}"""
226 |
227 | """a match {
228 | | case b =>
229 | | 1
230 | | case cc => 2
231 | |}""" ==>
232 | """a match {
233 | | case b =>
234 | | 1
235 | | case cc => 2
236 | |}"""
237 |
238 | "{ case a=> b }" ==> "{ case a => b }"}
239 |
240 | """t match {
241 | | case Cell [ a ] (x: Int) => c.x = 5
242 | |}""" ==>
243 | """t match {
244 | | case Cell[a](x: Int) => c.x = 5
245 | |}"""
246 |
247 |
248 | {
249 | implicit val formattingPreferences =
250 | FormattingPreferences.setPreference(AlignSingleLineCaseStatements, true).setPreference(RewriteArrowSymbols, true)
251 |
252 | """a match {
253 | |case b => 42
254 | |case ccc => 24
255 | |}""" ==>
256 | """a match {
257 | | case b ⇒ 42
258 | | case ccc ⇒ 24
259 | |}"""
260 | }
261 |
262 | {
263 |
264 | implicit val formattingPreferences =
265 | FormattingPreferences
266 | .setPreference(AlignSingleLineCaseStatements, true)
267 | .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 5)
268 |
269 | """x match {
270 | | case 123456789 => a
271 | | case _ => b
272 | |}""" ==>
273 | """x match {
274 | | case 123456789 => a
275 | | case _ => b
276 | |}"""
277 |
278 | }
279 |
280 | """a match {
281 | | case true => {
282 | | case true => false
283 | | case false => true
284 | | }
285 | | case false => b match {
286 | | case true => true
287 | | case false => false
288 | | }
289 | |}""" ==>
290 | """a match {
291 | | case true => {
292 | | case true => false
293 | | case false => true
294 | | }
295 | | case false => b match {
296 | | case true => true
297 | | case false => false
298 | | }
299 | |}"""
300 |
301 |
302 | "{ case a ::(b) ⇒ }" ==>
303 | "{ case a :: (b) ⇒ }"
304 |
305 | """{
306 | | case a ⇒
307 | | {
308 | | a
309 | | }
310 | |}""" ==>
311 | """{
312 | | case a ⇒
313 | | {
314 | | a
315 | | }
316 | |}"""
317 |
318 |
319 | {
320 | implicit val formattingPreferences = FormattingPreferences.setPreference(SpacesWithinPatternBinders, false)
321 |
322 | """(a: @switch) match {
323 | |case elem@Multi(values@_*) =>
324 | |}""" ==>
325 | """(a: @switch) match {
326 | | case elem@Multi(values@_*) =>
327 | |}"""
328 | }
329 |
330 | """(a: @switch) match {
331 | |case elem@Multi(values@_*) =>
332 | |}""" ==>
333 | """(a: @switch) match {
334 | | case elem @ Multi(values @ _*) =>
335 | |}"""
336 |
337 | }
338 |
--------------------------------------------------------------------------------
/scalariform/src/test/scala/com/danieltrinh/scalariform/formatter/DefOrDclFormatterTest.scala:
--------------------------------------------------------------------------------
1 |
2 | package scalariform.formatter
3 |
4 | import scalariform.parser._
5 | import scalariform.formatter._
6 | import scalariform.formatter.preferences._
7 |
8 | // format: OFF
9 | class DefOrDclFormatterTest extends AbstractFormatterTest {
10 |
11 | override val debug = false
12 |
13 | "def foo" ==> "def foo"
14 |
15 | "def foo()" ==> "def foo()"
16 |
17 | "def foo=42" ==> "def foo = 42"
18 |
19 | "def foo{doStuff()}" ==> "def foo { doStuff() }"
20 |
21 | "def foo={doStuff()}" ==> "def foo = { doStuff() }"
22 |
23 | "def foo ()" ==> "def foo()"
24 |
25 | "def foo(n:Int)" ==> "def foo(n: Int)"
26 |
27 | "def foo( n:Int,m:String )" ==> "def foo(n: Int, m: String)"
28 |
29 | "def foo:Int" ==> "def foo: Int"
30 |
31 | "def modN ( n :Int ) (x: Int) = ((x % n) == 0)" ==> "def modN(n: Int)(x: Int) = ((x % n) == 0)"
32 |
33 | "def foo(a: Int=123+2, b: Int=456+7)" ==> "def foo(a: Int = 123 + 2, b: Int = 456 + 7)"
34 |
35 | "def foo[X<%T1,Y<:T2,Z>:T3]()" ==> "def foo[X <% T1, Y <: T2, Z >: T3]()"
36 |
37 | "def foo(x: =>Int, y: Int *)" ==> "def foo(x: => Int, y: Int*)"
38 |
39 | "def a[+[+_]]" ==> "def a[+[+_]]"
40 | "def a[+]" ==> "def a[+]"
41 | "def a[-]" ==> "def a[-]"
42 |
43 | "def foo(x_ : Int)" ==> "def foo(x_ : Int)"
44 |
45 | "private def x" ==> "private def x"
46 |
47 | "private[pack]def x" ==> "private[pack] def x"
48 | "private[pack]val x" ==> "private[pack] val x"
49 | "private[pack]var x" ==> "private[pack] var x"
50 |
51 | """def a
52 | |: String""" ==>
53 | """def a: String"""
54 |
55 | """def foo =
56 | | if (true)
57 | | 1
58 | | else
59 | | 2""" ==>
60 | """def foo =
61 | | if (true)
62 | | 1
63 | | else
64 | | 2"""
65 |
66 | """val x =
67 | | if (true)
68 | | 42
69 | | else
70 | | 24""" ==>
71 | """val x =
72 | | if (true)
73 | | 42
74 | | else
75 | | 24"""
76 |
77 | """def a()
78 | |{
79 | |b
80 | | }""" ==>
81 | """def a() {
82 | | b
83 | |}"""
84 |
85 | """type
86 | |B""" ==>
87 | """type B"""
88 |
89 | """type
90 | |
91 | |B""" ==>
92 | """type B"""
93 |
94 | "class A { val b = _.c }" ==> "class A { val b = _.c }"
95 |
96 | """def a() { return }""" ==> """def a() { return }"""
97 |
98 | """def a[B,
99 | |C]
100 | |()""" ==>
101 | """def a[B, C]()"""
102 |
103 | """private [a]
104 | |sealed trait B""" ==>
105 | """private[a] sealed trait B"""
106 |
107 | {
108 |
109 | implicit val formattingPreferences =
110 | FormattingPreferences
111 | .setPreference(IndentLocalDefs, true)
112 |
113 | """class A {
114 | | def b() = {
115 | | def c() = 42
116 | | println("d")
117 | | def e() =
118 | | 42
119 | |println("f")
120 | | def g() {
121 | |println("h")
122 | |}
123 | | c() * e()
124 | | }
125 | |}""" ==>
126 | """class A {
127 | | def b() = {
128 | | def c() = 42
129 | | println("d")
130 | | def e() =
131 | | 42
132 | | println("f")
133 | | def g() {
134 | | println("h")
135 | | }
136 | | c() * e()
137 | | }
138 | |}"""
139 |
140 | """val x = { i =>
141 | | def a
142 | | def b
143 | |}""" ==>
144 | """val x = { i =>
145 | | def a
146 | | def b
147 | |}"""
148 |
149 | // See issue #24
150 | """val inc: Int => Int = { i =>
151 | | def plus1 = i + 1
152 | | plus1
153 | |}""" ==>
154 | """val inc: Int => Int = { i =>
155 | | def plus1 = i + 1
156 | | plus1
157 | |}"""
158 |
159 | }
160 |
161 | {
162 | implicit val formattingPreferences = FormattingPreferences.setPreference(DanglingCloseParenthesis, Preserve)
163 |
164 | """def foo(
165 | | alpha: Int,
166 | | beta: String = "default",
167 | | gamma: Boolean = true,
168 | | delta: Boolean = false): Double = {
169 | |
170 | | bar
171 | |}""" ==>
172 | """def foo(
173 | | alpha: Int,
174 | | beta: String = "default",
175 | | gamma: Boolean = true,
176 | | delta: Boolean = false): Double = {
177 | |
178 | | bar
179 | |}"""
180 |
181 | """def foo(
182 | | alpha: Int,
183 | | beta: String = "default",
184 | | gamma: Boolean = true,
185 | | delta: Boolean = false
186 | |): Double = {
187 | |
188 | | bar
189 | |}""" ==>
190 | """def foo(
191 | | alpha: Int,
192 | | beta: String = "default",
193 | | gamma: Boolean = true,
194 | | delta: Boolean = false
195 | |): Double = {
196 | |
197 | | bar
198 | |}"""
199 | }
200 |
201 | {
202 | implicit val formattingPreferences = FormattingPreferences.setPreference(DanglingCloseParenthesis, Prevent)
203 |
204 | """private def foo(
205 | | alpha: Int,
206 | | beta: String = "default",
207 | | gamma: Boolean = true,
208 | | delta: Boolean = false
209 | |): Double = {
210 | |
211 | | bar
212 | |}""" ==>
213 | """private def foo(
214 | | alpha: Int,
215 | | beta: String = "default",
216 | | gamma: Boolean = true,
217 | | delta: Boolean = false): Double = {
218 | |
219 | | bar
220 | |}"""
221 |
222 | """case class FqnSymbol(
223 | | id: Option[Int],
224 | | file: String, // the underlying file
225 | | path: String, // the VFS handle (e.g. classes in jars)
226 | | fqn: String,
227 | | descriptor: Option[String], // for methods
228 | | internal: Option[String], // for fields
229 | | source: Option[String], // VFS
230 | | line: Option[Int],
231 | | offset: Option[Int] = None // future features:
232 | |)""" ==>
233 | """case class FqnSymbol(
234 | | id: Option[Int],
235 | | file: String, // the underlying file
236 | | path: String, // the VFS handle (e.g. classes in jars)
237 | | fqn: String,
238 | | descriptor: Option[String], // for methods
239 | | internal: Option[String], // for fields
240 | | source: Option[String], // VFS
241 | | line: Option[Int],
242 | | offset: Option[Int] = None // future features:
243 | |)"""
244 | }
245 |
246 | {
247 | implicit val formattingPreferences = FormattingPreferences.setPreference(DanglingCloseParenthesis, Force)
248 |
249 | """private def foo(
250 | | alpha: Int,
251 | | beta: String = "default",
252 | | gamma: Boolean = true,
253 | | delta: Boolean = false): Double = {
254 | |
255 | | bar
256 | |}""" ==>
257 | """private def foo(
258 | | alpha: Int,
259 | | beta: String = "default",
260 | | gamma: Boolean = true,
261 | | delta: Boolean = false
262 | |): Double = {
263 | |
264 | | bar
265 | |}"""
266 | }
267 |
268 | """def foo(n, m)""" ==>
269 | """def foo(n, m)"""
270 |
271 | """def test(test: ^^ *)""" ==>
272 | """def test(test: ^^ *)"""
273 |
274 |
275 | def parse(parser: ScalaParser) = parser.nonLocalDefOrDcl()
276 |
277 | type Result = FullDefOrDcl
278 |
279 | def format(formatter: ScalaFormatter, result: Result) = formatter.format(result)(FormatterState(indentLevel = 0))
280 |
281 |
282 | }
283 |
284 |
285 |
--------------------------------------------------------------------------------