Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Allow more required line breaks#240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
natestedman wants to merge4 commits intoswiftlang:swift-5.3-branch
base:swift-5.3-branch
Choose a base branch
Loading
fromnatestedman:more-line-breaks

Conversation

@natestedman
Copy link

Currently, whenrespectsExistingLineBreaks is set tofalse,swift-format squishes most of code onto single lines when it will fit under the line length limit. I'd like to userespectsExistingLineBreaks so that output is fully deterministic based on the source code structure, but I've found readability is negative impacted by formatting like this:

func foo(bar: Bool) { if bar { print("Bar!") } }

Instead, I'd prefer more line breaks:

func foo(bar: Bool) {    if bar {        print("Bar!")    }}

So, I want to add more options to force the addition of line breaks. Specifically, the ones that I'm currently looking at are:

  • lineBreakBeforeEachFuncBody: after the opening{ of afunc, always use a line break.
  • lineBreakBeforeEachIfElseBody: after the{ followingif orelse, always use a line break.
  • lineBreakBeforeEachLoopBody: same, but for loops.
    • This could be configurable per-loop-type, but would anyone want that?
  • lineBreakBeforeEachSwitchCaseOrDefaultBody: aftercase ...: ordefault:, always use a line break.

The other constructs I can think of areguard andvar. I don't need these, as I think the squished style is more typical for simple, short cases of these, but they could be added as well for the sake of completeness.

I think that this isbasicallyhttps://bugs.swift.org/browse/SR-13458, though these changes won't add moreflexibility, only morerequired line breaks.

I'm putting this up with justlineBreakBeforeEachSwitchCaseOrDefaultBody so that the idea and the implementation can be discussed, if moving forward, I'll stack the other commits and also add tests (testing locally by formatting my Swift code, it appears to work).

I'm also currently targeting theswift-5.3-branch because I'm using Xcode 12 locally, but I expect later on I'll need to rebase to target themain branch?

I also noticed that running the compiledswift-format, like this:

find Sources -name '*.swift' | xargs ./.build/debug/swift-format -i

...against all of the Swift files made a lot of changes, so I manually formatted the code (just the now-longafter call). Isswift-format being used on the repo, and if so, how should I run it?

ra1028, sodastsai, hassila, barkm, okycelt, wollodev, bogdan-razvan, abegehr, and tevelee reacted with thumbs up emoji
@natestedmannatestedman marked this pull request as draftOctober 14, 2020 16:41
Copy link
Member

@allevatoallevato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thanks for working on this! I think better control of when things get one-lined or not is definitely something we need.

Part of me wonders if we could just make logic smarter somehow, with less manual interference. For example, I think many of the cases that look less-than-ideal, like you mentioned, are when you have nested curly-brace structures that happen to be so short that the whole thing can occur on one line:

func log(_ msg:String){if(debugging){print(msg}}}

If the body of this function had multiple statements, this problem resolves itself because there's a hard break between them that forces the break after the open{ of the function.

But in this case, there's only a single statement in the function body (we only look at the direct children, so we don't see the nested statements), so that logic never occurs.

So instead of having separate configuration settings for different types of syntactic constructs, I wonder if we should just try to detect the presence of nested curly brace structures and force the break(s) on the outer one(s) if we do. (And also for the body of statements after acase ...: clause; that should be treated as if it has invisible braces around it for the purposes of this logic.)

Is that something you'd be interested in trying? Do you think it would cover the cases you're concerned about?

@natestedman
Copy link
Author

So, the main thing that I'd want is deterministic output based on the code structure (thus norespectsExistingLineBreaks), but without the "squishing" that comes with a line limit of 120 (pretty typical for iOS) for simple classes, extensions, etc.

But, I don't know that nested braces alone get exactly my ideal formatting. It's pretty subjective, but single-line functions:

func example(arg: Int) -> Int { return arg }

and single lineif:

if something { print("something!") }

Don't feel "normal" (whereas single-line computedvar andguard/else do... can't explain it!). Maybe the former is different with implicit single-expression returns fromfunc being allowed now though!

But, it's less important than avoiding the excessive squishing. I think overall I prefer theresult of this, but:

  1. If the complexity of special-casing so many constructs is too much, a simpler approach is definitely valid, and will get most of the way there.
  2. I made them all separate settings, just going off everything existing being a pretty small config option. But, to reduce complexity somewhat (in config, not so much in the implementation), they could just be one "more line breaks!" option to reduce the number of variations in outputs. Depends whether you value consistency or flexibility inswift-format (e.g.black is very inflexible,clang-format is very flexible).

@allevato
Copy link
Member

Since there's no "blessed" style at this time, I'm open to some degree of configurability, but I also want to avoid having so much that it becomes difficult to maintain, since the current architecture of the pretty printer is such that some options can interact with each other and that causes a combinatorial explosion of edge cases that we'd need to test thoroughly.

The only real constraints (at this time) are that new features do not affect the behavior of the formatter under the default configuration, so that people using it without a configuration don't have their formatter change suddenly.

It's not exactly what you had in mind, but I think I'd be more inclined to partition curly brace behavior based on whether the braces define the body of a type declaration, the body of a non-type declaration (computed property, function), or the body of a statement (if,while, etc.) and allow customization of those categories. That seems better from the point of view of users defining a configuration, so they don't have to audit each individual structure.

@hfossli
Copy link

I want to add tuples to this discussion. I would love to see long unnamed and named tuple arguments break into several lines just as functions do. Why? There's a big movementaway from protocols over to structs. Our codebase uses this a lot and many of the tuples are hard to read.

❌ Current result

structPeopleSearchService{varquery:(      _ query:String?, _ orderBy:String?, _ ascending:Bool?, _ limit:Int?,      _ offset:Int?)->[String]}structCarSearchService{varquery:(      _ args:(        query:String?, orderBy:String?, ascending:Bool?,        limit:Int?, offset:Int?))->[String]}

✅ Wanted result

structPeopleSearchService{varquery:(      _ query:String?,      _ orderBy:String?,      _ ascending:Bool?,      _ limit:Int?,      _ offset:Int?)->[String]}structCarSearchService{varquery:(      _ args:(        query:String?,        orderBy:String?,        ascending:Bool?,        limit:Int?,        offset:Int?))->[String]}
See full example here
{"respectsExistingLineBreaks":false,"lineBreakBeforeControlFlowKeywords":true,"lineBreakBeforeEachArgument":true,"lineLength":80,"maximumBlankLines":1,"respectsExistingLineBreaks":false,"prioritizeKeepingFunctionOutputTogether":false,"lineBreakAroundMultilineExpressionChainComponents":true,"rules": {"BlankLineBetweenMembers":false,"MultiLineTrailingCommas":true,"OneCasePerLine":true,"OneVariableDeclarationPerLine":true,"OnlyOneTrailingClosureArgument":true,"UseSingleLinePropertyGetter":true,  },"tabWidth":4,"version":1}
protocolCompanySearchService{func query(    query:String?,    orderBy:String?,    ascending:Bool?,    limit:Int?,    offset:Int?)->[String]}structMyCompanySearchService:CompanySearchService{func query(    query:String?,    orderBy:String?,    ascending:Bool?,    limit:Int?,    offset:Int?)->[String]{return["a","b","c"]}}structPeopleSearchService{varquery:(      _ query:String?, _ orderBy:String?, _ ascending:Bool?, _ limit:Int?,      _ offset:Int?)->[String]}letmyPeopleSearchService=PeopleSearchService(query:{(query, orderBy, ascending, limit, offset)inreturn["a","b","c"]})structCarSearchService{varquery:(      _ args:(        query:String?, orderBy:String?, ascending:Bool?,        limit:Int?, offset:Int?))->[String]}letmyCarSearchService=CarSearchService(query:{ paramsinlet(query, orderBy, direction, limit, offset)= paramsreturn["a","b","c"]})
stackotter reacted with heart emoji

aaditya-chandrasekhar pushed a commit to val-verde/swift-format that referenced this pull requestMay 20, 2021
…wiftlang#240)* Render GraphViz graphs using library instead of spawning processesUpdate GraphViz dependency* Add BrewfileUse brew bundle in CI
@marius-se
Copy link

marius-se commentedFeb 13, 2024
edited
Loading

@allevato are there any plans on reviving this PR? Would be great to have it!

abegehr, mrstegeman, and tevelee reacted with thumbs up emoji

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@allevatoallevatoallevato left review comments

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

4 participants

@natestedman@allevato@hfossli@marius-se

[8]ページ先頭

©2009-2025 Movatter.jp