Skip to content
This repository has been archived by the owner on Jul 14, 2023. It is now read-only.

Allow customizing blank lines between organized import groups #142

Merged
merged 11 commits into from
Jan 11, 2021
233 changes: 224 additions & 9 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def scalafixIvyDeps = Agg(ivy"com.github.liancheng::organize-imports:{latest-rel

=== Source formatting tools

The `OrganizeImports` rule plays nicely with source formatting tools like https://scalameta.org/scalafmt/[Scalafmt]. If an import statement is already organized according to the configuration, its original source level format would be preserved. For example, in an sbt project, if you run the following command sequence:
The `OrganizeImports` rule plays nicely with source-formatting tools like https://scalameta.org/scalafmt/[Scalafmt]. If an import statement is already organized according to the configuration, its original source level format would be preserved. For example, in an sbt project, if you run the following command sequence:

[source]
----
Expand Down Expand Up @@ -91,6 +91,7 @@ By default, `OrganizeImports` already removes unused imports for you (see the <<
[source,hocon]
----
OrganizeImports {
blankLines = Auto
coalesceToWildcardImportThreshold = 2147483647 # Int.MaxValue
expandRelative = false
groupExplicitlyImportedImplicitsSeparately = false
Expand All @@ -102,6 +103,134 @@ OrganizeImports {
}
----

[[blank-lines]]
=== `blankLines`

Configures whether blank lines between adjacent import groups are automatically or manually inserted. This option is used together with the <<blank-line-marker, `---` blank line markers>>.

==== Value type

Enum: `Auto | Manual`

Auto:: A blank line is automatically inserted between adjacent import groups. All blank line markers (`---`) configured in the <<groups, `groups` option`>> are ignored.

Manual:: A blank line is inserted at all the positions where blank line markers appear in the <<groups, `groups` option>>.

The following two configurations are equivalent:

[source,hocon]
----
OrganizeImports {
blankLines = Auto
groups = [
"re:javax?\\."
"scala."
"*"
]
}

OrganizeImports {
blankLines = Manual
groups = [
"re:javax?\\."
"---"
"scala."
"---"
"*"
]
}
----

==== Default value

`Auto`

==== Examples

`Auto`::
+
--
Configuration:

[source,hocon]
----
OrganizeImports {
blankLines = Auto
groups = [
"re:javax?\\."
"scala."
"*"
]
}
----

Before:

[source,scala]
----
import scala.collection.JavaConverters._
import java.time.Clock
import sun.misc.BASE64Encoder
import javax.annotation.Generated
import scala.concurrent.ExecutionContext
----

After:

[source,scala]
----
import java.time.Clock
import javax.annotation.Generated

import scala.collection.JavaConverters._
import scala.concurrent.ExecutionContext

import sun.misc.BASE64Encoder
----
--

`Manual`::
+
--
Configuration:

[source,hocon]
----
OrganizeImports {
blankLines = Manual
groups = [
"re:javax?\\."
"scala."
"---"
"*"
]
}
----

Before:

[source,scala]
----
import scala.collection.JavaConverters._
import java.time.Clock
import sun.misc.BASE64Encoder
import javax.annotation.Generated
import scala.concurrent.ExecutionContext
----

After:

[source,scala]
----
import java.time.Clock
import javax.annotation.Generated
import scala.collection.JavaConverters._
import scala.concurrent.ExecutionContext

import sun.misc.BASE64Encoder
----
--

[[coalesce]]
=== `coalesceToWildcardImportThreshold`

Expand All @@ -124,7 +253,7 @@ object Example {
----
The type of `Example.m` above is not ambiguous because the mutable `Map` explicitly imported in the second import takes higher precedence than the immutable `Map` imported via wildcard in the first import.

However, if we coalesce the grouped importes in the second import statement into a wildcard, there will be a compilation error:
However, if we coalesce the grouped imports in the second import statement into a wildcard, there will be a compilation error:
[source,scala]
----
import scala.collection.immutable._
Expand All @@ -147,7 +276,7 @@ Integer

Rationale:: Setting the default value to `Int.MaxValue` essentially disables this feature, since it may cause correctness issues.

==== Example
==== Examples

Configuration:

Expand Down Expand Up @@ -217,7 +346,7 @@ Boolean

`false`

==== Example
==== Examples

Configuration:

Expand Down Expand Up @@ -302,7 +431,7 @@ This behavior could be due to a Scala compiler bug since https://scala-lang.org/

Unfortunately, Scalafix is not able to surgically identify conflicting implicit values behind a wildcard import. In order to guarantee correctness in all cases, when the `groupExplicitlyImportedImplicitsSeparately` option is set to `true`, all explicitly imported implicit names are moved into the trailing order-preserving import group together with relative imports, if any (see the <<trailing-order-preserving-import-group, trailing order-preserving import group>> section for more details).

CAUTION: In general, order-sensitive imports are fragile, and can easily be broken by either human collaborators or tools (e.g., the IntelliJ IDEA Scala import optimizer does not handle this case correctly). They should be eliminated whenever possible. This option is mostly useful when you are dealing with a large trunk of legacy codebase and you want to minimize manual intervention and guarantee correctness in all cases.
CAUTION: In general, order-sensitive imports are fragile, and can easily be broken by either human collaborators or tools (e.g., the IntelliJ IDEA Scala import optimizer does not handle this case correctly). They should be eliminated whenever possible. This option is mostly useful when you are dealing with a large trunk of legacy codebase, and you want to minimize manual intervention and guarantee correctness in all cases.

==== Value type

Expand All @@ -321,10 +450,10 @@ This option defaults to `false` due to the following reasons:
+
E.g., why my `scala.concurrent.ExecutionContext.Implicits.global` import is moved to a separate group even if I have a `scala.` group defined in the `groups` option?

. The concerned correctness issue is rarely seen in real life. When it really happens, it is usually a sign of bad coding style and you may want to tweak your imports to eliminate the root cause.
. The concerned correctness issue is rarely seen in real life. When it really happens, it is usually a sign of bad coding style, and you may want to tweak your imports to eliminate the root cause.
--

==== Example
==== Examples

Configuration:

Expand Down Expand Up @@ -462,7 +591,7 @@ object Example {
}
----

At a first glance, it seems feasible to simply drop the second import since `mutable._` already covers `mutble.Map`. However, similar to the example illustrated in the section about the <<coalesce, `coalesceToWildcardImportThreshold` configuration>>, the type of `Example.m` above is `mutable.Map`, because the mutable `Map` explicitly imported in the second import takes higher precedence than the immutable `Map` imported via wildcard in the first import. If we merge the last two imports naively, we'll get:
At a first glance, it seems feasible to simply drop the second import since `mutable._` already covers `mutble.Map`. However, similar to the example illustrated in the section about the <<coalesce, `coalesceToWildcardImportThreshold` option>>, the type of `Example.m` above is `mutable.Map`, because the mutable `Map` explicitly imported in the second import takes higher precedence than the immutable `Map` imported via wildcard in the first import. If we merge the last two imports naively, we'll get:

[source,scala]
----
Expand Down Expand Up @@ -668,6 +797,50 @@ OrganizeImports.groups = ["re:javax?\\.", "scala."]
----
--

[[blank-line-marker]]
A blank line marker::
+
--
A blank line marker, `"---"`, defines a blank line between two adjacent import groups when <<blank-lines, `blankLines`>> is set to `Manual`. It is ignored when `blankLines` is `Auto`. Leading and trailing blank line markers are always ignored. Multiple consecutive blank line markers are treated as a single one. So the following three configurations are all equivalent:

[source,hocon]
----
OrganizeImports {
blankLines = Manual
groups = [
"----"
"re:javax?\\."
"----"
"scala."
"----"
"----"
"*"
"----"
]
}

OrganizeImports {
blankLines = Manual
groups = [
"re:javax?\\."
"---"
"scala."
"---"
"*"
]
}

OrganizeImports {
blankLines = Auto
groups = [
"re:javax?\\."
"scala."
"*"
]
}
----
--

==== Default value

[source,hocon]
Expand Down Expand Up @@ -846,6 +1019,48 @@ import sun.misc.BASE64Encoder
----
--

With manually configured blank lines::
+
--
Configuration:

[source,hocon]
----
OrganizeImports {
blankLines = Manual
groups = [
"*"
"---"
"re:javax?\\."
"scala."
]
}
----

Before:

[source,scala]
----
import scala.collection.JavaConverters._
import java.time.Clock
import sun.misc.BASE64Encoder
import javax.annotation.Generated
import scala.concurrent.ExecutionContext
----

After:

[source,scala]
----
import sun.misc.BASE64Encoder

import java.time.Clock
import javax.annotation.Generated
import scala.collection.JavaConverters._
import scala.concurrent.ExecutionContext
----
--

=== `importSelectorsOrder`

Specifies the order of grouped import selectors within a single import expression.
Expand Down Expand Up @@ -1029,7 +1244,7 @@ Boolean

`true`

==== Example
==== Examples

Configuration:

Expand Down
19 changes: 19 additions & 0 deletions input/src/main/scala/fix/BlankLinesManual.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
rules = [OrganizeImports]
OrganizeImports {
blankLines = Manual
groups = [
"re:javax?\\."
"scala."
"---"
"*"
]
}
*/
package fix

import scala.collection.mutable
import java.util.Arrays
import sun.misc.Unsafe

object BlankLinesManual
2 changes: 1 addition & 1 deletion input/src/main/scala/fix/ExpandRelative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ import scala.util
import util.control
import control.NonFatal

object ExpandRelativeImports
object ExpandRelative
4 changes: 1 addition & 3 deletions input/src/main/scala/fix/ExpandRelativePackageObject.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@ package fix

import PackageObject.a

object ExpandRelativePackageObject {
println(a)
}
object ExpandRelativePackageObject
8 changes: 8 additions & 0 deletions output/src/main/scala/fix/BlankLinesManual.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package fix

import java.util.Arrays
import scala.collection.mutable

import sun.misc.Unsafe

object BlankLinesManual
2 changes: 1 addition & 1 deletion output/src/main/scala/fix/ExpandRelative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import scala.util
import scala.util.control
import scala.util.control.NonFatal

object ExpandRelativeImports
object ExpandRelative
4 changes: 1 addition & 3 deletions output/src/main/scala/fix/ExpandRelativePackageObject.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ package fix

import fix.PackageObject.a

object ExpandRelativePackageObject {
println(a)
}
object ExpandRelativePackageObject
Loading