diff --git a/docs/configuration.md b/docs/configuration.md index 00fc950649..2db1521d00 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -4298,6 +4298,68 @@ spaces.afterSymbolicDefs=true def +++(a: A): F[A] ``` +### `spaces.beforeXxxArgInParens` + +> Since v3.7.13. + +These parameters control whether a space should be added before an argument of +a function call or infix expression, if the argument is enclosed in parentheses. + +They take the following values: + +- `Never`: no space is added +- `Always`: space is added +- `AfterSymbolic`: space is added if the infix operator or function name is + symbolic + - doesn't start with a letter or underscore + - for function name only (not for infix): not an + [unary operator](https://docs.scala-lang.org/scala3/reference/changed-features/operators.html#unary-operators): + `+`, `-`, `!`, `~` + +```scala mdoc:defaults +spaces.beforeApplyArgInParens +spaces.beforeInfixArgInParens +``` + +```scala mdoc:scalafmt +spaces.beforeApplyArgInParens = Always +spaces.beforeInfixArgInParens = Always +--- ++(baz) +===(baz) +bar(baz) + +foo +(baz) +foo ===(baz) +foo bar(baz) +``` + +```scala mdoc:scalafmt +spaces.beforeApplyArgInParens = Never +spaces.beforeInfixArgInParens = Never +--- ++ (baz) +=== (baz) +bar (baz) + +foo + (baz) +foo === (baz) +foo bar (baz) +``` + +```scala mdoc:scalafmt +spaces.beforeApplyArgInParens = AfterSymbolic +spaces.beforeInfixArgInParens = AfterSymbolic +--- ++ (baz) +===(baz) +bar (baz) + +foo +(baz) +foo ===(baz) +foo bar (baz) +``` + ## Literals > Since v2.5.0. diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala index 77af28af2a..1ee3c9d199 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala @@ -3,6 +3,7 @@ package org.scalafmt.config import scala.meta.tokens.Token import metaconfig._ +import org.scalafmt.util.TokenOps /** @param beforeContextBoundColon * formats [A: T] as [A : T] @@ -47,6 +48,10 @@ import metaconfig._ case class Spaces( beforeContextBoundColon: Spaces.BeforeContextBound = Spaces.BeforeContextBound.Never, + beforeApplyArgInParens: Spaces.BeforeArgInParens = + Spaces.BeforeArgInParens.Never, + beforeInfixArgInParens: Spaces.BeforeArgInParens = + Spaces.BeforeArgInParens.Always, afterTripleEquals: Boolean = false, inImportCurlyBraces: Boolean = false, inInterpolatedStringCurlyBraces: Boolean = false, @@ -78,4 +83,25 @@ object Spaces { case object IfMultipleBounds extends BeforeContextBound } + sealed abstract class BeforeArgInParens { + def apply(name: => String): Boolean + } + private object BeforeArgInParens { + implicit val codec: ConfCodecEx[BeforeArgInParens] = ReaderUtil + .oneOfCustom[BeforeArgInParens](Never, Always, AfterSymbolic) { + case Conf.Bool(true) => Configured.ok(Always) + case Conf.Bool(false) => Configured.ok(Never) + } + + case object Never extends BeforeArgInParens { + def apply(name: => String): Boolean = false + } + case object Always extends BeforeArgInParens { + def apply(name: => String): Boolean = true + } + case object AfterSymbolic extends BeforeArgInParens { + def apply(name: => String): Boolean = TokenOps.isSymbolicName(name) + } + } + } diff --git a/scalafmt-tests/src/test/resources/unit/Apply.stat b/scalafmt-tests/src/test/resources/unit/Apply.stat index c71a02f0b9..4393e9b15c 100644 --- a/scalafmt-tests/src/test/resources/unit/Apply.stat +++ b/scalafmt-tests/src/test/resources/unit/Apply.stat @@ -62,3 +62,81 @@ test("foo " + case baz => case qux => } +<<< #3607 beforeApplyArgInParens=always +spaces.beforeApplyArgInParens = always +=== +object a { + + () + === () + bar () + + (baz) + === (baz) + bar (baz) + + (baz, qux) + === (baz, qux) + bar (baz, qux) +} +>>> +object a { + +() + ===() + bar() + +(baz) + ===(baz) + bar(baz) + +(baz, qux) + ===(baz, qux) + bar(baz, qux) +} +<<< #3607 beforeApplyArgInParens=never +spaces.beforeApplyArgInParens = never +=== +object a { + + () + === () + bar () + + (baz) + === (baz) + bar (baz) + + (baz, qux) + === (baz, qux) + bar (baz, qux) +} +>>> +object a { + +() + ===() + bar() + +(baz) + ===(baz) + bar(baz) + +(baz, qux) + ===(baz, qux) + bar(baz, qux) +} +<<< #3607 beforeApplyArgInParens=aftersymbolic +spaces.beforeApplyArgInParens = aftersymbolic +=== +object a { + + () + === () + bar () + + (baz) + === (baz) + bar (baz) + + (baz, qux) + === (baz, qux) + bar (baz, qux) +} +>>> +object a { + +() + ===() + bar() + +(baz) + ===(baz) + bar(baz) + +(baz, qux) + ===(baz, qux) + bar(baz, qux) +} diff --git a/scalafmt-tests/src/test/resources/unit/ApplyInfix.stat b/scalafmt-tests/src/test/resources/unit/ApplyInfix.stat index be0bd5b28a..f076a268c5 100644 --- a/scalafmt-tests/src/test/resources/unit/ApplyInfix.stat +++ b/scalafmt-tests/src/test/resources/unit/ApplyInfix.stat @@ -181,3 +181,99 @@ type x = (X type x = (X :: Y :: Z) +<<< #3607 beforeInfixArgInParens=always +spaces.beforeInfixArgInParens = always +=== +object a { + foo + baz + foo === baz + foo bar baz + foo + () + foo === () + foo bar () + foo + (baz) + foo === (baz) + foo bar (baz) + foo + (baz, qux) + foo === (baz, qux) + foo bar (baz, qux) +} +>>> +object a { + foo + baz + foo === baz + foo bar baz + foo + () + foo === () + foo bar () + foo + (baz) + foo === (baz) + foo bar (baz) + foo + (baz, qux) + foo === (baz, qux) + foo bar (baz, qux) +} +<<< #3607 beforeInfixArgInParens=never +spaces.beforeInfixArgInParens = never +=== +object a { + foo + baz + foo === baz + foo bar baz + foo + () + foo === () + foo bar () + foo + (baz) + foo === (baz) + foo bar (baz) + foo + (baz, qux) + foo === (baz, qux) + foo bar (baz, qux) +} +>>> +object a { + foo + baz + foo === baz + foo bar baz + foo + () + foo === () + foo bar () + foo + (baz) + foo === (baz) + foo bar (baz) + foo + (baz, qux) + foo === (baz, qux) + foo bar (baz, qux) +} +<<< #3607 beforeInfixArgInParens=aftersymbolic +spaces.beforeInfixArgInParens = aftersymbolic +=== +object a { + foo + baz + foo === baz + foo bar baz + foo + () + foo === () + foo bar () + foo + (baz) + foo === (baz) + foo bar (baz) + foo + (baz, qux) + foo === (baz, qux) + foo bar (baz, qux) +} +>>> +object a { + foo + baz + foo === baz + foo bar baz + foo + () + foo === () + foo bar () + foo + (baz) + foo === (baz) + foo bar (baz) + foo + (baz, qux) + foo === (baz, qux) + foo bar (baz, qux) +}