@@ -32,8 +32,13 @@ open class BasicFormat: SyntaxRewriter {
3232 /// This is used as a reference-point to indent user-indented code.
3333 private var anchorPoints : [ TokenSyntax : Trivia ] = [ : ]
3434
35- public init ( indentationIncrement: Trivia = . spaces( 4 ) , initialIndentation: Trivia = [ ] ) {
36- self . indentationWidth = indentationIncrement
35+ /// The previously visited token. This is faster than accessing
36+ /// `token.previousToken` inside `visit(_:TokenSyntax)`. `nil` if no token has
37+ /// been visited yet.
38+ private var previousToken : TokenSyntax ? = nil
39+
40+ public init ( indentationWidth: Trivia = . spaces( 4 ) , initialIndentation: Trivia = [ ] ) {
41+ self . indentationWidth = indentationWidth
3742 self . indentationStack = [ initialIndentation]
3843 }
3944
@@ -132,7 +137,7 @@ open class BasicFormat: SyntaxRewriter {
132137 var ancestor : Syntax = Syntax ( token)
133138 while let parent = ancestor. parent {
134139 ancestor = parent
135- if ancestor. firstToken ( viewMode : . sourceAccurate ) != token {
140+ if ancestor. position != token. position {
136141 break
137142 }
138143 if let ancestorsParent = ancestor. parent, childrenSeparatedByNewline ( ancestorsParent) {
@@ -143,22 +148,10 @@ open class BasicFormat: SyntaxRewriter {
143148 return false
144149 }
145150
146- /// Whether a leading space on `token` should be added.
147- open func requiresLeadingWhitespace( _ token: TokenSyntax ) -> Bool {
148- switch ( token. previousToken ( viewMode: . sourceAccurate) ? . tokenKind, token. tokenKind) {
149- case ( . leftParen, . leftBrace) : // Ensures there is not a space in `.map({ $0.foo })`
150- return false
151- default :
152- break
153- }
154-
155- return token. requiresLeadingSpace
156- }
157-
158- /// Whether a trailing space on `token` should be added.
159- open func requiresTrailingWhitespace( _ token: TokenSyntax ) -> Bool {
160- switch ( token. tokenKind, token. nextToken ( viewMode: . sourceAccurate) ? . tokenKind) {
161- case ( . exclamationMark, . leftParen) , // Ensures there is not a space in `myOptionalClosure!()`
151+ open func requiresWhitespace( between first: TokenSyntax ? , and second: TokenSyntax ? ) -> Bool {
152+ switch ( first? . tokenKind, second? . tokenKind) {
153+ case ( . leftParen, . leftBrace) , // Ensures there is not a space in `.map({ $0.foo })`
154+ ( . exclamationMark, . leftParen) , // Ensures there is not a space in `myOptionalClosure!()`
162155 ( . exclamationMark, . period) , // Ensures there is not a space in `myOptionalBar!.foo()`
163156 ( . keyword( . as) , . exclamationMark) , // Ensures there is not a space in `as!`
164157 ( . keyword( . as) , . postfixQuestionMark) , // Ensures there is not a space in `as?`
@@ -172,22 +165,34 @@ open class BasicFormat: SyntaxRewriter {
172165 break
173166 }
174167
175- return token. requiresTrailingSpace
168+ if first? . requiresTrailingSpace ?? false {
169+ return true
170+ }
171+ if second? . requiresLeadingSpace ?? false {
172+ return true
173+ }
174+ return false
176175 }
177176
178177 // MARK: - Formatting a token
179178
180179 open override func visit( _ token: TokenSyntax ) -> TokenSyntax {
180+ defer {
181+ self . previousToken = token
182+ }
183+ let previousToken = self . previousToken ?? token. previousToken ( viewMode: . sourceAccurate)
184+ let nextToken = token. nextToken ( viewMode: . sourceAccurate)
185+
181186 lazy var previousTokenWillEndWithWhitespace : Bool = {
182- guard let previousToken = token . previousToken ( viewMode : . sourceAccurate ) else {
187+ guard let previousToken = previousToken else {
183188 return false
184189 }
185190 return previousToken. trailingTrivia. pieces. last? . isWhitespace ?? false
186- || requiresTrailingWhitespace ( previousToken)
191+ || requiresWhitespace ( between : previousToken, and : token )
187192 } ( )
188193
189194 lazy var previousTokenWillEndWithNewline : Bool = {
190- guard let previousToken = token . previousToken ( viewMode : . sourceAccurate ) else {
195+ guard let previousToken = previousToken else {
191196 // Assume that the start of the tree is equivalent to a newline so we
192197 // don't add a leading newline to the file.
193198 return true
@@ -196,7 +201,7 @@ open class BasicFormat: SyntaxRewriter {
196201 } ( )
197202
198203 lazy var nextTokenWillStartWithNewline : Bool = {
199- guard let nextToken = token . nextToken ( viewMode : . sourceAccurate ) else {
204+ guard let nextToken = nextToken else {
200205 return false
201206 }
202207 return nextToken. leadingTrivia. startsWithNewline
@@ -206,7 +211,6 @@ open class BasicFormat: SyntaxRewriter {
206211 /// This token's trailing trivia + any spaces or tabs at the start of the
207212 /// next token's leading trivia.
208213 lazy var combinedTrailingTrivia : Trivia = {
209- let nextToken = token. nextToken ( viewMode: . sourceAccurate)
210214 let nextTokenLeadingWhitespace = nextToken? . leadingTrivia. prefix ( while: { $0. isSpaceOrTab } ) ?? [ ]
211215 return trailingTrivia + Trivia( pieces: nextTokenLeadingWhitespace)
212216 } ( )
@@ -224,7 +228,7 @@ open class BasicFormat: SyntaxRewriter {
224228 // - the previous token didn't end with a newline
225229 leadingTrivia = . newline + leadingTrivia
226230 }
227- } else if requiresLeadingWhitespace ( token) {
231+ } else if requiresWhitespace ( between : previousToken , and : token) {
228232 // Add a leading space if the token requires it unless
229233 // - it already starts with a whitespace or
230234 // - the previous token ends with a whitespace after the rewrite
@@ -243,7 +247,7 @@ open class BasicFormat: SyntaxRewriter {
243247 // - it already ends with a whitespace or
244248 // - the next token will start starts with a newline after the rewrite
245249 // because newlines should be preferred to spaces as a whitespace
246- if requiresTrailingWhitespace ( token)
250+ if requiresWhitespace ( between : token, and : nextToken )
247251 && !trailingTrivia. endsWithWhitespace
248252 && !nextTokenWillStartWithNewline
249253 {
@@ -272,6 +276,10 @@ open class BasicFormat: SyntaxRewriter {
272276 leadingTrivia = leadingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: false )
273277 trailingTrivia = trailingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: nextTokenWillStartWithNewline)
274278
275- return token. with ( \. leadingTrivia, leadingTrivia) . with ( \. trailingTrivia, trailingTrivia)
279+ if leadingTrivia == token. leadingTrivia && trailingTrivia == token. trailingTrivia {
280+ return token
281+ }
282+
283+ return token. detach ( ) . with ( \. leadingTrivia, leadingTrivia) . with ( \. trailingTrivia, trailingTrivia)
276284 }
277285}
0 commit comments