swiftlang / swift-format

Formatting technology for Swift source code
Apache License 2.0
2.45k stars 224 forks source link

Needless line breaks injected #490

Open dabrahams opened 1 year ago

dabrahams commented 1 year ago
    let searchSpace = [currentDirectory.path] + (
      ProcessInfo.processInfo.environment["PATH"] ?? ""
    ).split(separator: pathSeparator).lazy.map(String.init)

It's confounding that swift-format forces a line break after the = in this case, and then rearranges everything else. Is there any way to turn that off?

allevato commented 1 year ago

Not as something easily configurable today. We have logic that determines whether something on the RHS of an assignment is a "complex expression", so things like a single function call would remain on the same line:

let foo = bar(
   some, really, long, arguments)

But a multi-term expression with infix operators would be wrapped before the expression:

let foo =
  bar(x, y) + baz(a, b, c)

IMO, I wouldn't mind being more prescriptive here and always wrapping after the = if any part of the RHS wraps, à la the rectangle rule, but that's probably controversal. And, there are always exceptions (it would be silly to wrap between the = [ of a multi-line collection literal).

So I'm open to considering refinements to the logic we have today, but we'd have to make sure that it doesn't have adverse side effects elsewhere.

dabrahams commented 1 year ago

FWIW, this "complex expression" consideration does not correspond to anything I use when deciding where to break lines, and it clashes with what I consider to be optimal formatting in several cases. Rewinding to the origin of the line-breaking rules (which may no longer be relevant—but are something I know well 😉), the point was to enforce what's required to get basic readability, make efficient use of space, and avoid situations that will cause reformatting busywork on other lines when one line changes, while being easy to follow. The point of my insistence on a "discretionary line breaks" option is that below the level of my rule, humans often have information they can use to convey more about the meaning of the code, and can usually be trusted not to put every token on its own line.

The "complex expression" consideration is vague (not documented AFAICT) and makes it hard for humans to follow the rules without using a tool. I'm not particularly convinced that your example above is better than the alternative, and it's easy for me to think of cases where it's clearly suboptimal, so I'm dubious of its value:

let foo =
  somethingUnlikeTheOtherTerms(x, y) + bar(a, b, c)
   + baz(a, b, c) + qux(a, b, c)

really should be

let foo = somethingUnlikeTheOtherTerms(x, y) 
   + bar(a, b, c) + baz(a, b, c) + qux(a, b, c)

Because it also clashes with my discretion around line breaks, it should at least be disabled when discretionary line breaks are allowed. If you really, really believe in its value, you could say that with discretionary breaks on, lines that obey the other rules will be left alone but a line that the tool must wrap has the "complex expression" heuristic applied.

ahoppen commented 4 months ago

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