Skip to content

Commit 44edbc0

Browse files
authored
Merge pull request swiftlang#103 from dylansturg/stop_breaking_conditional_compilation
Disable breaks inside of #if conditionals.
2 parents 4a07aa0 + 3c45c79 commit 44edbc0

File tree

5 files changed

+140
-1
lines changed

5 files changed

+140
-1
lines changed

Sources/SwiftFormatPrettyPrint/PrettyPrint.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,15 @@ public class PrettyPrinter {
9696
/// `currentLineIsContinuation` to become true).
9797
private var wasLastBreakKindContinue = false
9898

99+
/// Tracks how many printer control tokens to suppress firing breaks are active.
100+
private var activeBreakSuppressionCount = 0
101+
102+
/// Whether breaks are supressed from firing. When true, no breaks should fire and the only way to
103+
/// move to a new line is an explicit new line token.
104+
private var isBreakingSupressed: Bool {
105+
return activeBreakSuppressionCount > 0
106+
}
107+
99108
/// The computed indentation level, as a number of spaces, based on the state of any unclosed
100109
/// delimiters and whether or not the current line is a continuation line.
101110
private var currentIndentation: [Indent] {
@@ -283,6 +292,7 @@ public class PrettyPrinter {
283292
// scope. Additionally, continuation open breaks must indent when the break fires.
284293
let continuationBreakWillFire = openKind == .continuation
285294
&& (isAtStartOfLine || length > spaceRemaining || mustBreak)
295+
&& !isBreakingSupressed
286296
let contributesContinuationIndent = currentLineIsContinuation || continuationBreakWillFire
287297

288298
activeOpenBreaks.append(
@@ -387,7 +397,7 @@ public class PrettyPrinter {
387397
mustBreak = currentLineIsContinuation
388398
}
389399

390-
if (!isAtStartOfLine && length > spaceRemaining) || mustBreak {
400+
if !isBreakingSupressed && ((!isAtStartOfLine && length > spaceRemaining) || mustBreak) {
391401
currentLineIsContinuation = isContinuationIfBreakFires
392402
writeNewlines(1, kind: .flexible)
393403
lastBreak = true
@@ -451,6 +461,14 @@ public class PrettyPrinter {
451461
pendingSpaces = 0
452462
lastBreak = false
453463
spaceRemaining -= length
464+
465+
case .printerControl(let kind):
466+
switch kind {
467+
case .disableBreaking:
468+
activeBreakSuppressionCount += 1
469+
case .enableBreaking:
470+
activeBreakSuppressionCount -= 1
471+
}
454472
}
455473
}
456474

@@ -554,6 +572,10 @@ public class PrettyPrinter {
554572
}
555573
lengths.append(length)
556574
total += length
575+
576+
case .printerControl:
577+
// Control tokens have no length. They aren't printed.
578+
lengths.append(0)
557579
}
558580
}
559581

@@ -642,6 +664,9 @@ public class PrettyPrinter {
642664
printDebugIndent()
643665
print("[VERBATIM Length: \(length) Idx: \(idx)]")
644666
print(verbatim.print(indent: debugIndent))
667+
668+
case .printerControl(let kind):
669+
print("[PRINTER CONTROL Kind: \(kind)]")
645670
}
646671
}
647672

Sources/SwiftFormatPrettyPrint/Token.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,21 @@ enum NewlineKind {
141141
case mandatory
142142
}
143143

144+
/// Kinds of printer control tokens that can be used to customize the pretty printer's behavior in
145+
/// a subsection of a token stream.
146+
enum PrinterControlKind {
147+
/// A signal that break tokens shouldn't be allowed to fire until a corresponding enable breaking
148+
/// control token is encountered.
149+
///
150+
/// It's valid to nest `disableBreaking` and `enableBreaking` tokens. Breaks will be suppressed
151+
/// long as there is at least 1 unmatched disable token.
152+
case disableBreaking
153+
154+
/// A signal that break tokens should be allowed to fire following this token, as long as there
155+
/// are no other unmatched disable tokens.
156+
case enableBreaking
157+
}
158+
144159
enum Token {
145160
case syntax(String)
146161
case open(GroupBreakStyle)
@@ -150,6 +165,7 @@ enum Token {
150165
case newlines(Int, kind: NewlineKind)
151166
case comment(Comment, wasEndOfLine: Bool)
152167
case verbatim(Verbatim)
168+
case printerControl(kind: PrinterControlKind)
153169

154170
// Convenience overloads for the enum types
155171
static let open = Token.open(.inconsistent, 0)

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,12 @@ private final class TokenStreamCreator: SyntaxVisitor {
956956
} else {
957957
before(tokenToOpenWith.nextToken, tokens: .break(breakKindClose), .newline, .close)
958958
}
959+
960+
if let condition = node.condition {
961+
before(condition.firstToken, tokens: .printerControl(kind: .disableBreaking))
962+
after(condition.lastToken, tokens: .printerControl(kind: .enableBreaking), .break(.reset, size: 0))
963+
}
964+
959965
return .visitChildren
960966
}
961967

Tests/SwiftFormatPrettyPrintTests/IfConfigTests.swift

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,93 @@ public class IfConfigTests: PrettyPrintTestCase {
141141

142142
assertPrettyPrintEqual(input: input, expected: expected, linelength: 45)
143143
}
144+
145+
public func testPrettyPrintLineBreaksDisabled() {
146+
let input =
147+
"""
148+
#if canImport(SwiftUI) && !(os(iOS)&&arch( arm ) )&&( (canImport(AppKit) || canImport(UIKit)) && !os(watchOS))
149+
conditionalFunc(foo, bar, baz)
150+
#endif
151+
"""
152+
153+
let expected =
154+
"""
155+
#if canImport(SwiftUI) && !(os(iOS) && arch(arm)) && ((canImport(AppKit) || canImport(UIKit)) && !os(watchOS))
156+
conditionalFunc(foo, bar, baz)
157+
#endif
158+
159+
"""
160+
161+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 40)
162+
}
163+
164+
public func testInvalidDiscretionaryLineBreaksRemoved() {
165+
let input =
166+
"""
167+
#if (canImport(SwiftUI) &&
168+
!(os(iOS) &&
169+
arch(arm)) &&
170+
((canImport(AppKit) ||
171+
canImport(UIKit)) && !os(watchOS)))
172+
conditionalFunc(foo, bar, baz)
173+
#endif
174+
"""
175+
176+
let expected =
177+
"""
178+
#if (canImport(SwiftUI) && !(os(iOS) && arch(arm)) && ((canImport(AppKit) || canImport(UIKit)) && !os(watchOS)))
179+
conditionalFunc(foo, bar, baz)
180+
#endif
181+
182+
"""
183+
184+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 40)
185+
}
186+
187+
public func testValidDiscretionaryLineBreaksRetained() {
188+
let input =
189+
"""
190+
#if (canImport(SwiftUI)
191+
&& !(os(iOS)
192+
&& arch(arm))
193+
&& ((canImport(AppKit)
194+
|| canImport(UIKit)) && !os(watchOS))
195+
&& canImport(Foundation))
196+
conditionalFunc(foo, bar, baz)
197+
#endif
198+
199+
#if (canImport(SwiftUI)
200+
&& os(iOS)
201+
&& arch(arm)
202+
&& canImport(AppKit)
203+
|| canImport(UIKit) && !os(watchOS)
204+
&& canImport(Foundation))
205+
conditionalFunc(foo, bar, baz)
206+
#endif
207+
"""
208+
209+
let expected =
210+
"""
211+
#if (canImport(SwiftUI)
212+
&& !(os(iOS)
213+
&& arch(arm))
214+
&& ((canImport(AppKit)
215+
|| canImport(UIKit)) && !os(watchOS))
216+
&& canImport(Foundation))
217+
conditionalFunc(foo, bar, baz)
218+
#endif
219+
220+
#if (canImport(SwiftUI)
221+
&& os(iOS)
222+
&& arch(arm)
223+
&& canImport(AppKit)
224+
|| canImport(UIKit) && !os(watchOS)
225+
&& canImport(Foundation))
226+
conditionalFunc(foo, bar, baz)
227+
#endif
228+
229+
"""
230+
231+
assertPrettyPrintEqual(input: input, expected: expected, linelength: 40)
232+
}
144233
}

Tests/SwiftFormatPrettyPrintTests/XCTestManifests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,10 @@ extension IfConfigTests {
313313
static let __allTests__IfConfigTests = [
314314
("testBasicIfConfig", testBasicIfConfig),
315315
("testIfConfigNoIndentation", testIfConfigNoIndentation),
316+
("testInvalidDiscretionaryLineBreaksRemoved", testInvalidDiscretionaryLineBreaksRemoved),
316317
("testPoundIfAroundMembers", testPoundIfAroundMembers),
318+
("testPrettyPrintLineBreaksDisabled", testPrettyPrintLineBreaksDisabled),
319+
("testValidDiscretionaryLineBreaksRetained", testValidDiscretionaryLineBreaksRetained),
317320
]
318321
}
319322

0 commit comments

Comments
 (0)