예제 #1
0
 def postcmd(self, stop, line):
     """Called just before execution of line. For readline, this handles the
     automatic indentation of code blocks.
     """
     try:
         import readline
     except ImportError:
         return stop
     if self.need_more_lines:
         if len(line.strip()) == 0:
             readline.set_pre_input_hook(None)
             self._current_indent = ""
         elif ends_with_colon_token(line):
             ind = line[:len(line) - len(line.lstrip())]
             ind += XSH.env.get("INDENT")
             readline.set_pre_input_hook(_insert_text_func(ind, readline))
             self._current_indent = ind
         elif line.split(maxsplit=1)[0] in DEDENT_TOKENS:
             env = XSH.env
             ind = self._current_indent[:-len(env.get("INDENT"))]
             readline.set_pre_input_hook(_insert_text_func(ind, readline))
             self._current_indent = ind
         else:
             ind = line[:len(line) - len(line.lstrip())]
             if ind != self._current_indent:
                 insert_func = _insert_text_func(ind, readline)
                 readline.set_pre_input_hook(insert_func)
                 self._current_indent = ind
     else:
         readline.set_pre_input_hook(None)
     return stop
예제 #2
0
def carriage_return(b, cli, *, autoindent=True):
    """Preliminary parser to determine if 'Enter' key should send command to the
    xonsh parser for execution or should insert a newline for continued input.

    Current 'triggers' for inserting a newline are:
    - Not on first line of buffer and line is non-empty
    - Previous character is a colon (covers if, for, etc...)
    - User is in an open paren-block
    - Line ends with backslash
    - Any text exists below cursor position (relevant when editing previous
    multiline blocks)
    """
    doc = b.document
    at_end_of_line = _is_blank(doc.current_line_after_cursor)
    current_line_blank = _is_blank(doc.current_line)

    env = XSH.env
    indent = env.get("INDENT") if autoindent else ""

    partial_string_info = check_for_partial_string(doc.text)
    in_partial_string = (
        partial_string_info[0] is not None and partial_string_info[1] is None
    )

    # indent after a colon
    if ends_with_colon_token(doc.current_line_before_cursor) and at_end_of_line:
        b.newline(copy_margin=autoindent)
        b.insert_text(indent, fire_event=False)
    # if current line isn't blank, check dedent tokens
    elif (
        not current_line_blank
        and doc.current_line.split(maxsplit=1)[0] in DEDENT_TOKENS
        and doc.line_count > 1
    ):
        b.newline(copy_margin=autoindent)
        b.delete_before_cursor(count=len(indent))
    elif not doc.on_first_line and not current_line_blank:
        b.newline(copy_margin=autoindent)
    elif doc.current_line.endswith(get_line_continuation()):
        b.newline(copy_margin=autoindent)
    elif doc.find_next_word_beginning() is not None and (
        any(not _is_blank(i) for i in doc.lines_from_current[1:])
    ):
        b.newline(copy_margin=autoindent)
    elif not current_line_blank and not can_compile(doc.text):
        b.newline(copy_margin=autoindent)
    elif current_line_blank and in_partial_string:
        b.newline(copy_margin=autoindent)
    else:
        b.validate_and_handle()
예제 #3
0
파일: execer.py 프로젝트: seanfarley/xonsh
    def _parse_ctx_free(self,
                        input,
                        mode="exec",
                        filename=None,
                        logical_input=False):
        last_error_line = last_error_col = -1
        parsed = False
        original_error = None
        greedy = False
        if filename is None:
            filename = self.filename
        if logical_input:
            beg_spaces = starting_whitespace(input)
            input = input[len(beg_spaces):]
        while not parsed:
            try:
                tree = self.parser.parse(
                    input,
                    filename=filename,
                    mode=mode,
                    debug_level=(self.debug_level >= 2),
                )
                parsed = True
            except IndentationError as e:
                if original_error is None:
                    raise e
                else:
                    raise original_error
            except SyntaxError as e:
                if original_error is None:
                    original_error = e
                if (e.loc is None) or (last_error_line == e.loc.lineno
                                       and last_error_col
                                       in (e.loc.column + 1, e.loc.column)):
                    raise original_error from None
                elif last_error_line != e.loc.lineno:
                    original_error = e
                last_error_col = e.loc.column
                last_error_line = e.loc.lineno
                idx = last_error_line - 1
                lines = input.splitlines()
                if input.endswith("\n"):
                    lines.append("")
                line, nlogical, idx = get_logical_line(lines, idx)
                if nlogical > 1 and not logical_input:
                    _, sbpline = self._parse_ctx_free(line,
                                                      mode=mode,
                                                      filename=filename,
                                                      logical_input=True)
                    self._print_debug_wrapping(line,
                                               sbpline,
                                               last_error_line,
                                               last_error_col,
                                               maxcol=None)
                    replace_logical_line(lines, sbpline, idx, nlogical)
                    last_error_col += 3
                    input = "\n".join(lines)
                    continue
                if len(line.strip()) == 0:
                    # whitespace only lines are not valid syntax in Python's
                    # interactive mode='single', who knew?! Just ignore them.
                    # this might cause actual syntax errors to have bad line
                    # numbers reported, but should only affect interactive mode
                    del lines[idx]
                    last_error_line = last_error_col = -1
                    input = "\n".join(lines)
                    continue

                if last_error_line > 1 and ends_with_colon_token(
                        lines[idx - 1]):
                    # catch non-indented blocks and raise error.
                    prev_indent = len(lines[idx - 1]) - len(
                        lines[idx - 1].lstrip())
                    curr_indent = len(lines[idx]) - len(lines[idx].lstrip())
                    if prev_indent == curr_indent:
                        raise original_error
                lexer = self.parser.lexer
                maxcol = (None if greedy else find_next_break(
                    line, mincol=last_error_col, lexer=lexer))
                if not greedy and maxcol in (e.loc.column + 1, e.loc.column):
                    # go greedy the first time if the syntax error was because
                    # we hit an end token out of place. This usually indicates
                    # a subshell or maybe a macro.
                    if not balanced_parens(line, maxcol=maxcol):
                        greedy = True
                        maxcol = None
                sbpline = subproc_toks(line,
                                       returnline=True,
                                       greedy=greedy,
                                       maxcol=maxcol,
                                       lexer=lexer)
                if sbpline is None:
                    # subprocess line had no valid tokens,
                    if len(line.partition("#")[0].strip()) == 0:
                        # likely because it only contained a comment.
                        del lines[idx]
                        last_error_line = last_error_col = -1
                        input = "\n".join(lines)
                        continue
                    elif not greedy:
                        greedy = True
                        continue
                    else:
                        # or for some other syntax error
                        raise original_error
                elif sbpline[last_error_col:].startswith(
                        "![![") or sbpline.lstrip().startswith("![!["):
                    # if we have already wrapped this in subproc tokens
                    # and it still doesn't work, adding more won't help
                    # anything
                    if not greedy:
                        greedy = True
                        continue
                    else:
                        raise original_error
                # replace the line
                self._print_debug_wrapping(line,
                                           sbpline,
                                           last_error_line,
                                           last_error_col,
                                           maxcol=maxcol)
                replace_logical_line(lines, sbpline, idx, nlogical)
                last_error_col += 3
                input = "\n".join(lines)
        if logical_input:
            input = beg_spaces + input
        return tree, input
예제 #4
0
def test_ends_with_colon_token(line, exp):
    obs = ends_with_colon_token(line, lexer=LEXER)
    if exp:
        assert obs
    else:
        assert not obs