├── .gitignore ├── README.md ├── project ├── Build.scala ├── Dependencies.scala ├── build.properties └── plugins.sbt ├── scalariform.sbt └── src └── main ├── resources └── LICENSE-2.0.txt └── scala └── com └── typesafe └── sbt ├── PreferencesProtocol.scala ├── SbtScalariform.scala └── Scalariform.scala /.gitignore: -------------------------------------------------------------------------------- 1 | # SBT 2 | boot/ 3 | lib_managed/ 4 | target/ 5 | .history 6 | 7 | # Eclipse 8 | .cache 9 | .classpath 10 | .project 11 | .scala_dependencies 12 | .settings 13 | .target/ 14 | eclipse.sbt 15 | 16 | # IntelliJ 17 | .idea/ 18 | *.iml 19 | *.ipr 20 | *.iws 21 | out/ 22 | 23 | # TextMate 24 | *.tmproj 25 | 26 | # Mac 27 | .DS_Store 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sbt-scalariform 2 | =============== 3 | 4 | Welcome to sbt-scalariform, an sbt plugin adding support for source code formatting using Scalariform. 5 | 6 | Installing sbt-scalariform 7 | -------------------------- 8 | 9 | As of sbt-scalariform 1.5.0, this plugin is now an auto plugin. Make sure to read the _Upgrading from 1.4.0_ 10 | and _Advanced Configuration_ sections carefully when upgrading. 11 | 12 | sbt-scalariform is a plugin for sbt 0.13.5+. Please make sure that you are using an appropriate sbt release. 13 | In order to download and install sbt, please refer to [sbt Getting Started Guide / Setup](http://www.scala-sbt.org/release/docs/Getting-Started/Setup.html). 14 | 15 | As sbt-scalariform is a plugin for sbt, it is installed like any other sbt plugin, that is by mere configuration. 16 | For details about using sbt plugins, please refer to [sbt Getting Started Guide / Using Plugins](http://www.scala-sbt.org/release/docs/Getting-Started/Using-Plugins.html). 17 | 18 | If you've got a simple one project build, you can probably skip the details and just add sbt-scalariform to your local plugin definition. 19 | If you've got a more complicated build with several projects and are __upgrading from 1.4.0 or older__, see the next section below. 20 | Local plugins are defined in a `plugins.sbt` file in the `project/` folder of your project. 21 | 22 | To add sbt-scalariform to your build using sbt 0.13.5, just add the below setting, paying attention to blank lines: 23 | 24 | ``` 25 | ... // Other settings 26 | resolvers += "Sonatype OSS Releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2" 27 | 28 | addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0") 29 | ``` 30 | 31 | This will add the task `scalariformFormat` in the scopes `compile` and `test` and additionally run this task automatically when compiling; 32 | for more control see the section *Advanced configuration* below 33 | 34 | Now you are ready to go. Either start sbt or, if it was already started, reload the current session by executing the 35 | `reload` command. If everything worked, you should have the new command `scalariformFormat` available as well automatic 36 | formatting on `compile` and `test:compile` activated. 37 | 38 | 39 | After adding the sbt-scalariform plugin like this, if you want different formatting settings from the default behavior, read 40 | the advanced configuration section. 41 | 42 | If you are using an sbt 0.13.x version older than 0.13.5, you'll want to upgrade, or stick to using sbt-scalariform 1.4.0. 43 | 44 | sbt 0.12.x and below is not supported for this fork, see `https://github.com/sbt/sbt-scalariform` for 45 | older versions. 46 | 47 | Upgrading from 1.4.0: Disabling Auto-plugin Auto Formatting behavior 48 | --------------------------------------------- 49 | Sbt-Scalariform versions 1.5.0 and greater have switched to using AutoPlugins for automatic settings in build files. 50 | By default, when including this project, all of your projects defined will now have sbt-scalariform settings mixed into 51 | each project. This means on compilation, your code will be formatted. If you'd like to keep sbt-scalariform 52 | available for manual formatting with a sbt `scalariformFormat` command, you can mix in `defaultScalariformSettings` to your project -- 53 | see the advanced configuration section for details on how to do this. 54 | 55 | Autoplugins only work with sbt 0.13.5 or greater. 56 | 57 | If you'd like to disable this plugin entirely on a per project basis, you can use sbt's built in feature to disable auto plugins: 58 | 59 | ``` 60 | import com.typesafe.sbt.SbtScalariform 61 | 62 | lazy val project = Project( 63 | ... 64 | ).disablePlugins(SbtScalariform) 65 | ``` 66 | 67 | Using sbt-scalariform 68 | --------------------- 69 | 70 | If you added the settings for this plugin like described above, you can either format your sources manually or automatically: 71 | 72 | - Whenever you run the tasks `compile` or `test:compile`, your source files will be automatically formatted by Scalariform 73 | 74 | - If you want to start formatting your source files explicitly, just run the task `scalariformFormat` or `test:scalariformFormat` 75 | 76 | Advanced configuration 77 | ---------------------- 78 | sbt-scalariform comes with various configuration options. Changing the formatting preferences and deactivating the automatic formatting on compile are probably the most important ones and described in detail. 79 | 80 | You can provide your own formatting preferences for Scalariform via the setting key `ScalariformKeys.preferences` which expects an instance of `IFormattingPreferences`. Make sure you import all necessary members from the package `scalariform.formatter.preferences`. Let's look at an example: 81 | 82 | .sbt build example 83 | ``` 84 | import scalariform.formatter.preferences._ 85 | import com.typesafe.sbt.SbtScalariform 86 | 87 | SbtScalariform.scalariformSettings 88 | 89 | ScalariformKeys.preferences := ScalariformKeys.preferences.value 90 | .setPreference(AlignSingleLineCaseStatements, true) 91 | .setPreference(DoubleIndentClassDeclaration, true) 92 | .setPreference(PreserveDanglingCloseParenthesis, true) 93 | ``` 94 | 95 | .scala build example 96 | ``` 97 | import scalariform.formatter.preferences._ 98 | import com.typesafe.sbt.SbtScalariform 99 | 100 | lazy val project = Project( 101 | ... 102 | settings = SbtScalariform.scalariformSettings ++ Seq( 103 | ScalariformKeys.preferences := ScalariformKeys.preferences.value 104 | .setPreference(AlignSingleLineCaseStatements, true) 105 | .setPreference(DoubleIndentClassDeclaration, true) 106 | .setPreference(PreserveDanglingCloseParenthesis, true) 107 | ) 108 | ) 109 | ``` 110 | 111 | If you don't want sbt to automatically format your source files when the tasks `compile` or `test:compile`, just add 112 | `defaultScalariformSettings` instead of `scalariformSettings` to your build definition. 113 | 114 | .scala build example: 115 | ``` 116 | import com.typesafe.sbt.SbtScalariform 117 | 118 | lazy val project = Project( 119 | "project_name", 120 | file("."), 121 | settings = SbtScalariform.defaultScalariformSettings ++ 122 | ... 123 | ) 124 | ``` 125 | 126 | .sbt build example: 127 | 128 | ``` 129 | import com.typesafe.sbt.SbtScalariform 130 | 131 | SbtScalariform.defaultScalariformSettings 132 | ``` 133 | 134 | 135 | If you want to additionally enable Scalariform for your integration tests, use `scalariformSettingsWithIt` or `defaultScalariformSettingsWithIt` instead of the above. 136 | 137 | Other useful configuration options are provided by common sbt setting keys: 138 | 139 | - `includeFilter in format`: Defaults to **.scala* 140 | - `excludeFilter in format`: Using the default of sbt 141 | 142 | Contact 143 | ------------ 144 | 145 | Please contact `@daniel-trinh` on http://github.com for help 146 | 147 | License 148 | ------- 149 | 150 | This code is open source software licensed under the Apache 2.0 License. 151 | -------------------------------------------------------------------------------- /project/Build.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import sbt.Keys._ 3 | import sbt.{ThisBuild, Project} 4 | import scala.Some 5 | import com.typesafe.sbt.SbtScalariform 6 | import com.typesafe.sbt.SbtScalariform.ScalariformKeys 7 | import scalariform.formatter.preferences._ 8 | 9 | object SbtScalariformBuild extends Build { 10 | 11 | val formattingPreferences = { 12 | import scalariform.formatter.preferences._ 13 | FormattingPreferences() 14 | .setPreference(AlignParameters, true) 15 | .setPreference(CompactStringConcatenation, true) 16 | .setPreference(CompactControlReadability, false) 17 | .setPreference(AlignSingleLineCaseStatements, true) 18 | .setPreference(AlignSingleLineCaseStatements.MaxArrowIndent, 40) 19 | .setPreference(SpacesWithinPatternBinders, true) 20 | .setPreference(DoubleIndentClassDeclaration, true) 21 | .setPreference(SpacesAroundMultiImports, true) 22 | } 23 | 24 | def getPublishToRepo(isSnapshot: Boolean) = 25 | if (isSnapshot) 26 | Some("snapshots" at "https://oss.sonatype.org/content/repositories/snapshots") 27 | else 28 | Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") 29 | 30 | val sbtScalariform: Project = Project( 31 | "sbt-scalariform", 32 | file("."), 33 | settings = Seq( 34 | organization := "org.scalariform", 35 | name := "sbt-scalariform", 36 | version in ThisBuild := "1.6.0", 37 | resolvers ++= Resolvers.resolvers, 38 | libraryDependencies ++= Dependencies.sbtScalariform, 39 | scalacOptions ++= List( 40 | "-unchecked", 41 | "-deprecation", 42 | "-Xlint", 43 | "-language:_", 44 | "-target:jvm-1.6", 45 | "-encoding", "UTF-8" 46 | ), 47 | ScalariformKeys.preferences := formattingPreferences, 48 | sbtPlugin := true, 49 | publishTo <<= isSnapshot(getPublishToRepo), 50 | publishMavenStyle := true, 51 | publishArtifact in Test := false, 52 | publishArtifact in (Compile, packageSrc) := true, 53 | pomExtra := 54 | http://github.com/daniel-trinh/sbt-scalariform 55 | 56 | 57 | Apache 2.0 58 | http://www.apache.org/licenses/LICENSE-2.0 59 | repo 60 | 61 | 62 | 63 | git@github.com:daniel-trinh/sbt-scalariform.git 64 | scm:git@github.com:daniel-trinh/sbt-scalariform.git 65 | 66 | 67 | 68 | hseeberger 69 | Heiko Seeberger 70 | http://blog.heikoseeberger.name/ 71 | 72 | 73 | daniel-trinh 74 | Daniel Trinh 75 | http://danieltrinh.com 76 | 77 | 78 | ) 79 | ) 80 | } 81 | 82 | object Resolvers { 83 | val sonatypeSnapshots = "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" 84 | val sonatypeReleases = "Sonatype OSS Releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2" 85 | 86 | val resolvers = Seq( 87 | sonatypeSnapshots, 88 | sonatypeReleases 89 | ) 90 | } -------------------------------------------------------------------------------- /project/Dependencies.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | 3 | object Version { 4 | val scalariform = "0.1.8" 5 | } 6 | 7 | object Library { 8 | val scalariform = "org.scalariform" %% "scalariform" % Version.scalariform 9 | } 10 | 11 | object Dependencies { 12 | 13 | import Library._ 14 | 15 | val sbtScalariform = List( 16 | scalariform 17 | ) 18 | } -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.9 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.5.1") 2 | 3 | addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.1") -------------------------------------------------------------------------------- /scalariform.sbt: -------------------------------------------------------------------------------- 1 | import com.typesafe.sbt.SbtScalariform.ScalariformKeys 2 | import scalariform.formatter.preferences._ 3 | 4 | ScalariformKeys.preferences := ScalariformKeys.preferences.value 5 | .setPreference(AlignSingleLineCaseStatements, true) 6 | .setPreference(DoubleIndentClassDeclaration, true) 7 | .setPreference(PreserveDanglingCloseParenthesis, true) 8 | -------------------------------------------------------------------------------- /src/main/resources/LICENSE-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/main/scala/com/typesafe/sbt/PreferencesProtocol.scala: -------------------------------------------------------------------------------- 1 | package com.typesafe.sbt 2 | 3 | import java.io.{ StringReader, StringWriter } 4 | import java.util.Properties 5 | import sbinary.Operations._ 6 | import sbinary.{ Input, Output, Format, DefaultProtocol } 7 | import scalariform.formatter.preferences.{ PreferencesImporterExporter, IFormattingPreferences } 8 | 9 | object PreferencesProtocol extends DefaultProtocol { 10 | 11 | implicit object PrefFormat extends Format[IFormattingPreferences]() { 12 | override def writes(out: Output, value: IFormattingPreferences): Unit = { 13 | val outStream = new StringWriter() 14 | PreferencesImporterExporter.asProperties(value).store(outStream, null) 15 | write[String](out, outStream.toString) 16 | } 17 | 18 | override def reads(in: Input): IFormattingPreferences = { 19 | val properties = new Properties 20 | properties.load(new StringReader(read[String](in))) 21 | PreferencesImporterExporter.getPreferences(properties) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/scala/com/typesafe/sbt/SbtScalariform.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 Typesafe Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.typesafe.sbt 18 | 19 | import sbt._ 20 | import sbt.plugins.JvmPlugin 21 | import sbt.{ IntegrationTest => It } 22 | import sbt.Keys._ 23 | import scala.collection.immutable.Seq 24 | import scalariform.formatter.preferences.IFormattingPreferences 25 | 26 | object SbtScalariform extends AutoPlugin { 27 | 28 | val defaultPreferences = { 29 | import scalariform.formatter.preferences._ 30 | FormattingPreferences() 31 | .setPreference(SpacesAroundMultiImports, true) // this was changed in 0.1.7 scalariform, setting this to preserve default. 32 | .setPreference(DoubleIndentClassDeclaration, true) 33 | } 34 | 35 | object autoImport { 36 | 37 | val scalariformFormat: TaskKey[Seq[File]] = 38 | TaskKey[Seq[File]]( 39 | prefixed("format"), 40 | "Format (Scala) sources using scalariform" 41 | ) 42 | 43 | val scalariformPreferences: SettingKey[IFormattingPreferences] = 44 | SettingKey[IFormattingPreferences]( 45 | prefixed("preferences"), 46 | "Scalariform formatting preferences, e.g. indentation" 47 | ) 48 | private def prefixed(key: String) = s"scalariform-$key" 49 | 50 | def scalariformSettings: Seq[Setting[_]] = 51 | defaultScalariformSettings ++ List( 52 | compileInputs in (Compile, compile) <<= (compileInputs in (Compile, compile)) dependsOn (scalariformFormat in Compile), 53 | compileInputs in (Test, compile) <<= (compileInputs in (Test, compile)) dependsOn (scalariformFormat in Test) 54 | ) 55 | } 56 | 57 | import autoImport._ 58 | 59 | override lazy val projectSettings = scalariformSettings 60 | override val trigger = allRequirements 61 | override val requires = JvmPlugin 62 | 63 | object ScalariformKeys { 64 | 65 | val format = autoImport.scalariformFormat 66 | 67 | val preferences = autoImport.scalariformPreferences 68 | } 69 | 70 | def scalariformSettings: Seq[Setting[_]] = autoImport.scalariformSettings 71 | 72 | def scalariformSettingsWithIt: Seq[Setting[_]] = 73 | defaultScalariformSettingsWithIt ++ List( 74 | compileInputs in (Compile, compile) <<= (compileInputs in (Compile, compile)) dependsOn (scalariformFormat in Compile), 75 | compileInputs in (Test, compile) <<= (compileInputs in (Test, compile)) dependsOn (scalariformFormat in Test), 76 | compileInputs in (It, compile) <<= (compileInputs in (It, compile)) dependsOn (scalariformFormat in It) 77 | ) 78 | 79 | def defaultScalariformSettings: Seq[Setting[_]] = 80 | noConfigScalariformSettings ++ inConfig(Compile)(configScalariformSettings) ++ inConfig(Test)(configScalariformSettings) 81 | 82 | def defaultScalariformSettingsWithIt: Seq[Setting[_]] = 83 | defaultScalariformSettings ++ inConfig(It)(configScalariformSettings) 84 | 85 | def configScalariformSettings: Seq[Setting[_]] = 86 | List( 87 | (sourceDirectories in Global in scalariformFormat) := List(scalaSource.value), 88 | scalariformFormat := Scalariform( 89 | scalariformPreferences.value, 90 | (sourceDirectories in scalariformFormat).value.toList, 91 | (includeFilter in scalariformFormat).value, 92 | (excludeFilter in scalariformFormat).value, 93 | thisProjectRef.value, 94 | configuration.value, 95 | streams.value, 96 | scalaVersion.value 97 | ) 98 | ) 99 | 100 | def noConfigScalariformSettings: Seq[Setting[_]] = 101 | List( 102 | scalariformPreferences in Global := defaultPreferences, 103 | includeFilter in Global in scalariformFormat := "*.scala" 104 | ) 105 | } 106 | -------------------------------------------------------------------------------- /src/main/scala/com/typesafe/sbt/Scalariform.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011-2012 Typesafe Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.typesafe.sbt 18 | 19 | import sbt._ 20 | import sbt.Keys._ 21 | import sbt.{ File, FileFilter, _ } 22 | import scala.collection.immutable.Seq 23 | import scalariform.formatter.ScalaFormatter 24 | import scalariform.formatter.preferences.{ IFormattingPreferences, PreferencesImporterExporter } 25 | import scalariform.parser.ScalaParserException 26 | 27 | private object Scalariform { 28 | 29 | def apply( 30 | preferences: IFormattingPreferences, 31 | sourceDirectories: Seq[File], 32 | includeFilter: FileFilter, 33 | excludeFilter: FileFilter, 34 | ref: ProjectRef, 35 | configuration: Configuration, 36 | streams: TaskStreams, 37 | scalaVersion: String 38 | ): Seq[File] = { 39 | 40 | def log(label: String, logger: Logger)(message: String)(count: String) = 41 | logger.info(message.format(count, label)) 42 | 43 | def performFormat(files: Set[File]) = 44 | for (file <- files if file.exists) { 45 | try { 46 | val contents = IO.read(file) 47 | val formatted = ScalaFormatter.format( 48 | contents, 49 | preferences, 50 | scalaVersion = pureScalaVersion(scalaVersion) 51 | ) 52 | if (formatted != contents) IO.write(file, formatted) 53 | } catch { 54 | case e: ScalaParserException => 55 | streams.log.warn("Scalariform parser error for %s: %s".format(file, e.getMessage)) 56 | } 57 | } 58 | 59 | val files = sourceDirectories.descendantsExcept(includeFilter, excludeFilter).get.toSet 60 | val cache = streams.cacheDirectory / "scalariform" 61 | val logFun = log("%s(%s)".format(Reference.display(ref), configuration), streams.log) _ 62 | if (preferencesChanged(streams.cacheDirectory / "scalariform-preferences")(preferences)) { 63 | IO.delete(cache) 64 | } 65 | handleFiles(files, cache, logFun("Formatting %s %s ..."), performFormat) 66 | handleFiles(files, cache, logFun("Reformatted %s %s."), _ => ()).toList // recalculate cache because we're formatting in-place 67 | } 68 | 69 | def handleFiles( 70 | files: Set[File], 71 | cache: File, 72 | logFun: String => Unit, 73 | updateFun: Set[File] => Unit 74 | ): Set[File] = { 75 | 76 | def handleUpdate(in: ChangeReport[File], out: ChangeReport[File]) = { 77 | val files = in.modified -- in.removed 78 | inc.Analysis.counted("Scala source", "", "s", files.size) foreach logFun 79 | updateFun(files) 80 | files 81 | } 82 | 83 | FileFunction.cached(cache)(FilesInfo.hash, FilesInfo.exists)(handleUpdate)(files) 84 | } 85 | 86 | def pureScalaVersion(scalaVersion: String): String = 87 | scalaVersion split "-" head 88 | 89 | protected def preferencesChanged(cacheDir: File): IFormattingPreferences => Boolean = { 90 | import com.typesafe.sbt.PreferencesProtocol._ 91 | val prefChanged = new Changed[IFormattingPreferences](cacheDir) 92 | prefChanged({ _ => true }, { _ => false }) 93 | } 94 | 95 | protected implicit val prefEquivalence = new Equiv[IFormattingPreferences]() { 96 | override def equiv(x: IFormattingPreferences, y: IFormattingPreferences): Boolean = { 97 | PreferencesImporterExporter.asProperties(x) == PreferencesImporterExporter.asProperties(y) 98 | } 99 | } 100 | 101 | } 102 | --------------------------------------------------------------------------------