14 |
14 |
15 from PyQt4.QtCore import QObject |
15 from PyQt4.QtCore import QObject |
16 |
16 |
17 from E5Gui import E5MessageBox |
17 from E5Gui import E5MessageBox |
18 |
18 |
|
19 from . import pep8 |
|
20 |
19 import Utilities |
21 import Utilities |
20 |
22 |
21 Pep8FixableIssues = ["E101", "E111", "W191", "E201", "E202", "E203", |
23 Pep8FixableIssues = ["E101", "E111", "E121", "E122", "E123", "E124", |
|
24 "E125", "E126", "E127", "E128", "E133", "W191", "E201", "E202", "E203", |
22 "E211", "E221", "E222", "E223", "E224", "E225", |
25 "E211", "E221", "E222", "E223", "E224", "E225", |
23 "E226", "E227", "E228", "E231", "E241", "E242", |
26 "E226", "E227", "E228", "E231", "E241", "E242", |
24 "E251", "E261", "E262", "E271", "E272", "E273", |
27 "E251", "E261", "E262", "E271", "E272", "E273", |
25 "E274", "W291", "W292", "W293", "E301", "E302", |
28 "E274", "W291", "W292", "W293", "E301", "E302", |
26 "E303", "E304", "W391", "E401", "E502", "W603", |
29 "E303", "E304", "W391", "E401", "E502", "W603", |
63 "fixed_" + os.path.basename(self.__filename)) |
66 "fixed_" + os.path.basename(self.__filename)) |
64 |
67 |
65 self.__fixes = { |
68 self.__fixes = { |
66 "E101": self.__fixE101, |
69 "E101": self.__fixE101, |
67 "E111": self.__fixE101, |
70 "E111": self.__fixE101, |
|
71 "E121": self.__fixE121, |
|
72 "E122": self.__fixE122, |
|
73 "E123": self.__fixE123, |
|
74 "E124": self.__fixE121, |
|
75 "E125": self.__fixE125, |
|
76 "E126": self.__fixE126, |
|
77 "E127": self.__fixE127, |
|
78 "E128": self.__fixE127, |
|
79 "E133": self.__fixE126, |
68 "W191": self.__fixE101, |
80 "W191": self.__fixE101, |
69 "E201": self.__fixE201, |
81 "E201": self.__fixE201, |
70 "E202": self.__fixE201, |
82 "E202": self.__fixE201, |
71 "E203": self.__fixE201, |
83 "E203": self.__fixE201, |
72 "E211": self.__fixE201, |
84 "E211": self.__fixE201, |
185 self.__eol = self.__project.getEolString() |
205 self.__eol = self.__project.getEolString() |
186 else: |
206 else: |
187 self.__eol = Utilities.linesep() |
207 self.__eol = Utilities.linesep() |
188 return self.__eol |
208 return self.__eol |
189 |
209 |
|
210 def __findLogical(self): |
|
211 """ |
|
212 Private method to extract the index of all the starts and ends of lines. |
|
213 |
|
214 @return tuple containing two lists of integer with start and end tuples |
|
215 of lines |
|
216 """ |
|
217 logical_start = [] |
|
218 logical_end = [] |
|
219 last_newline = True |
|
220 sio = io.StringIO("".join(self.__source)) |
|
221 parens = 0 |
|
222 for t in tokenize.generate_tokens(sio.readline): |
|
223 if t[0] in [tokenize.COMMENT, tokenize.DEDENT, |
|
224 tokenize.INDENT, tokenize.NL, |
|
225 tokenize.ENDMARKER]: |
|
226 continue |
|
227 if not parens and t[0] in [tokenize.NEWLINE, tokenize.SEMI]: |
|
228 last_newline = True |
|
229 logical_end.append((t[3][0] - 1, t[2][1])) |
|
230 continue |
|
231 if last_newline and not parens: |
|
232 logical_start.append((t[2][0] - 1, t[2][1])) |
|
233 last_newline = False |
|
234 if t[0] == tokenize.OP: |
|
235 if t[1] in '([{': |
|
236 parens += 1 |
|
237 elif t[1] in '}])': |
|
238 parens -= 1 |
|
239 return logical_start, logical_end |
|
240 |
|
241 def __getLogical(self, line, pos): |
|
242 """ |
|
243 Private method to get the logical line corresponding to the given |
|
244 position. |
|
245 |
|
246 @param line line number of the issue (integer) |
|
247 @param pos position inside line (integer) |
|
248 @return tuple of a tuple of two integers giving the start of the |
|
249 logical line, another tuple of two integers giving the end |
|
250 of the logical line and a list of strings with the original |
|
251 source lines |
|
252 """ |
|
253 try: |
|
254 (logical_start, logical_end) = self.__findLogical() |
|
255 except (SyntaxError, tokenize.TokenError): |
|
256 return None |
|
257 |
|
258 line = line - 1 |
|
259 ls = None |
|
260 le = None |
|
261 for i in range(0, len(logical_start)): |
|
262 x = logical_end[i] |
|
263 if x[0] > line or (x[0] == line and x[1] > pos): |
|
264 le = x |
|
265 ls = logical_start[i] |
|
266 break |
|
267 if ls is None: |
|
268 return None |
|
269 |
|
270 original = self.__source[ls[0]:le[0] + 1] |
|
271 return ls, le, original |
|
272 |
190 def __getIndentWord(self): |
273 def __getIndentWord(self): |
191 """ |
274 """ |
192 Private method to determine the indentation type. |
275 Private method to determine the indentation type. |
193 |
276 |
194 @return string to be used for an indentation (string) |
277 @return string to be used for an indentation (string) |
210 |
293 |
211 @param line line to determine the indentation string from (string) |
294 @param line line to determine the indentation string from (string) |
212 @return indentation string (string) |
295 @return indentation string (string) |
213 """ |
296 """ |
214 return line.replace(line.lstrip(), "") |
297 return line.replace(line.lstrip(), "") |
|
298 |
|
299 def __fixReindent(self, line, pos, logical): |
|
300 """ |
|
301 Private method to fix a badly indented line. |
|
302 |
|
303 This is done by adding or removing from its initial indent only. |
|
304 |
|
305 @param line line number of the issue (integer) |
|
306 @param pos position inside line (integer) |
|
307 @return flag indicating a change was done (boolean) |
|
308 """ |
|
309 assert logical |
|
310 ls, _, original = logical |
|
311 |
|
312 rewrapper = Pep8IndentationWrapper(original) |
|
313 valid_indents = rewrapper.pep8Expected() |
|
314 if not rewrapper.rel_indent: |
|
315 return False |
|
316 |
|
317 if line > ls[0]: |
|
318 # got a valid continuation line number |
|
319 row = line - ls[0] - 1 |
|
320 # always pick the first option for this |
|
321 valid = valid_indents[row] |
|
322 got = rewrapper.rel_indent[row] |
|
323 else: |
|
324 return False |
|
325 |
|
326 line1 = ls[0] + row |
|
327 # always pick the expected indent, for now. |
|
328 indent_to = valid[0] |
|
329 |
|
330 if got != indent_to: |
|
331 orig_line = self.__source[line1] |
|
332 new_line = ' ' * (indent_to) + orig_line.lstrip() |
|
333 if new_line == orig_line: |
|
334 return False |
|
335 else: |
|
336 self.__source[line1] = new_line |
|
337 return True |
|
338 else: |
|
339 return False |
215 |
340 |
216 def __fixWhitespace(self, line, offset, replacement): |
341 def __fixWhitespace(self, line, offset, replacement): |
217 """ |
342 """ |
218 Private method to correct whitespace at the given offset. |
343 Private method to correct whitespace at the given offset. |
219 |
344 |
252 msg = self.trUtf8("Indentation adjusted to be a multiple of four.") |
377 msg = self.trUtf8("Indentation adjusted to be a multiple of four.") |
253 return (True, msg) |
378 return (True, msg) |
254 else: |
379 else: |
255 return (False, self.trUtf8("Fix for {0} failed.").format(code)) |
380 return (False, self.trUtf8("Fix for {0} failed.").format(code)) |
256 |
381 |
|
382 def __fixE121(self, code, line, pos, apply=False): |
|
383 """ |
|
384 Private method to fix the indentation of continuation lines and |
|
385 closing brackets (E121,E124). |
|
386 |
|
387 @param code code of the issue (string) |
|
388 @param line line number of the issue (integer) |
|
389 @param pos position inside line (integer) |
|
390 @keyparam apply flag indicating, that the fix should be applied |
|
391 (boolean) |
|
392 @return flag indicating an applied fix (boolean) and a message for |
|
393 the fix (string) |
|
394 """ |
|
395 if apply: |
|
396 logical = self.__getLogical(line, pos) |
|
397 if logical: |
|
398 # Fix by adjusting initial indent level. |
|
399 self.__fixReindent(line, pos, logical) |
|
400 else: |
|
401 self.__stackLogical.append((code, line, pos)) |
|
402 if code == "E121": |
|
403 msg = self.trUtf8("Indentation of continuation line corrected.") |
|
404 elif code == "E124": |
|
405 msg = self.trUtf8("Indentation of closing bracket corrected.") |
|
406 return (True, msg) |
|
407 |
|
408 def __fixE122(self, code, line, pos, apply=False): |
|
409 """ |
|
410 Private method to fix a missing indentation of continuation lines (E122). |
|
411 |
|
412 @param code code of the issue (string) |
|
413 @param line line number of the issue (integer) |
|
414 @param pos position inside line (integer) |
|
415 @keyparam apply flag indicating, that the fix should be applied |
|
416 (boolean) |
|
417 @return flag indicating an applied fix (boolean) and a message for |
|
418 the fix (string) |
|
419 """ |
|
420 if apply: |
|
421 logical = self.__getLogical(line, pos) |
|
422 if logical: |
|
423 # Fix by adding an initial indent. |
|
424 modified = self.__fixReindent(line, pos, logical) |
|
425 if not modified: |
|
426 # fall back to simple method |
|
427 line = line - 1 |
|
428 text = self.__source[line] |
|
429 indentation = self.__getIndent(text) |
|
430 self.__source[line] = indentation + \ |
|
431 self.__indentWord + text.lstrip() |
|
432 else: |
|
433 self.__stackLogical.append((code, line, pos)) |
|
434 return (True, self.trUtf8("Missing indentation of continuation line corrected.")) |
|
435 |
|
436 def __fixE123(self, code, line, pos, apply=False): |
|
437 """ |
|
438 Private method to fix the indentation of a closing bracket lines (E123). |
|
439 |
|
440 @param code code of the issue (string) |
|
441 @param line line number of the issue (integer) |
|
442 @param pos position inside line (integer) |
|
443 @keyparam apply flag indicating, that the fix should be applied |
|
444 (boolean) |
|
445 @return flag indicating an applied fix (boolean) and a message for |
|
446 the fix (string) |
|
447 """ |
|
448 if apply: |
|
449 logical = self.__getLogical(line, pos) |
|
450 if logical: |
|
451 # Fix by deleting whitespace to the correct level. |
|
452 logicalLines = logical[2] |
|
453 row = line - 1 |
|
454 text = self.__source[row] |
|
455 newText = self.__getIndent(logicalLines[0]) + text.lstrip() |
|
456 if newText == text: |
|
457 # fall back to slower method |
|
458 self.__fixReindent(line, pos, logical) |
|
459 else: |
|
460 self.__source[row] = newText |
|
461 else: |
|
462 self.__stackLogical.append((code, line, pos)) |
|
463 return (True, self.trUtf8("Closing bracket aligned to opening bracket.")) |
|
464 |
|
465 def __fixE125(self, code, line, pos, apply=False): |
|
466 """ |
|
467 Private method to fix the indentation of continuation lines not |
|
468 distinguishable from next logical line (E125). |
|
469 |
|
470 @param code code of the issue (string) |
|
471 @param line line number of the issue (integer) |
|
472 @param pos position inside line (integer) |
|
473 @keyparam apply flag indicating, that the fix should be applied |
|
474 (boolean) |
|
475 @return flag indicating an applied fix (boolean) and a message for |
|
476 the fix (string) |
|
477 """ |
|
478 if apply: |
|
479 logical = self.__getLogical(line, pos) |
|
480 if logical: |
|
481 # Fix by adjusting initial indent level. |
|
482 modified = self.__fixReindent(line, pos, logical) |
|
483 if not modified: |
|
484 row = line - 1 |
|
485 text = self.__source[row] |
|
486 self.__source[row] = self.__getIndent(text) + \ |
|
487 self.__indentWord + text.lstrip() |
|
488 else: |
|
489 self.__stackLogical.append((code, line, pos)) |
|
490 return (True, self.trUtf8("Indentation level changed.")) |
|
491 |
|
492 def __fixE126(self, code, line, pos, apply=False): |
|
493 """ |
|
494 Private method to fix over-indented/under-indented hanging |
|
495 indentation (E126, E133). |
|
496 |
|
497 @param code code of the issue (string) |
|
498 @param line line number of the issue (integer) |
|
499 @param pos position inside line (integer) |
|
500 @keyparam apply flag indicating, that the fix should be applied |
|
501 (boolean) |
|
502 @return flag indicating an applied fix (boolean) and a message for |
|
503 the fix (string) |
|
504 """ |
|
505 if apply: |
|
506 logical = self.__getLogical(line, pos) |
|
507 if logical: |
|
508 # Fix by deleting whitespace to the left. |
|
509 logicalLines = logical[2] |
|
510 row = line - 1 |
|
511 text = self.__source[row] |
|
512 newText = self.__getIndent(logicalLines[0]) + \ |
|
513 self.__indentWord + text.lstrip() |
|
514 if newText == text: |
|
515 # fall back to slower method |
|
516 self.__fixReindent(line, pos, logical) |
|
517 else: |
|
518 self.__source[row] = newText |
|
519 else: |
|
520 self.__stackLogical.append((code, line, pos)) |
|
521 return (True, self.trUtf8("Indentation level of hanging indentation changed.")) |
|
522 |
|
523 def __fixE127(self, code, line, pos, apply=False): |
|
524 """ |
|
525 Private method to fix over/under indented lines (E127, E128). |
|
526 |
|
527 @param code code of the issue (string) |
|
528 @param line line number of the issue (integer) |
|
529 @param pos position inside line (integer) |
|
530 @keyparam apply flag indicating, that the fix should be applied |
|
531 (boolean) |
|
532 @return flag indicating an applied fix (boolean) and a message for |
|
533 the fix (string) |
|
534 """ |
|
535 if apply: |
|
536 logical = self.__getLogical(line, pos) |
|
537 if logical: |
|
538 # Fix by inserting/deleting whitespace to the correct level. |
|
539 logicalLines = logical[2] |
|
540 row = line - 1 |
|
541 text = self.__source[row] |
|
542 newText = text |
|
543 |
|
544 if logicalLines[0].rstrip().endswith('\\'): |
|
545 newText = self.__getIndent(logicalLines[0]) + \ |
|
546 self.__indentWord + text.lstrip() |
|
547 else: |
|
548 startIndex = None |
|
549 for symbol in '([{': |
|
550 if symbol in logicalLines[0]: |
|
551 foundIndex = logicalLines[0].find(symbol) + 1 |
|
552 if startIndex is None: |
|
553 startIndex = foundIndex |
|
554 else: |
|
555 startIndex = min(startIndex, foundIndex) |
|
556 |
|
557 if startIndex is not None: |
|
558 newText = startIndex * ' ' + text.lstrip() |
|
559 |
|
560 if newText == text: |
|
561 # fall back to slower method |
|
562 self.__fixReindent(line, pos, logical) |
|
563 else: |
|
564 self.__source[row] = newText |
|
565 else: |
|
566 self.__stackLogical.append((code, line, pos)) |
|
567 return (True, self.trUtf8("Visual indentation corrected.")) |
|
568 |
257 def __fixE201(self, code, line, pos): |
569 def __fixE201(self, code, line, pos): |
258 """ |
570 """ |
259 Private method to fix extraneous whitespace (E201, E202, |
571 Private method to fix extraneous whitespace (E201, E202, |
260 E203, E211). |
572 E203, E211). |
261 |
573 |
866 i = 0 |
1186 i = 0 |
867 n = len(line) |
1187 n = len(line) |
868 while i < n and line[i] == " ": |
1188 while i < n and line[i] == " ": |
869 i += 1 |
1189 i += 1 |
870 return i |
1190 return i |
|
1191 |
|
1192 |
|
1193 class Pep8IndentationWrapper(object): |
|
1194 """ |
|
1195 Class used by fixers dealing with indentation. |
|
1196 |
|
1197 Each instance operates on a single logical line. |
|
1198 """ |
|
1199 |
|
1200 SKIP_TOKENS = frozenset([ |
|
1201 tokenize.COMMENT, tokenize.NL, tokenize.INDENT, |
|
1202 tokenize.DEDENT, tokenize.NEWLINE, tokenize.ENDMARKER |
|
1203 ]) |
|
1204 |
|
1205 def __init__(self, physical_lines): |
|
1206 """ |
|
1207 Constructor |
|
1208 |
|
1209 @param physical_lines list of physical lines to operate on |
|
1210 (list of strings) |
|
1211 """ |
|
1212 self.lines = physical_lines |
|
1213 self.tokens = [] |
|
1214 self.rel_indent = None |
|
1215 sio = io.StringIO(''.join(physical_lines)) |
|
1216 for t in tokenize.generate_tokens(sio.readline): |
|
1217 if not len(self.tokens) and t[0] in self.SKIP_TOKENS: |
|
1218 continue |
|
1219 if t[0] != tokenize.ENDMARKER: |
|
1220 self.tokens.append(t) |
|
1221 |
|
1222 self.logical_line = self.__buildTokensLogical(self.tokens) |
|
1223 |
|
1224 def __buildTokensLogical(self, tokens): |
|
1225 """ |
|
1226 Private method to build a logical line from a list of tokens. |
|
1227 |
|
1228 @param tokens list of tokens as generated by tokenize.generate_tokens |
|
1229 @return logical line (string) |
|
1230 """ |
|
1231 # from pep8.py with minor modifications |
|
1232 logical = [] |
|
1233 previous = None |
|
1234 for t in tokens: |
|
1235 token_type, text = t[0:2] |
|
1236 if token_type in self.SKIP_TOKENS: |
|
1237 continue |
|
1238 if previous: |
|
1239 end_line, end = previous[3] |
|
1240 start_line, start = t[2] |
|
1241 if end_line != start_line: # different row |
|
1242 prev_text = self.lines[end_line - 1][end - 1] |
|
1243 if prev_text == ',' or (prev_text not in '{[(' |
|
1244 and text not in '}])'): |
|
1245 logical.append(' ') |
|
1246 elif end != start: # different column |
|
1247 fill = self.lines[end_line - 1][end:start] |
|
1248 logical.append(fill) |
|
1249 logical.append(text) |
|
1250 previous = t |
|
1251 logical_line = ''.join(logical) |
|
1252 assert logical_line.lstrip() == logical_line |
|
1253 assert logical_line.rstrip() == logical_line |
|
1254 return logical_line |
|
1255 |
|
1256 def pep8Expected(self): |
|
1257 """ |
|
1258 Public method to replicate logic in pep8.py, to know what level to |
|
1259 indent things to. |
|
1260 |
|
1261 @return list of lists, where each list represents valid indent levels for |
|
1262 the line in question, relative from the initial indent. However, the |
|
1263 first entry is the indent level which was expected. |
|
1264 """ |
|
1265 # What follows is an adjusted version of |
|
1266 # pep8.py:continuation_line_indentation. All of the comments have been |
|
1267 # stripped and the 'yield' statements replaced with 'pass'. |
|
1268 if not self.tokens: |
|
1269 return |
|
1270 |
|
1271 first_row = self.tokens[0][2][0] |
|
1272 nrows = 1 + self.tokens[-1][2][0] - first_row |
|
1273 |
|
1274 # here are the return values |
|
1275 valid_indents = [list()] * nrows |
|
1276 indent_level = self.tokens[0][2][1] |
|
1277 valid_indents[0].append(indent_level) |
|
1278 |
|
1279 if nrows == 1: |
|
1280 # bug, really. |
|
1281 return valid_indents |
|
1282 |
|
1283 indent_next = self.logical_line.endswith(':') |
|
1284 |
|
1285 row = depth = 0 |
|
1286 parens = [0] * nrows |
|
1287 self.rel_indent = rel_indent = [0] * nrows |
|
1288 indent = [indent_level] |
|
1289 indent_chances = {} |
|
1290 last_indent = (0, 0) |
|
1291 last_token_multiline = None |
|
1292 |
|
1293 for token_type, text, start, end, line in self.tokens: |
|
1294 newline = row < start[0] - first_row |
|
1295 if newline: |
|
1296 row = start[0] - first_row |
|
1297 newline = (not last_token_multiline and |
|
1298 token_type not in (tokenize.NL, tokenize.NEWLINE)) |
|
1299 |
|
1300 if newline: |
|
1301 # This is where the differences start. Instead of looking at |
|
1302 # the line and determining whether the observed indent matches |
|
1303 # our expectations, we decide which type of indentation is in |
|
1304 # use at the given indent level, and return the offset. This |
|
1305 # algorithm is susceptible to "carried errors", but should |
|
1306 # through repeated runs eventually solve indentation for |
|
1307 # multiline expressions. |
|
1308 |
|
1309 if depth: |
|
1310 for open_row in range(row - 1, -1, -1): |
|
1311 if parens[open_row]: |
|
1312 break |
|
1313 else: |
|
1314 open_row = 0 |
|
1315 |
|
1316 # That's all we get to work with. This code attempts to |
|
1317 # "reverse" the below logic, and place into the valid indents |
|
1318 # list |
|
1319 vi = [] |
|
1320 add_second_chances = False |
|
1321 if token_type == tokenize.OP and text in ']})': |
|
1322 # this line starts with a closing bracket, so it needs to |
|
1323 # be closed at the same indent as the opening one. |
|
1324 if indent[depth]: |
|
1325 # hanging indent |
|
1326 vi.append(indent[depth]) |
|
1327 else: |
|
1328 # visual indent |
|
1329 vi.append(indent_level + rel_indent[open_row]) |
|
1330 elif depth and indent[depth]: |
|
1331 # visual indent was previously confirmed. |
|
1332 vi.append(indent[depth]) |
|
1333 add_second_chances = True |
|
1334 elif depth and True in indent_chances.values(): |
|
1335 # visual indent happened before, so stick to |
|
1336 # visual indent this time. |
|
1337 if depth > 1 and indent[depth - 1]: |
|
1338 vi.append(indent[depth - 1]) |
|
1339 else: |
|
1340 # stupid fallback |
|
1341 vi.append(indent_level + 4) |
|
1342 add_second_chances = True |
|
1343 elif not depth: |
|
1344 vi.append(indent_level + 4) |
|
1345 else: |
|
1346 # must be in hanging indent |
|
1347 hang = rel_indent[open_row] + 4 |
|
1348 vi.append(indent_level + hang) |
|
1349 |
|
1350 # about the best we can do without look-ahead |
|
1351 if (indent_next and vi[0] == indent_level + 4 and |
|
1352 nrows == row + 1): |
|
1353 vi[0] += 4 |
|
1354 |
|
1355 if add_second_chances: |
|
1356 # visual indenters like to line things up. |
|
1357 min_indent = vi[0] |
|
1358 for col, what in indent_chances.items(): |
|
1359 if col > min_indent and ( |
|
1360 what is True or |
|
1361 (what == str and token_type == tokenize.STRING) or |
|
1362 (what == text and token_type == tokenize.OP) |
|
1363 ): |
|
1364 vi.append(col) |
|
1365 vi = sorted(vi) |
|
1366 |
|
1367 valid_indents[row] = vi |
|
1368 |
|
1369 # Returning to original continuation_line_indentation() from |
|
1370 # pep8. |
|
1371 visual_indent = indent_chances.get(start[1]) |
|
1372 last_indent = start |
|
1373 rel_indent[row] = pep8.expand_indent(line) - indent_level |
|
1374 hang = rel_indent[row] - rel_indent[open_row] |
|
1375 |
|
1376 if token_type == tokenize.OP and text in ']})': |
|
1377 pass |
|
1378 elif visual_indent is True: |
|
1379 if not indent[depth]: |
|
1380 indent[depth] = start[1] |
|
1381 |
|
1382 # line altered: comments shouldn't define a visual indent |
|
1383 if parens[row] and not indent[depth] and token_type not in ( |
|
1384 tokenize.NL, tokenize.COMMENT |
|
1385 ): |
|
1386 indent[depth] = start[1] |
|
1387 indent_chances[start[1]] = True |
|
1388 elif token_type == tokenize.STRING or text in ( |
|
1389 'u', 'ur', 'b', 'br' |
|
1390 ): |
|
1391 indent_chances[start[1]] = str |
|
1392 |
|
1393 if token_type == tokenize.OP: |
|
1394 if text in '([{': |
|
1395 depth += 1 |
|
1396 indent.append(0) |
|
1397 parens[row] += 1 |
|
1398 elif text in ')]}' and depth > 0: |
|
1399 prev_indent = indent.pop() or last_indent[1] |
|
1400 for d in range(depth): |
|
1401 if indent[d] > prev_indent: |
|
1402 indent[d] = 0 |
|
1403 for ind in list(indent_chances): |
|
1404 if ind >= prev_indent: |
|
1405 del indent_chances[ind] |
|
1406 depth -= 1 |
|
1407 if depth and indent[depth]: # modified |
|
1408 indent_chances[indent[depth]] = True |
|
1409 for idx in range(row, -1, -1): |
|
1410 if parens[idx]: |
|
1411 parens[idx] -= 1 |
|
1412 break |
|
1413 assert len(indent) == depth + 1 |
|
1414 if start[1] not in indent_chances: |
|
1415 indent_chances[start[1]] = text |
|
1416 |
|
1417 last_token_multiline = (start[0] != end[0]) |
|
1418 |
|
1419 return valid_indents |