1010//
1111//===----------------------------------------------------------------------===//
1212
13- import SwiftSyntax
13+ @ _spi ( RawSyntax ) import SwiftSyntax
1414
1515/// A rewriter that performs a "basic" format of the passed tree.
1616///
@@ -271,7 +271,7 @@ open class BasicFormat: SyntaxRewriter {
271271 ( . keyword( . `init`) , . leftParen) , // init()
272272 ( . keyword( . self ) , . period) , // self.someProperty
273273 ( . keyword( . Self) , . period) , // self.someProperty
274- ( . keyword( . set) , . leftParen) , // var mYar : Int { set(value) {} }
274+ ( . keyword( . set) , . leftParen) , // var mVar : Int { set(value) {} }
275275 ( . keyword( . subscript) , . leftParen) , // subscript(x: Int)
276276 ( . keyword( . super) , . period) , // super.someProperty
277277 ( . leftBrace, . rightBrace) , // {}
@@ -348,6 +348,26 @@ open class BasicFormat: SyntaxRewriter {
348348 return true
349349 }
350350
351+ /// Change the text of a token during formatting.
352+ ///
353+ /// This allows formats to e.g. replace missing tokens by placeholder tokens.
354+ ///
355+ /// - Parameter token: The token whose text should be changed
356+ /// - Returns: The new text or `nil` if the text should not be changed
357+ open func transformTokenText( _ token: TokenSyntax ) -> String ? {
358+ return nil
359+ }
360+
361+ /// Change the presence of a token during formatting.
362+ ///
363+ /// This allows formats to e.g. replace missing tokens by placeholder tokens.
364+ ///
365+ /// - Parameter token: The token whose presence should be changed
366+ /// - Returns: The new presence or `nil` if the presence should not be changed
367+ open func transformTokenPresence( _ token: TokenSyntax ) -> SourcePresence ? {
368+ return nil
369+ }
370+
351371 // MARK: - Formatting a token
352372
353373 open override func visit( _ token: TokenSyntax ) -> TokenSyntax {
@@ -357,6 +377,8 @@ open class BasicFormat: SyntaxRewriter {
357377 let isInitialToken = self . previousToken == nil
358378 let previousToken = self . previousToken ?? token. previousToken ( viewMode: viewMode)
359379 let nextToken = token. nextToken ( viewMode: viewMode)
380+ let transformedTokenText = self . transformTokenText ( token)
381+ let transformedTokenPresence = self . transformTokenPresence ( token)
360382
361383 /// In addition to existing trivia of `previousToken`, also considers
362384 /// `previousToken` as ending with whitespace if it and `token` should be
@@ -372,7 +394,7 @@ open class BasicFormat: SyntaxRewriter {
372394 || ( requiresWhitespace ( between: previousToken, and: token) && isMutable ( previousToken) )
373395 } ( )
374396
375- /// This method does not consider any posssible mutations to `previousToken`
397+ /// This method does not consider any possible mutations to `previousToken`
376398 /// because newlines should be added to the next token's leading trivia.
377399 let previousTokenWillEndWithNewline : Bool = {
378400 guard let previousToken = previousToken else {
@@ -416,6 +438,14 @@ open class BasicFormat: SyntaxRewriter {
416438 if nextToken. leadingTrivia. startsWithNewline {
417439 return true
418440 }
441+ if nextToken. leadingTrivia. isEmpty {
442+ if nextToken. text. first? . isNewline ?? false {
443+ return true
444+ }
445+ if nextToken. text. isEmpty && nextToken. trailingTrivia. startsWithNewline {
446+ return true
447+ }
448+ }
419449 if requiresNewline ( between: token, and: nextToken) ,
420450 isMutable ( nextToken) ,
421451 !token. trailingTrivia. endsWithNewline,
@@ -436,6 +466,19 @@ open class BasicFormat: SyntaxRewriter {
436466 return trailingTrivia + Trivia( pieces: nextTokenLeadingWhitespace)
437467 } ( )
438468
469+ /// Whether the leading trivia of the token is followed by a newline.
470+ let leadingTriviaIsFollowedByNewline : Bool = {
471+ if ( transformedTokenText ?? token. text) . isEmpty && token. trailingTrivia. startsWithNewline {
472+ return true
473+ } else if token. text. first? . isNewline ?? false {
474+ return true
475+ } else if ( transformedTokenText ?? token. text) . isEmpty && token. trailingTrivia. isEmpty && nextTokenWillStartWithNewline {
476+ return true
477+ } else {
478+ return false
479+ }
480+ } ( )
481+
439482 if requiresNewline ( between: previousToken, and: token) {
440483 // Add a leading newline if the token requires it unless
441484 // - it already starts with a newline or
@@ -455,7 +498,8 @@ open class BasicFormat: SyntaxRewriter {
455498 }
456499 }
457500
458- if leadingTrivia. indentation ( isOnNewline: isInitialToken || previousTokenWillEndWithNewline) == [ ] {
501+ let isEmptyLine = token. leadingTrivia. isEmpty && leadingTriviaIsFollowedByNewline
502+ if leadingTrivia. indentation ( isOnNewline: isInitialToken || previousTokenWillEndWithNewline) == [ ] && !isEmptyLine {
459503 // If the token starts on a new line and does not have indentation, this
460504 // is the last non-indented token. Store its indentation level
461505 anchorPoints [ token] = currentIndentationLevel
@@ -501,14 +545,24 @@ open class BasicFormat: SyntaxRewriter {
501545 leadingTrivia = leadingTrivia. indented ( indentation: leadingTriviaIndentation, isOnNewline: previousTokenIsStringLiteralEndingInNewline)
502546 trailingTrivia = trailingTrivia. indented ( indentation: trailingTriviaIndentation, isOnNewline: false )
503547
504- leadingTrivia = leadingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: false )
548+ leadingTrivia = leadingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: leadingTriviaIsFollowedByNewline )
505549 trailingTrivia = trailingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: nextTokenWillStartWithNewline)
506550
507- if leadingTrivia == token. leadingTrivia && trailingTrivia == token. trailingTrivia {
508- return token
551+ var result = token. detached
552+ if leadingTrivia != result. leadingTrivia {
553+ result = result. with ( \. leadingTrivia, leadingTrivia)
509554 }
510-
511- return token. detached. with ( \. leadingTrivia, leadingTrivia) . with ( \. trailingTrivia, trailingTrivia)
555+ if trailingTrivia != result. trailingTrivia {
556+ result = result. with ( \. trailingTrivia, trailingTrivia)
557+ }
558+ if let transformedTokenText {
559+ let newKind = TokenKind . fromRaw ( kind: token. tokenKind. decomposeToRaw ( ) . rawKind, text: transformedTokenText)
560+ result = result. with ( \. tokenKind, newKind) . with ( \. presence, . present)
561+ }
562+ if let transformedTokenPresence {
563+ result = result. with ( \. presence, transformedTokenPresence)
564+ }
565+ return result
512566 }
513567}
514568
0 commit comments