Swiftformat: Multi-line guard statement indentation

Created on 5 Oct 2016  路  9Comments  路  Source: nicklockwood/SwiftFormat

This one might require bike shedding. I'm not 100% sure what the general convention is for this, but I prefer to split my guard statements up over a number of lines.

Current SwiftFormat will do this:

guard
     let nextFocusedIndexPath = context.nextFocusedIndexPath,
     nextFocusedIndexPath != context.previouslyFocusedIndexPath
     else {
     return
}

Whereas I would prefer that it outdent the else to align with the guard start (much like an if鈥lse control statement):

guard
     let nextFocusedIndexPath = context.nextFocusedIndexPath,
     nextFocusedIndexPath != context.previouslyFocusedIndexPath
else {
     return
}

In my eyes, that's easier to read, but I understand that's a personal preference.

Most helpful comment

As of v0.12, multiline guard is now indented like this:

guard
     let nextFocusedIndexPath = context.nextFocusedIndexPath,
     nextFocusedIndexPath != context.previouslyFocusedIndexPath
else {
     return
}

All 9 comments

Although if the goal is to match Xcode where possible, they do:

guard
     let nextFocusedIndexPath = context.nextFocusedIndexPath,
     nextFocusedIndexPath != context.previouslyFocusedIndexPath
     else {
          return
}

Matching Xcode is not an explicit goal - in some cases I deliberately deviate from it when it clashes with my own preferences (but in those cases I usually add an option to make it behave like Xcode, unless I think Xcode's behaviour is a bug rather than a deliberate choice by Apple).

Ideally I don't want to deviate too far from Apple standard, nor do I want to try to support every nonstandard variant that people want to use by adding a million config options.

Your usage is neither Apple standard, nor my own preference. I think the best way to handle situations like this might be to offer a way to disable formatting for guard statements, so that it leaves it however you've formatted it.

Fair enough, I do understand your logic. It would be nice if it matched Xcode 馃槃

How do you prefer to format these blocks?

Xcode is (IMHO) inconsistent in how it handles these cases:

// body and closing brace indented based on the indent of the if statement
if foo ||
    bar {
    // do stuff
}

// body indented based on the indent of the opening brace
// closing brace indented based on the indent of the guard statement
guard foo
    else {
        // do stuff
}

// body indented based on the indent of the opening brace
// closing brace indented based on the indent of the first line
foo ||
    bar { _ in
        // do stuff
}

// body indented based on the indent of the opening brace
// closing brace for bar has same indent as body (I think this is a bug)
// final closing brace indented based on the indent of the first line
foo ||
    bar { _ in
        // do stuff
        } // <-- I think this is a bug, it should match the indent of bar
        .baz { _ in
            // do more stuff
}

That's why I explicitly _don't_ want to match Xcode's behavior - because in some of these cases it seems like its behavior is broken/buggy rather than deliberate.

Originally, I was just indenting everything the same way Xcode handles if statements. You pointed out to me that for chained closures this doesn't seem right, which is why I made the changes in 0.11.1 and 0.11.2 to fix that. For chained closures it will now do this, which is not the same as Xcode, but is more logical IMHO:

foo ||
    bar { _ in
        // do stuff
    }
    .baz { _ in
        // do more stuff
    } // <-- arguably this last } could be indented to match foo, but I don't particularly like that

For guard statements, I'm treating the else as a continuation of the guard line, which is why it's indented. I did this because it's what Xcode does. But I indent the body of the else the same way that Xcode does for if statements that wrap onto two lines, because I didn't see any reason why it should be special-cased.

if foo ||
    bar {
    // do stuff
}

guard foo
    else {
    // do stuff < -- this is consistent with the if statement above
}

However, I now realise that indenting else after a guard is arguably not consistent with if/else because it means that these two cases are not handled the same way:

if foo { bar() }
else {
    baz()
}

guard foo
    else { // <-- inconsistent
    baz()
}

So rather than emulating Xcode's behaviour of indenting the inside of the else an extra level (which is inconsistent with everything else) maybe removing the indent for else _would_ be better, as you suggested.

Yeah, there are quite a few Swift formatting issues in Xcode. I'm not sure filing a radar about their whacko indentation of switch cases is more worth of my time than contributing to this project, so I'll do this instead 馃尰

Re: switch/case, do you mean that you'd prefer

switch foo {
    case .bar:
        break
    default:
        break
}

to

switch foo {
case .bar:
    break
default:
    break
}

?

I know I'd prefer the former - indenting the case statements

Should be straightforward to implement, but it would need to be optional (defaulting to current behavior).

As of v0.12, multiline guard is now indented like this:

guard
     let nextFocusedIndexPath = context.nextFocusedIndexPath,
     nextFocusedIndexPath != context.previouslyFocusedIndexPath
else {
     return
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

DagAgren picture DagAgren  路  4Comments

zizi4n5 picture zizi4n5  路  3Comments

PompeiaPaetenari picture PompeiaPaetenari  路  4Comments

meherkasam picture meherkasam  路  3Comments

MaxDesiatov picture MaxDesiatov  路  4Comments