swiftlang / swift-format

Formatting technology for Swift source code
Apache License 2.0
2.39k stars 217 forks source link

Request: Line break for each multiline chain expression #543

Open valentin-mille opened 1 year ago

valentin-mille commented 1 year ago

Is it plan to add line break for each multiline chain expression? It may be really helpful for SwiftUI view modifiers. For example with :

👉 The input view I want to format ```swift import SwiftUI struct OkFormattedView: View { var body: some View { VStack { Text("Hello, world!" ) }.padding().background(.red).frame(maxWidth: .infinity, maxHeight: .infinity) } } ```
❌ The result with the .swift-format configuration file (see below) ```swift import SwiftUI struct OkFormattedView: View { var body: some View { VStack { Text("Hello, world!") } .padding().background(.red).frame(maxWidth: .infinity, maxHeight: .infinity) } } ```
✅ The expected result with the feature request ```swift import SwiftUI struct OkFormattedView: View { var body: some View { VStack { Text("Hello, world!") } .padding() .background(.red) .frame(maxWidth: .infinity, maxHeight: .infinity) } } ```
.swift-format config used ```json { "version" : 1, "lineLength" : 120, "indentation" : { "tabs" : 1 }, "tabWidth" : 4, "maximumBlankLines" : 1, "respectsExistingLineBreaks" : true, "lineBreakBeforeControlFlowKeywords" : false, "lineBreakBeforeEachArgument" : true, "lineBreakBeforeEachGenericRequirement" : false, "prioritizeKeepingFunctionOutputTogether" : false, "indentConditionalCompilationBlocks" : false, "lineBreakAroundMultilineExpressionChainComponents" : true, "fileScopedDeclarationPrivacy" : { "accessLevel" : "private" }, "indentSwitchCaseLabels" : false, "rules" : { "AllPublicDeclarationsHaveDocumentation" : false, "AlwaysUseLowerCamelCase" : true, "AmbiguousTrailingClosureOverload" : true, "BeginDocumentationCommentWithOneLineSummary" : false, "DoNotUseSemicolons" : true, "DontRepeatTypeInStaticProperties" : true, "FileScopedDeclarationPrivacy" : true, "FullyIndirectEnum" : true, "GroupNumericLiterals" : true, "IdentifiersMustBeASCII" : true, "NeverForceUnwrap" : false, "NeverUseForceTry" : false, "NeverUseImplicitlyUnwrappedOptionals" : false, "NoAccessLevelOnExtensionDeclaration" : false, "NoAssignmentInExpressions" : true, "NoBlockComments" : true, "NoCasesWithOnlyFallthrough" : true, "NoEmptyTrailingClosureParentheses" : true, "NoLabelsInCasePatterns" : true, "NoLeadingUnderscores" : false, "NoParensAroundConditions" : true, "NoVoidReturnOnFunctionSignature" : true, "OneCasePerLine" : true, "OneVariableDeclarationPerLine" : true, "OnlyOneTrailingClosureArgument" : true, "OrderedImports" : true, "ReturnVoidInsteadOfEmptyTuple" : true, "UseEarlyExits" : false, "UseLetInEveryBoundCaseVariable" : true, "UseShorthandTypeNames" : true, "UseSingleLinePropertyGetter" : true, "UseSynthesizedInitializer" : true, "UseTripleSlashForDocumentationComments" : true, "UseWhereClausesInForLoops" : false, "ValidateDocumentationComments" : false }, "spacesAroundRangeFormationOperators" : false, } ```
allevato commented 1 year ago

This sounds like an interesting idea. I don't think we'd want it in member chains in general (e.g., a.b.c.d), and I don't want to try to detect things like "this is a SwiftUI context", but maybe we could say that if the chain contains function calls, we always break after each function call?

allevato commented 1 year ago

Actually, can you try setting lineBreakAroundMultilineExpressionChainComponents in your configuration and see if that works for you?

valentin-mille commented 1 year ago

I agree with your point @allevato. We don't need to analyze the context to know if we are in SwiftUI or UIKit. Applying it to every chain function call may be relevant, even in Swift (e.g. Combine code could be an excellent example with chained subscribers).

In my previous message, lineBreakAroundMultilineExpressionChainComponents was set to true and just broke the line of the first chaining expression. Setting it to false doesn't format the chain expression. It may be better to break each multiline expression when the option is true or create another option for that specific case (to not change existing configuration behavior). Please refer to my previous message for more details about the configuration and the results.

kuglee commented 1 year ago

This would be great to have.

HassanTaleb90 commented 9 months ago

Interesting

ahoppen commented 2 months ago

Tracked in Apple’s issue tracker as rdar://126948253