3

I am using SwiftLint and I need to have a new line after the "{" if there is a body, for example, this is correct

    func foo() {
        if true { }
    }

but this doesn't seem right

    func foo() {
        if true { print("This print should be on the new line") }
    }

like this

    func foo() {
        if true { 
          print("This print should be on the new line") 
        }
    }

How to do this?

UPD

Thanks, @Bram, there is such a regex

custom_rules:
 newline_block:
    name: "Newline Block"
    regex: 'if \(?\w+\)? \{[ ]*(.+)+[ ]*\}'
    message: "Statement must be on its own line"

The problem is this regex catch all the conditions with one word after the if, like this

if myCondition { } 

and it doesn't matter if braces are on the next line or not, however, this regex doesn't catch conditions like this

if 0 < 1 { print() }
Sirop4ik
  • 4,543
  • 2
  • 54
  • 121
  • Are you really sure you want to enforce this for all blocks? Note this should be also valid for things like `map { /* */ }`. – Sulthan Jun 30 '22 at 15:28

1 Answers1

1

It appears SwiftLint is a bit flaky with the any single character (.), so the closest I got was this

custom_rules:
  newline_block:
    name: "Newline Block"
    regex: "\\{[ ]*(\\S|( +))+[ ]*\\}"
    message: "Statement must be on its own line"

The better regex would be {[ ]*(.+)+[ ]*} (unescaped), but for some reason that doens't work when I run it at Xcode.

This will work for your request with the prints, but the solution does have some drawbacks:

func foo() {
    // No warning
    if true {}
    // Newline Block Violation: Statement must be on its own line (newline_block)
    if true { }
}

And, but I'm not sure if that applies to you as well:

var connection: OpaquePointer? {
    // Newline Block Violation: Statement must be on its own line 
    get { queue.sync { underlyingConnection } }
    // Newline Block Violation: Statement must be on its own line 
    set { queue.sync { underlyingConnection = newValue } }
}
Bram
  • 2,718
  • 1
  • 22
  • 43
  • Actually, in my case I used this one `{[ ]*(.+)+[ ]*}`, however, I would like to ask one more thing what would be a regex if I need it for `if` condition only? – Sirop4ik Jul 03 '22 at 07:09
  • @AlekseyTimoshchenko you should be fine prefixing the regex with `if`. That way it'll do the same check, but also make sure it has `if` in there. Maybe with one or more spaces as seen in the existing regex, so something along the lines of `if {[ ]*(.+)+[ ]*}` – Bram Jul 03 '22 at 21:09
  • if I set prefix `if` it doesn't work as expected because `if` condition means that there is a condition like `if true { }` , so what I mean is your suggestion will work for `if { print() }`, but not for `if true { print() }`, is there a way to set the rule like `if (condition) { }`? – Sirop4ik Jul 10 '22 at 09:55
  • Oh, damn. Stupid mistake indeed. You can do something like `if \w+ {[ ]*(.+)+[ ]*}` or `if \(\w+\) {[ ]*(.+)+[ ]*}`. The `\w+` does match entire words such as `true` or `someBoolVariable`. You could also combine that into a single statement, where you make the `()` optional. The regex for that would be `if \(?\w+\)? {[ ]*(.+)+[ ]*}` – Bram Jul 17 '22 at 09:54
  • You can also add multiple comma separated variables using `if \(?(\w+,? ?)*\)? {[ ]*(.+)+[ ]*}` – Bram Jul 17 '22 at 10:03
  • edited my question, weird why does this happen? – Sirop4ik Jul 18 '22 at 11:11
  • Ah right, yeah, makes sense that happens. You technically want some kind of regex for any code block with or without curly braces, but that one is quite tricky. You could try playing around with the `.*` operator, but that would skip newlines, so you'd have to play around with something like `if(\s+.*\s+)?{[ ]*(.+)+[ ]*}` – Bram Jul 18 '22 at 11:21