@@ -43,7 +43,7 @@ export class LineFormatter {
43
43
44
44
case TokenType . Comma :
45
45
this . builder . append ( ',' ) ;
46
- if ( next && ! this . isCloseBraceType ( next . type ) ) {
46
+ if ( next && ! this . isCloseBraceType ( next . type ) && next . type !== TokenType . Colon ) {
47
47
this . builder . softAppendSpace ( ) ;
48
48
}
49
49
break ;
@@ -52,7 +52,12 @@ export class LineFormatter {
52
52
if ( prev && ! this . isOpenBraceType ( prev . type ) && prev . type !== TokenType . Colon && prev . type !== TokenType . Operator ) {
53
53
this . builder . softAppendSpace ( ) ;
54
54
}
55
- this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
55
+ const id = this . text . substring ( t . start , t . end ) ;
56
+ this . builder . append ( id ) ;
57
+ if ( this . keywordWithSpaceAfter ( id ) && next && this . isOpenBraceType ( next . type ) ) {
58
+ // for x in ()
59
+ this . builder . softAppendSpace ( ) ;
60
+ }
56
61
break ;
57
62
58
63
case TokenType . Colon :
@@ -84,8 +89,10 @@ export class LineFormatter {
84
89
return this . builder . getText ( ) ;
85
90
}
86
91
92
+ // tslint:disable-next-line:cyclomatic-complexity
87
93
private handleOperator ( index : number ) : void {
88
94
const t = this . tokens . getItemAt ( index ) ;
95
+ const prev = index > 0 ? this . tokens . getItemAt ( index - 1 ) : undefined ;
89
96
if ( t . length === 1 ) {
90
97
const opCode = this . text . charCodeAt ( t . start ) ;
91
98
switch ( opCode ) {
@@ -99,18 +106,36 @@ export class LineFormatter {
99
106
case Char . ExclamationMark :
100
107
this . builder . append ( this . text [ t . start ] ) ;
101
108
return ;
109
+ case Char . Asterisk :
110
+ if ( prev && prev . type === TokenType . Identifier && prev . length === 6 && this . text . substr ( prev . start , prev . length ) === 'lambda' ) {
111
+ this . builder . softAppendSpace ( ) ;
112
+ this . builder . append ( '*' ) ;
113
+ return ;
114
+ }
115
+ break ;
102
116
default :
103
117
break ;
104
118
}
119
+ } else if ( t . length === 2 ) {
120
+ if ( this . text . charCodeAt ( t . start ) === Char . Asterisk && this . text . charCodeAt ( t . start + 1 ) === Char . Asterisk ) {
121
+ if ( ! prev || ( prev . type !== TokenType . Identifier && prev . type !== TokenType . Number ) ) {
122
+ this . builder . append ( '**' ) ;
123
+ return ;
124
+ }
125
+ if ( prev && prev . type === TokenType . Identifier && prev . length === 6 && this . text . substr ( prev . start , prev . length ) === 'lambda' ) {
126
+ this . builder . softAppendSpace ( ) ;
127
+ this . builder . append ( '**' ) ;
128
+ return ;
129
+ }
130
+ }
105
131
}
132
+
106
133
// Do not append space if operator is preceded by '(' or ',' as in foo(**kwarg)
107
- if ( index > 0 ) {
108
- const prev = this . tokens . getItemAt ( index - 1 ) ;
109
- if ( this . isOpenBraceType ( prev . type ) || prev . type === TokenType . Comma ) {
110
- this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
111
- return ;
112
- }
134
+ if ( prev && ( this . isOpenBraceType ( prev . type ) || prev . type === TokenType . Comma ) ) {
135
+ this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
136
+ return ;
113
137
}
138
+
114
139
this . builder . softAppendSpace ( ) ;
115
140
this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
116
141
this . builder . softAppendSpace ( ) ;
@@ -135,43 +160,82 @@ export class LineFormatter {
135
160
return ;
136
161
}
137
162
138
- if ( this . isEqualsInsideArguments ( index - 1 ) ) {
163
+ const prev = index > 0 ? this . tokens . getItemAt ( index - 1 ) : undefined ;
164
+ if ( prev && prev . length === 1 && this . text . charCodeAt ( prev . start ) === Char . Equal && this . isEqualsInsideArguments ( index - 1 ) ) {
139
165
// Don't add space around = inside function arguments.
140
166
this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
141
167
return ;
142
168
}
143
169
144
- if ( index > 0 ) {
145
- const prev = this . tokens . getItemAt ( index - 1 ) ;
146
- if ( this . isOpenBraceType ( prev . type ) || prev . type === TokenType . Colon ) {
147
- // Don't insert space after (, [ or { .
148
- this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
149
- return ;
150
- }
170
+ if ( prev && ( this . isOpenBraceType ( prev . type ) || prev . type === TokenType . Colon ) ) {
171
+ // Don't insert space after (, [ or { .
172
+ this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
173
+ return ;
151
174
}
152
175
153
- // In general, keep tokens separated.
154
- this . builder . softAppendSpace ( ) ;
155
- this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
176
+ if ( t . type === TokenType . Unknown ) {
177
+ this . handleUnknown ( t ) ;
178
+ } else {
179
+ // In general, keep tokens separated.
180
+ this . builder . softAppendSpace ( ) ;
181
+ this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
182
+ }
156
183
}
157
184
185
+ private handleUnknown ( t : IToken ) : void {
186
+ const prevChar = t . start > 0 ? this . text . charCodeAt ( t . start - 1 ) : 0 ;
187
+ if ( prevChar === Char . Space || prevChar === Char . Tab ) {
188
+ this . builder . softAppendSpace ( ) ;
189
+ }
190
+ this . builder . append ( this . text . substring ( t . start , t . end ) ) ;
191
+
192
+ const nextChar = t . end < this . text . length - 1 ? this . text . charCodeAt ( t . end ) : 0 ;
193
+ if ( nextChar === Char . Space || nextChar === Char . Tab ) {
194
+ this . builder . softAppendSpace ( ) ;
195
+ }
196
+ }
158
197
private isEqualsInsideArguments ( index : number ) : boolean {
198
+ // Since we don't have complete statement, this is mostly heuristics.
199
+ // Therefore the code may not be handling all possible ways of the
200
+ // argument list continuation.
159
201
if ( index < 1 ) {
160
202
return false ;
161
203
}
204
+
162
205
const prev = this . tokens . getItemAt ( index - 1 ) ;
163
- if ( prev . type === TokenType . Identifier ) {
164
- if ( index >= 2 ) {
165
- // (x=1 or ,x=1
166
- const prevPrev = this . tokens . getItemAt ( index - 2 ) ;
167
- return prevPrev . type === TokenType . Comma || prevPrev . type === TokenType . OpenBrace ;
168
- } else if ( index < this . tokens . count - 2 ) {
169
- const next = this . tokens . getItemAt ( index + 1 ) ;
170
- const nextNext = this . tokens . getItemAt ( index + 2 ) ;
171
- // x=1, or x=1)
172
- if ( this . isValueType ( next . type ) ) {
173
- return nextNext . type === TokenType . Comma || nextNext . type === TokenType . CloseBrace ;
174
- }
206
+ if ( prev . type !== TokenType . Identifier ) {
207
+ return false ;
208
+ }
209
+
210
+ const first = this . tokens . getItemAt ( 0 ) ;
211
+ if ( first . type === TokenType . Comma ) {
212
+ return true ; // Line starts with commma
213
+ }
214
+
215
+ const last = this . tokens . getItemAt ( this . tokens . count - 1 ) ;
216
+ if ( last . type === TokenType . Comma ) {
217
+ return true ; // Line ends in comma
218
+ }
219
+
220
+ if ( index >= 2 ) {
221
+ // (x=1 or ,x=1
222
+ const prevPrev = this . tokens . getItemAt ( index - 2 ) ;
223
+ return prevPrev . type === TokenType . Comma || prevPrev . type === TokenType . OpenBrace ;
224
+ }
225
+
226
+ if ( index >= this . tokens . count - 2 ) {
227
+ return false ;
228
+ }
229
+
230
+ const next = this . tokens . getItemAt ( index + 1 ) ;
231
+ const nextNext = this . tokens . getItemAt ( index + 2 ) ;
232
+ // x=1, or x=1)
233
+ if ( this . isValueType ( next . type ) ) {
234
+ if ( nextNext . type === TokenType . CloseBrace ) {
235
+ return true ;
236
+ }
237
+ if ( nextNext . type === TokenType . Comma ) {
238
+ return last . type === TokenType . CloseBrace ;
175
239
}
176
240
}
177
241
return false ;
@@ -198,4 +262,10 @@ export class LineFormatter {
198
262
}
199
263
return false ;
200
264
}
265
+ private keywordWithSpaceAfter ( s : string ) : boolean {
266
+ return s === 'in' || s === 'return' || s === 'and' ||
267
+ s === 'or' || s === 'not' || s === 'from' ||
268
+ s === 'import' || s === 'except' || s === 'for' ||
269
+ s === 'as' || s === 'is' ;
270
+ }
201
271
}
0 commit comments