nicklockwood / SwiftFormat

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

Weird behavior with ternary operator within a block? #1689

Open 20015jjw opened 2 months ago

20015jjw commented 2 months ago

Hi. I've just integrated your lovely tool into the build phrase as the final success step. However, I've noticed a rather weird behavior.

Here's the original code snippet:

    // before
    var test = true
    private lazy var button: Button? = {
        test ? Button {
            $0.setImage(nil, for: .normal)
        } : nil
    }()

After a formatting session, it becomes:

    // after
    var test = true
    private lazy var button: Button? = test ? Button {
        $0.setImage(nil, for: .normal)
    } : nil

However, if I write more lines in the Button's initializer, the formatter starts to add a blank line out of nowhere:

    // before 
    var test = true
    private lazy var button: Button? = {
        test ? Button {
            $0.setImage(nil, for: .normal)
            $0.setImage(nil, for: .normal)
            $0.setImage(nil, for: .normal)
            $0.setImage(nil, for: .normal)
        } : nil
    }()

    // after, notice the second last line
    var test = true
    private lazy var button: Button? = test
        ? Button {
            $0.setImage(nil, for: .normal)
            $0.setImage(nil, for: .normal)
            $0.setImage(nil, for: .normal)
            $0.setImage(nil, for: .normal)
        }

        : nil

I'm not entirely sure if this is intended, but my money is on that it's not.

On a separate note, can we add a rule so the predicate always lives before the ternary operator visually? This is what I mean:

    // before
    var testlonglonglonglonglonglonglonglonglonglong = true
    lazy var test2longlonglonglonglonglonglonglonglonglong = testlonglonglonglonglonglonglonglonglonglong ? "longlonglonglonglonglonglonglonglong" : "longlonglonglonglonglonglonglonglong"

    // with the second line going way beyond the width limit, 
    // but the part before the question mark staying within
    // swiftformat seems to leave the predicate be and only wrap the two branches
    lazy var test2longlonglonglonglonglonglonglonglonglong = testlonglonglonglonglonglonglonglonglonglong
        ? "longlonglonglonglonglonglonglonglong"
        : "longlonglonglonglonglonglonglonglong"

    // if the predicate goes over the width limit, 
    // swiftformat wraps it along with the branches at one more level of indention
    var testlonglonglonglonglonglonglonglonglonglonglong = true
    lazy var test3longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong =
        testlonglonglonglonglonglonglonglonglonglonglong
            ? "longlonglonglonglonglonglonglonglong"
            : "longlong"

    // my thinking is that second case has far better readability as the branch comes after the predicate visually.
    // applying to the original case in the beginning of the issue, I'd like the result to be

    var test = true
    private lazy var button: Button? = 
        test 
          ? Button {
              $0.setImage(nil, for: .normal)
              $0.setImage(nil, for: .normal)
              $0.setImage(nil, for: .normal)
              $0.setImage(nil, for: .normal)
            } 
          : nil

Thanks in advance!