Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to set blanks after class/object header/end ? #2888

Closed
KonstantinTr opened this issue Nov 12, 2021 · 4 comments · Fixed by #2893
Closed

How to set blanks after class/object header/end ? #2888

KonstantinTr opened this issue Nov 12, 2021 · 4 comments · Fixed by #2893

Comments

@KonstantinTr
Copy link

Hi!

I am trying to make scalafmt to control the blanks after opening braces and before closing braces (more specifically - remove blanks over the limit) for classes/objects/traits/methods.

In IntelliJ IDEA formatting settings there is a family of settings called keep maximum blank lines and minimum blank lines (with options such as after class header and before class end).

To extend of my knowledge it is not possible to control blanks before/after curly braces with current feature set of scalafmt, would you kindly consider adding such functionality?

Many thanks in advance for all the help!

  • Version: 2.6.4
  • Integration: IntelliJ
  • Configuration:
version = 2.6.4
maxColumn = 100

Steps

Given code like this:

object a {

  val b = 0
  val c = 1


}

When I run scalafmt like this:

scalafmtAll

Problem

Scalafmt formats code like this:

object a {

  val b = 0
  val c = 1


}

Expectation

I would like the formatted output to look like this:

object a {
  val b = 0
  val c = 1
}

Workaround

The closest I have found to the solution is this but it is not possible to have 0 blank lines. On top of that it also inserts blanks between all top level statements of the class. And I need to modify only blanks after opening brace and before closing brace of the class/trait/object

Notes

@kitbellew
Copy link
Collaborator

доводилось ли почитать это: https://scalameta.org/scalafmt/docs/configuration.html#newlinestoplevelstatementblanklines

@KonstantinTr
Copy link
Author

Thanks for the link!
Unfortunately I don't see how I can achieve what I described in the issue with newlines.topLevelStatementBlankLines.

I was thinking to make a regex to narrow the search, but I don't think it will work due to following:
(1) It does not match Token.LeftBracket cause it's not a top level statement (so I will need to somehow match definitions within template)
(2) I can't match something like ^Defn.Object cause expected behaviour would be different if the def is on source-level or a nested definition
(3) There is no way to state minNest to omit source-level statements
(4) I couldn't find how matching only first/last statement works in scalafmt

Would it be asking to match to point out how to overcome the shortcomings posted above?

I am trying to make unformatted:

//somefile.scala

object A {

  val a = 0


  val b = 1

}


object B {
  
  object C {
  
    val a = 0

    val b = 1

  }

}

to look like formatted:

//somefile.scala

object A { //  no blank after header
  val a = 0
  //  max 1 blank between statements within the body
  val b = 1
} //  no blanks before closing brace
//  max 1 blank between statements on source-level
object B { //  no blank after header
  object C { //  no blank after header
    val a = 0
    //  blank between statements within the body is left intact
    val b = 1
  } //  no blanks before closing brace
} //  no blanks before closing brace

Would you consider reopening the issue if you agree that there is no way to configure such formatting with the current functionality of newlines.topLevelStatementBlankLines?

Thnx!

@kitbellew
Copy link
Collaborator

I was thinking to make a regex to narrow the search, but I don't think it will work due to following: (1) It does not match Token.LeftBracket cause it's not a top level statement (so I will need to somehow match definitions within template)

Token.LeftBracket is a token, not a tree so it will never match.

(3) There is no way to state minNest to omit source-level statements

I can add minNest, in addition to maxNest. However, you could always use a maxNest rule that does nothing -- and, therefore, simply blocks other rules. This scenario is clearly documented.

(4) I couldn't find how matching only first/last statement works in scalafmt

Via beforeAll and afterAll, which are also documented.

If you didn't care about nesting constraints, what you want can be accomplished via this:

newlines.topLevelStatementBlankLines = [
  {
    minBreaks = 0
    blanks = {
      before = 1
      after = 1
      beforeAll = -1
      afterAll = -1
    }
  }
]

Otherwise, the only thing that stands in your way is a bug in how nesting is computed (which I will fix shortly).

Keep in mind that scalafmt will always predictably set the number of blanks. If a rule matches (and rules do not care about the existing number of blanks), it will dictate the number. If no rules match, the number of blanks will be no more than 1 (depending on whether there were any blanks to begin with). Therefore, you can't allow a user the flexibility of controlling the number of blanks in some range.

@KonstantinTr
Copy link
Author

@kitbellew This is amazing!
Thanks a ton for the help and special thanks for adding minNest and the bug fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants