Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discretionary line break overridden #470

Open
dabrahams opened this issue Jan 9, 2023 · 9 comments
Open

Discretionary line break overridden #470

dabrahams opened this issue Jan 9, 2023 · 9 comments
Labels
bug Something isn't working

Comments

@dabrahams
Copy link
Contributor

Description

Even though I have

  "respectsExistingLineBreaks" : true,

in my configuration, swift format undoes the line break in this case (and de-indents the where clause)

public func sourceFiles<S: Collection>(in sourcePaths: S) throws -> [SourceFile]
  where S.Element == URL
{
  return try sourceFilePaths(in: sourcePaths).map(SourceFile.init)
}

Steps to Reproduce

No response

@dabrahams dabrahams added the bug Something isn't working label Jan 9, 2023
@allevato allevato transferred this issue from swiftlang/swift-syntax Jan 10, 2023
@allevato
Copy link
Member

respectsExistingLineBreaks still removes line breaks that are considered invalid by the style guidelines that the formatter implements. In this case, since the encoded guidelines indicate that where clauses are aligned +0 from their declaration, the { is placed on the end of that same line (when it fits).

So this is working as intended for now. I'm willing to consider configuration options for different styles but I'm also hesitant right now when it comes to things that affect declaration line-wrapping since the current implementation doesn't scale well as the number of options increases. I have some thoughts on how to improve this going forward, but I haven't had as much time as I'd like to prototype it out.

@dabrahams
Copy link
Contributor Author

It's not the de-indenting of the where clause that I'm reporting as a bug, but the removal of the discretionary line break.

@allevato
Copy link
Member

Do you mean that you would expect this output, given the de-indenting of the where clause?

public func sourceFiles<S: Collection>(in sourcePaths: S) throws -> [SourceFile]
where S.Element == URL
{
  return try sourceFilePaths(in: sourcePaths).map(SourceFile.init)
}

The general philosophy for our current line breaking scheme is that for braced structures, the open brace is on the same line if the indentation is such that the line that would contain the brace is indented less than the lines inside the braces, because there would be no confusion that the latter is a continuation of the former. Only if the line that would normally contain the brace is indented is the brace moved down to its own line, at a reduced indentation level.

Effectively, a line break before the { is not considered discretionary; it is only applied if necessary.

@dabrahams
Copy link
Contributor Author

dabrahams commented Mar 14, 2023 via email

@dabrahams
Copy link
Contributor Author

This feature again fails to do what I expect. If I write:

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

It removes the line break before else. I thought that this feature was supposed to implement my long-ago request, when sf was under development, to “allow discretionary line breaks” but now I suppose I was mistaken.

The docs say

Indicates whether or not existing line breaks in the source code should be honored (if they are valid according to the style guidelines being enforced)

Presumably this means “the style guidelines being enforced” include a rule that there are no line breaks between else and a preceding }. How do I find out what these rules are, and how do I change them? I don't want any rules that prohibit line breaks anywhere. That's what I meant by “allow discretionary line breaks.”

@dabrahams
Copy link
Contributor Author

OK, @allevato, I'm a little sorry to keep hammering on this, but I found documentation of the rules, and there is no mention of anything that prohibits a line break anywhere. What are the actual semantics of respectsExistingLineBreaks?

@allevato
Copy link
Member

allevato commented Dec 6, 2023

We don't really have documentation for all the cases; it's based on the prevailing style that we've chosen to implement. Some of the ideas are documented in https://google.github.io/swift/ but swift-format has also drifted slightly since that document was originally written.

Those specific cases can be examined by looking at TokenStreamCreator's implementation; any breaks that don't have newline behavior of .elective(ignoresDiscretionary: true) will permit a newline to be inserted there. However, this might also cause newlines to be inserted elsewhere for symmetry; for example, the following is not allowed, and a newline would be inserted before the closing brace:

if x {
  print() }

I'll be candid though; I'm extremely hesitant when considering new options that would expand the matrix of configurability for the formatter compared to previously. (Tree examining/transforming rules are less risky, but interactions between different pretty-printing knobs can cause very strange issues.) It's been years since SE-0250 was proposed and deferred, and we're still in the same state regarding whether the Swift project would recommend an official style guide and include swift-format in other official tooling (there's an open PR to add it to sourcekit-lsp, which I think is currently blocked on something Windows-related). Decisions like that would inform what to plan for the future of swift-format, and whether it should be more opinionated like gofmt or be a truly general purpose customizable formatter.

As the sole maintainer of the project, my main priority right now is keeping the logic that we currently have implemented working and expanding it to support new Swift syntactic constructs as they are added to the language. Supporting more customization is a far lower priority.

@dabrahams
Copy link
Contributor Author

Of course you can make whatever choices you want about the design of the project, its functionality, and which patches to accept. The only thing I really feel I have an absolute right to insist on is that the documentation is accurate, complete, and consistent. I would offer to fix the documentation for respectsExistingLineBreaks but after all this back and forth I still don't know what it's supposed to do. Once it's documented, I can decide whether I want to propose a change, fork the project, etc.

@ahoppen
Copy link
Member

ahoppen commented Apr 23, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants