@@ -32,8 +32,13 @@ open class BasicFormat: SyntaxRewriter {
32
32
/// This is used as a reference-point to indent user-indented code.
33
33
private var anchorPoints : [ TokenSyntax : Trivia ] = [ : ]
34
34
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
37
42
self . indentationStack = [ initialIndentation]
38
43
}
39
44
@@ -132,7 +137,7 @@ open class BasicFormat: SyntaxRewriter {
132
137
var ancestor : Syntax = Syntax ( token)
133
138
while let parent = ancestor. parent {
134
139
ancestor = parent
135
- if ancestor. firstToken ( viewMode : . sourceAccurate ) != token {
140
+ if ancestor. position != token. position {
136
141
break
137
142
}
138
143
if let ancestorsParent = ancestor. parent, childrenSeparatedByNewline ( ancestorsParent) {
@@ -143,22 +148,10 @@ open class BasicFormat: SyntaxRewriter {
143
148
return false
144
149
}
145
150
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!()`
162
155
( . exclamationMark, . period) , // Ensures there is not a space in `myOptionalBar!.foo()`
163
156
( . keyword( . as) , . exclamationMark) , // Ensures there is not a space in `as!`
164
157
( . keyword( . as) , . postfixQuestionMark) , // Ensures there is not a space in `as?`
@@ -172,22 +165,34 @@ open class BasicFormat: SyntaxRewriter {
172
165
break
173
166
}
174
167
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
176
175
}
177
176
178
177
// MARK: - Formatting a token
179
178
180
179
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
+
181
186
lazy var previousTokenWillEndWithWhitespace : Bool = {
182
- guard let previousToken = token . previousToken ( viewMode : . sourceAccurate ) else {
187
+ guard let previousToken = previousToken else {
183
188
return false
184
189
}
185
190
return previousToken. trailingTrivia. pieces. last? . isWhitespace ?? false
186
- || requiresTrailingWhitespace ( previousToken)
191
+ || requiresWhitespace ( between : previousToken, and : token )
187
192
} ( )
188
193
189
194
lazy var previousTokenWillEndWithNewline : Bool = {
190
- guard let previousToken = token . previousToken ( viewMode : . sourceAccurate ) else {
195
+ guard let previousToken = previousToken else {
191
196
// Assume that the start of the tree is equivalent to a newline so we
192
197
// don't add a leading newline to the file.
193
198
return true
@@ -196,7 +201,7 @@ open class BasicFormat: SyntaxRewriter {
196
201
} ( )
197
202
198
203
lazy var nextTokenWillStartWithNewline : Bool = {
199
- guard let nextToken = token . nextToken ( viewMode : . sourceAccurate ) else {
204
+ guard let nextToken = nextToken else {
200
205
return false
201
206
}
202
207
return nextToken. leadingTrivia. startsWithNewline
@@ -206,7 +211,6 @@ open class BasicFormat: SyntaxRewriter {
206
211
/// This token's trailing trivia + any spaces or tabs at the start of the
207
212
/// next token's leading trivia.
208
213
lazy var combinedTrailingTrivia : Trivia = {
209
- let nextToken = token. nextToken ( viewMode: . sourceAccurate)
210
214
let nextTokenLeadingWhitespace = nextToken? . leadingTrivia. prefix ( while: { $0. isSpaceOrTab } ) ?? [ ]
211
215
return trailingTrivia + Trivia( pieces: nextTokenLeadingWhitespace)
212
216
} ( )
@@ -224,7 +228,7 @@ open class BasicFormat: SyntaxRewriter {
224
228
// - the previous token didn't end with a newline
225
229
leadingTrivia = . newline + leadingTrivia
226
230
}
227
- } else if requiresLeadingWhitespace ( token) {
231
+ } else if requiresWhitespace ( between : previousToken , and : token) {
228
232
// Add a leading space if the token requires it unless
229
233
// - it already starts with a whitespace or
230
234
// - the previous token ends with a whitespace after the rewrite
@@ -243,7 +247,7 @@ open class BasicFormat: SyntaxRewriter {
243
247
// - it already ends with a whitespace or
244
248
// - the next token will start starts with a newline after the rewrite
245
249
// because newlines should be preferred to spaces as a whitespace
246
- if requiresTrailingWhitespace ( token)
250
+ if requiresWhitespace ( between : token, and : nextToken )
247
251
&& !trailingTrivia. endsWithWhitespace
248
252
&& !nextTokenWillStartWithNewline
249
253
{
@@ -272,6 +276,10 @@ open class BasicFormat: SyntaxRewriter {
272
276
leadingTrivia = leadingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: false )
273
277
trailingTrivia = trailingTrivia. trimmingTrailingWhitespaceBeforeNewline ( isBeforeNewline: nextTokenWillStartWithNewline)
274
278
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)
276
284
}
277
285
}
0 commit comments