@@ -11,5 +11,195 @@ import SwiftSyntax
11
11
///
12
12
/// - SeeAlso: https://google.github.io/swift#horizontal-whitespace
13
13
public final class OneSpaceAfterKeywords : SyntaxFormatRule {
14
+ public override func visit( _ token: TokenSyntax ) -> Syntax {
15
+ guard let nextToken = token. nextToken else { return token }
16
+
17
+ // Keywords own their trailing spaces, so ensure it only has 1, if there's
18
+ // another token on the same line.
19
+ if token. tokenKind. isTypeKeyword,
20
+ ( nextToken. tokenKind. isTypeKeyword || isIdentifier ( nextToken. tokenKind) ) ,
21
+ !nextToken. leadingTrivia. containsNewlines {
22
+ let numSpaces = token. trailingTrivia. numberOfSpaces
23
+ if numSpaces > 1 {
24
+ diagnose ( . removeSpacesAfterKeyword( numSpaces - 1 , token. description) , on: token)
25
+ return token. withOneTrailingSpace ( )
26
+ }
27
+ }
28
+ return token
29
+ }
30
+ }
31
+
32
+ /// Indicates if the token kind is an identifier
33
+ func isIdentifier( _ tokKind: TokenKind ) -> Bool {
34
+ if case . identifier( _) = tokKind {
35
+ return true
36
+ }
37
+ return false
38
+ }
39
+ extension Diagnostic . Message {
40
+ static func removeSpacesAfterKeyword( _ count: Int , _ keyWord: String ) -> Diagnostic . Message {
41
+ let ending = count == 1 ? " " : " s "
42
+ return Diagnostic . Message ( . warning, " remove \( count) space \( ending) after ' \( keyWord) ' " )
43
+ }
44
+ }
14
45
46
+ extension TokenKind {
47
+
48
+ // Indicates if the token kind is a keyword.
49
+ var isTypeKeyword : Bool {
50
+ switch self {
51
+ case . associatedtypeKeyword:
52
+ return true
53
+ case . classKeyword:
54
+ return true
55
+ case . enumKeyword:
56
+ return true
57
+ case . extensionKeyword:
58
+ return true
59
+ case . funcKeyword:
60
+ return true
61
+ case . importKeyword:
62
+ return true
63
+ case . initKeyword:
64
+ return true
65
+ case . inoutKeyword:
66
+ return true
67
+ case . letKeyword:
68
+ return true
69
+ case . operatorKeyword:
70
+ return true
71
+ case . precedencegroupKeyword:
72
+ return true
73
+ case . protocolKeyword:
74
+ return true
75
+ case . structKeyword:
76
+ return true
77
+ case . subscriptKeyword:
78
+ return true
79
+ case . typealiasKeyword:
80
+ return true
81
+ case . varKeyword:
82
+ return true
83
+ case . fileprivateKeyword:
84
+ return true
85
+ case . internalKeyword:
86
+ return true
87
+ case . privateKeyword:
88
+ return true
89
+ case . publicKeyword:
90
+ return true
91
+ case . staticKeyword:
92
+ return true
93
+ case . deferKeyword:
94
+ return true
95
+ case . ifKeyword:
96
+ return true
97
+ case . guardKeyword:
98
+ return true
99
+ case . doKeyword:
100
+ return true
101
+ case . repeatKeyword:
102
+ return true
103
+ case . elseKeyword:
104
+ return true
105
+ case . forKeyword:
106
+ return true
107
+ case . inKeyword:
108
+ return true
109
+ case . whileKeyword:
110
+ return true
111
+ case . returnKeyword:
112
+ return true
113
+ case . breakKeyword:
114
+ return true
115
+ case . continueKeyword:
116
+ return true
117
+ case . fallthroughKeyword:
118
+ return true
119
+ case . switchKeyword:
120
+ return true
121
+ case . caseKeyword:
122
+ return true
123
+ case . defaultKeyword:
124
+ return true
125
+ case . whereKeyword:
126
+ return true
127
+ case . catchKeyword:
128
+ return true
129
+ case . asKeyword:
130
+ return true
131
+ case . anyKeyword:
132
+ return true
133
+ case . falseKeyword:
134
+ return true
135
+ case . isKeyword:
136
+ return true
137
+ case . nilKeyword:
138
+ return true
139
+ case . rethrowsKeyword:
140
+ return true
141
+ case . superKeyword:
142
+ return true
143
+ case . selfKeyword:
144
+ return true
145
+ case . capitalSelfKeyword:
146
+ return true
147
+ case . throwKeyword:
148
+ return true
149
+ case . trueKeyword:
150
+ return true
151
+ case . tryKeyword:
152
+ return true
153
+ case . throwsKeyword:
154
+ return true
155
+ case . __file__Keyword:
156
+ return true
157
+ case . __line__Keyword:
158
+ return true
159
+ case . __column__Keyword:
160
+ return true
161
+ case . __function__Keyword:
162
+ return true
163
+ case . __dso_handle__Keyword:
164
+ return true
165
+ case . wildcardKeyword:
166
+ return true
167
+ case . poundAvailableKeyword:
168
+ return true
169
+ case . poundEndifKeyword:
170
+ return true
171
+ case . poundElseKeyword:
172
+ return true
173
+ case . poundElseifKeyword:
174
+ return true
175
+ case . poundIfKeyword:
176
+ return true
177
+ case . poundSourceLocationKeyword:
178
+ return true
179
+ case . poundFileKeyword:
180
+ return true
181
+ case . poundLineKeyword:
182
+ return true
183
+ case . poundColumnKeyword:
184
+ return true
185
+ case . poundDsohandleKeyword:
186
+ return true
187
+ case . poundFunctionKeyword:
188
+ return true
189
+ case . poundSelectorKeyword:
190
+ return true
191
+ case . poundKeyPathKeyword:
192
+ return true
193
+ case . poundColorLiteralKeyword:
194
+ return true
195
+ case . poundFileLiteralKeyword:
196
+ return true
197
+ case . poundImageLiteralKeyword:
198
+ return true
199
+ case . contextualKeyword( _) :
200
+ return true
201
+ default :
202
+ return false
203
+ }
204
+ }
15
205
}
0 commit comments