Show More
@@ -470,9 +470,12 b' def make_tokens_by_line(lines):' | |||||
470 | except tokenize.TokenError: |
|
470 | except tokenize.TokenError: | |
471 | # Input ended in a multiline string or expression. That's OK for us. |
|
471 | # Input ended in a multiline string or expression. That's OK for us. | |
472 | pass |
|
472 | pass | |
|
473 | ||||
|
474 | ||||
473 | if not tokens_by_line[-1]: |
|
475 | if not tokens_by_line[-1]: | |
474 | tokens_by_line.pop() |
|
476 | tokens_by_line.pop() | |
475 |
|
477 | |||
|
478 | ||||
476 | return tokens_by_line |
|
479 | return tokens_by_line | |
477 |
|
480 | |||
478 | def show_linewise_tokens(s: str): |
|
481 | def show_linewise_tokens(s: str): | |
@@ -579,7 +582,24 b' class TransformerManager:' | |||||
579 | The number of spaces by which to indent the next line of code. If |
|
582 | The number of spaces by which to indent the next line of code. If | |
580 | status is not 'incomplete', this is None. |
|
583 | status is not 'incomplete', this is None. | |
581 | """ |
|
584 | """ | |
|
585 | # Remember if the lines ends in a new line. | |||
|
586 | ends_with_newline = False | |||
|
587 | for character in reversed(cell): | |||
|
588 | if character == '\n': | |||
|
589 | ends_with_newline = True | |||
|
590 | break | |||
|
591 | elif character.strip(): | |||
|
592 | break | |||
|
593 | else: | |||
|
594 | continue | |||
|
595 | ||||
|
596 | if ends_with_newline: | |||
|
597 | # Append an newline for consistent tokenization | |||
|
598 | # See https://bugs.python.org/issue33899 | |||
|
599 | cell += '\n' | |||
|
600 | ||||
582 | lines = cell.splitlines(keepends=True) |
|
601 | lines = cell.splitlines(keepends=True) | |
|
602 | ||||
583 | if not lines: |
|
603 | if not lines: | |
584 | return 'complete', None |
|
604 | return 'complete', None | |
585 |
|
605 | |||
@@ -608,6 +628,7 b' class TransformerManager:' | |||||
608 | return 'invalid', None |
|
628 | return 'invalid', None | |
609 |
|
629 | |||
610 | tokens_by_line = make_tokens_by_line(lines) |
|
630 | tokens_by_line = make_tokens_by_line(lines) | |
|
631 | ||||
611 | if not tokens_by_line: |
|
632 | if not tokens_by_line: | |
612 | return 'incomplete', find_last_indent(lines) |
|
633 | return 'incomplete', find_last_indent(lines) | |
613 |
|
634 | |||
@@ -615,30 +636,33 b' class TransformerManager:' | |||||
615 | # We're in a multiline string or expression |
|
636 | # We're in a multiline string or expression | |
616 | return 'incomplete', find_last_indent(lines) |
|
637 | return 'incomplete', find_last_indent(lines) | |
617 |
|
638 | |||
618 | if len(tokens_by_line[-1]) == 1: |
|
639 | newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} | |
619 | return 'incomplete', find_last_indent(lines) |
|
640 | ||
620 | # Find the last token on the previous line that's not NEWLINE or COMMENT |
|
641 | # Remove newline_types for the list of tokens | |
621 |
|
|
642 | while len(tokens_by_line) > 1 and len(tokens_by_line[-1]) == 1 \ | |
622 | ix = len(tokens_by_line) - 1 |
|
643 | and tokens_by_line[-1][-1].type in newline_types: | |
|
644 | tokens_by_line.pop() | |||
623 |
|
645 | |||
|
646 | last_line_token = tokens_by_line[-1] | |||
624 |
|
647 | |||
625 |
while |
|
648 | while tokens_by_line[-1][-1].type in newline_types: | |
626 | tokenize.COMMENT}: |
|
649 | last_line_token = tokens_by_line[-1].pop() | |
627 | ix -= 1 |
|
650 | ||
628 | if tokens_by_line[ix][-2].string == ':': |
|
651 | if len(last_line_token) == 1 and not last_line_token[-1]: | |
|
652 | return 'incomplete', 0 | |||
|
653 | ||||
|
654 | if last_line_token[-1].string == ':': | |||
629 | # The last line starts a block (e.g. 'if foo:') |
|
655 | # The last line starts a block (e.g. 'if foo:') | |
630 | ix = 0 |
|
656 | ix = 0 | |
631 | while toks_last_line[ix].type in {tokenize.INDENT, tokenize.DEDENT}: |
|
657 | while last_line_token[ix].type \ | |
|
658 | in {tokenize.INDENT, tokenize.DEDENT}: | |||
632 | ix += 1 |
|
659 | ix += 1 | |
633 | indent = toks_last_line[ix].start[1] |
|
660 | ||
|
661 | indent = last_line_token[ix].start[1] | |||
634 | return 'incomplete', indent + 4 |
|
662 | return 'incomplete', indent + 4 | |
635 | if tokens_by_line[ix][-2].string == '\\': |
|
|||
636 | if not tokens_by_line[ix][-2].line.endswith('\\'): |
|
|||
637 | return 'invalid', None |
|
|||
638 |
|
663 | |||
639 | # If there's a blank line at the end, assume we're ready to execute |
|
664 | if last_line_token[-1].line.endswith('\\'): | |
640 | if not lines[-1].strip(): |
|
665 | return 'incomplete', None | |
641 | return 'complete', None |
|
|||
642 |
|
666 | |||
643 | # At this point, our checks think the code is complete (or invalid). |
|
667 | # At this point, our checks think the code is complete (or invalid). | |
644 | # We'll use codeop.compile_command to check this with the real parser |
|
668 | # We'll use codeop.compile_command to check this with the real parser | |
@@ -653,12 +677,13 b' class TransformerManager:' | |||||
653 | if res is None: |
|
677 | if res is None: | |
654 | return 'incomplete', find_last_indent(lines) |
|
678 | return 'incomplete', find_last_indent(lines) | |
655 |
|
679 | |||
656 |
if |
|
680 | if last_line_token[-1].type == tokenize.DEDENT: | |
657 | return 'complete', None |
|
681 | if ends_with_newline: | |
|
682 | return 'complete', None | |||
|
683 | return 'incomplete', find_last_indent(lines) | |||
658 |
|
684 | |||
659 | if toks_last_line[-2].type == tokenize.DEDENT: |
|
685 | if len(last_line_token) <= 1: | |
660 | if not lines[-1].endswith('\n'): |
|
686 | return 'incomplete', find_last_indent(lines) | |
661 | return 'incomplete', find_last_indent(lines) |
|
|||
662 |
|
687 | |||
663 | return 'complete', None |
|
688 | return 'complete', None | |
664 |
|
689 |
General Comments 0
You need to be logged in to leave comments.
Login now