nicklockwood / SwiftFormat

A command-line tool and Xcode Extension for formatting Swift code
MIT License
7.94k stars 639 forks source link

Blank line only after top-level braces #583

Open lukecharman opened 4 years ago

lukecharman commented 4 years ago

I'm trying to set up blankLinesAtStartOfScope to do the following (see the two comments): i.e., a blank line to start non-nested scopes, and no blank line for nested scopes.

import Foundation

class TabBarController: UITabBarController, UITabBarControllerDelegate {
    // I want a blank line here...

    override func viewDidLoad() {
        // But not here
        super.viewDidLoad()
    }
}
nicklockwood commented 4 years ago

This isn't currently supported. I'll consider adding more config options for this rule.

lukecharman commented 4 years ago

Nice, thank you :) Apologies for being a picky sod ;)

tobihagemann commented 4 years ago

I don't think it's picky at all, I was stumbling upon this as well. 😄

jwutke commented 3 years ago

@nicklockwood Is there any interest in a PR for this?

I was thinking of a slightly different approach than the original request. Rather than based on the top level / nested scopes, it would be based on what scope it is. "Type like" scopes (classes, structs, etc) would be one setting, and the rest would be another.

Given this input:

class SomeClass {

  func someFunction() {

    let someArray = [

      "value1",
      "value2",
    ]
  }
}

Removing blanks lines for all (equivalent to current behaviour when the rule is enabled):

class SomeClass {
  func someFunction() {
    let someArray = [
      "value1",
      "value2",
    ]
  }
}

Removing blanks lines for "type like" scopes:

class SomeClass {
  func someFunction() {

    let someArray = [

      "value1",
      "value2",
    ]
  }
}

Removing blanks lines for "other" scopes:

class SomeClass {

  func someFunction() {
    let someArray = [
      "value1",
      "value2",
    ]
  }
}

No removing of blank lines (same as original input, equivalent to current behaviour when the rule is disabled):

class SomeClass {

  func someFunction() {

    let someArray = [

      "value1",
      "value2",
    ]
  }
}

The naming of these settings would need to be improved for sure. This could potentially be done in non-breaking way if the current disabled and enabled settings can be mapped to the none and all settings. I'm definitely looking for input on the best approach for the configuration of it.

I would also take this and use it for blankLinesAtEndOfScope. Let me know what you think.

CC @lukecharman in case you have any thoughts.

nicklockwood commented 3 years ago

@jwutke that's exactly the sort of solution I had in mind. A PR would be amazing 🙏

jwutke commented 3 years ago

Sounds good. I'll open up a draft PR sometime soon and we can continue discussion there.

lukecharman commented 3 years ago

Amazing. You are my heroes :)

H-G-Hristov commented 3 years ago

Blank lines after start and end of nested scopes, including (possible) depending on the type of the scope class,struct,func, etc.:

class A {

    struct B {

         var d: C = ....

         func f() {
               func d() {
                    bla()
               }
         }

         // or 
         func b() {

              func c() {
                  bla()
              }

         }

    }

}
jawwad commented 2 years ago

Hi @nicklockwood,

This is a feature that I'd be interested in as well. I took a look at @jwutke's draft PR #806 to see if I could finish that up or help out on this. There were a few things that I wanted to discuss:

  1. One of them was the shorter option names that you had wanted and that are actually currently required (instead of removeBlankLinesAtStartOfScope and removeBlankLinesAtEndOfScope).
  2. The existing PR only handles removal whereas I'd like to also add a blank line if it's missing. So the option names and option values would have to be slightly different.
  3. My team wants a blank line at the beginning of classes and structs, but not in enums, so we want to have something a bit more granular than just "at-start-of-type" and "at-start-of-other".

Here is what I was thinking in terms of option names, let me know if this makes sense...

--blanklineatstart
--blanklineatend

The existing rule names actually have plural "lines" in them, i.e. blankLinesAtStartOfScope and blankLinesAtEndOfScope. It would have been nice to have the options be blanklinesatstart and blanklinesatend, however blanklinesatstart is 17 characters, i.e. 1 character longer than the limit so I removed the s.

In terms of the actual options here is what I was thinking:

never (default), always, class, struct, protocol, enum, init, func (and any other potential types that have a scope)

The never option would match the existing default. The always option would always add a blank line, and then if the user wanted to have blank lines at the start of certain scopes they would just list them, for example if the user wanted a blank line at the start of classes, structs, and protocols the options they would include would be:

--blanklineatstart class, struct, protocol

I saw your suggestion of the --insertlines and --removelines option, and while I do like those option names, this means the values for the options would need to include "at start" or "at end" making the actual option values a bit more complex. Also, these options could potentially conflict with the existing rules whereas the blanklineatstart and blanklineatend options would just modify the existing rules behavior.

Let me know what your thoughts are on this.