예제 #1
0
    def _apply_change(self, change):
        """
        Apply changeset to current snippets stack, correctly moving around
        snippet itself or its child.
        """
        if not self._snippets_stack:
            return

        change_type, line_number, column_number, change_text = change[0:4]

        line_before = line_number <= self._snippets_stack[0]._start.line
        column_before = column_number <= self._snippets_stack[0]._start.col
        if line_before and column_before:
            direction = 1
            if change_type == "D":
                direction = -1

            diff = Position(direction, 0)
            if len(change) != 5:
                diff = Position(0, direction * len(change_text))
            print(change, diff)

            self._snippets_stack[0]._move(Position(line_number, column_number),
                                          diff)
        else:
            if line_number > self._snippets_stack[0]._end.line:
                return
            if column_number >= self._snippets_stack[0]._end.col:
                return
            self._snippets_stack[0]._do_edit(change[0:4])
예제 #2
0
    def __init__(
        self,
        snippet,
        parent,
        initial_text,
        start,
        end,
        visual_content,
        last_re,
        globals,
        context,
    ):
        if start is None:
            start = Position(0, 0)
        if end is None:
            end = Position(0, 0)
        self.snippet = snippet
        self._cts = 0

        self.context = context
        self.locals = {"match": last_re, "context": context}
        self.globals = globals
        self.visual_content = visual_content
        self.current_placeholder = None

        EditableTextObject.__init__(self, parent, start, end, initial_text)
예제 #3
0
    def _apply_change(self, change):
        """
        Apply changeset to current snippets stack, correctly moving around
        snippet itself or its child.
        """
        if not self._snippets_stack:
            return

        line_number = change[1]
        column_number = change[2]
        line_before = line_number <= self._snippets_stack[0]._start.line
        column_before = column_number <= self._snippets_stack[0]._start.col
        if line_before and column_before:
            direction = 1
            if change[0] == 'D':
                direction = -1

            self._snippets_stack[0]._move(
                Position(line_number, 0),
                Position(direction, 0)
            )
        else:
            if line_number > self._snippets_stack[0]._end.line:
                return
            if column_number >= self._snippets_stack[0]._end.col:
                return
            self._snippets_stack[0]._do_edit(change)
예제 #4
0
 def _jump(self, backwards=False):
     """Helper method that does the actual jump."""
     jumped = False
     # If next tab has length 1 and the distance between itself and
     # self._ctab is 1 then there is 1 less CursorMove events.  We
     # cannot ignore next movement in such case.
     ntab_short_and_near = False
     if self._cs:
         ntab = self._cs.select_next_tab(backwards)
         if ntab:
             if self._cs.snippet.has_option("s"):
                 lineno = _vim.buf.cursor.line
                 _vim.buf[lineno] = _vim.buf[lineno].rstrip()
             _vim.select(ntab.start, ntab.end)
             jumped = True
             if (self._ctab is not None
                     and ntab.start - self._ctab.end == Position(0, 1)
                     and ntab.end - ntab.start == Position(0, 1)):
                 ntab_short_and_near = True
             if ntab.number == 0:
                 self._current_snippet_is_done()
         else:
             # This really shouldn't happen, because a snippet should
             # have been popped when its final tabstop was used.
             # Cleanup by removing current snippet and recursing.
             self._current_snippet_is_done()
             jumped = self._jump(backwards)
         self._ctab = ntab
     if jumped:
         self._vstate.remember_position()
         self._vstate.remember_unnamed_register(self._ctab.current_text)
         if not ntab_short_and_near:
             self._ignore_movements = True
     return jumped
예제 #5
0
def _calc_end(text, start):
    """Calculate the end position of the 'text' starting at 'start."""
    if len(text) == 1:
        new_end = start + Position(0, len(text[0]))
    else:
        new_end = Position(start.line + len(text) - 1, len(text[-1]))
    return new_end
예제 #6
0
    def select_next_tab(self, backwards=False):
        """Selects the next tabstop or the previous if 'backwards' is True."""
        if self._cts is None:
            return

        if backwards:
            cts_bf = self._cts

            res = self._get_prev_tab(self._cts)
            if res is None:
                self._cts = cts_bf
                return self._tabstops.get(self._cts, None)
            self._cts, ts = res
            return ts
        else:
            res = self._get_next_tab(self._cts)
            if res is None:
                self._cts = None

                ts = self._get_tabstop(self, 0)
                if ts:
                    return ts

                # TabStop 0 was deleted. It was probably killed through some
                # edit action. Recreate it at the end of us.
                start = Position(self.end.line, self.end.col)
                end = Position(self.end.line, self.end.col)
                return TabStop(self, 0, start, end)
            else:
                self._cts, ts = res
                return ts

        return self._tabstops[self._cts]
예제 #7
0
    def select_next_tab(self, jump_direction: JumpDirection):
        """Selects the next tabstop in the direction of 'jump_direction'."""
        if self._cts is None:
            return

        if jump_direction == JumpDirection.BACKWARD:
            current_tabstop_backup = self._cts

            res = self._get_prev_tab(self._cts)
            if res is None:
                self._cts = current_tabstop_backup
                return self._tabstops.get(self._cts, None)
            self._cts, ts = res
            return ts
        elif jump_direction == JumpDirection.FORWARD:
            res = self._get_next_tab(self._cts)
            if res is None:
                self._cts = None

                ts = self._get_tabstop(self, 0)
                if ts:
                    return ts

                # TabStop 0 was deleted. It was probably killed through some
                # edit action. Recreate it at the end of us.
                start = Position(self.end.line, self.end.col)
                end = Position(self.end.line, self.end.col)
                return TabStop(self, 0, start, end)
            else:
                self._cts, ts = res
                return ts
        else:
            assert False, "Unknown JumpDirection: %r" % jump_direction
예제 #8
0
    def _get_next_tab(self, number):
        """Returns the next tabstop after 'number'."""
        if not len(self._tabstops.keys()):
            return

        tno_max = max(self._tabstops.keys())
        possible_sol = []

        i = number + 1
        while i <= tno_max:
            # FIXME: fix Position(0, 1)
            if i in self._tabstops and self._tabstops[i]._start + Position(
                    0, 1) >= vim_helper.buf.cursor:
                possible_sol.append((i, self._tabstops[i]))
                break
            i += 1

        child = [c._get_next_tab(number) for c in self._editable_children]
        child = [c for c in child if c]

        possible_sol += child

        if not len(possible_sol):
            if self._tabstops[0]._start + Position(0,
                                                   1) >= vim_helper.buf.cursor:
                return (0, self._tabstops[0])
            return None

        return min(possible_sol)
예제 #9
0
    def _jump(self, backwards=False):
        # we need to set 'onemore' there, because of limitations of the vim
        # API regarding cursor movements; without that test
        # 'CanExpandAnonSnippetInJumpActionWhileSelected' will fail
        with _vim.toggle_opt('ve', 'onemore'):
            """Helper method that does the actual jump."""
            jumped = False

            # We need to remember current snippets stack here because of
            # post-jump action on the last tabstop should be able to access
            # snippet instance which is ended just now.
            stack_for_post_jump = self._csnippets[:]

            # If next tab has length 1 and the distance between itself and
            # self._ctab is 1 then there is 1 less CursorMove events.  We
            # cannot ignore next movement in such case.
            ntab_short_and_near = False

            if self._cs:
                snippet_for_action = self._cs
            elif stack_for_post_jump:
                snippet_for_action = stack_for_post_jump[-1]
            else:
                snippet_for_action = None

            if self._cs:
                ntab = self._cs.select_next_tab(backwards)
                if ntab:
                    if self._cs.snippet.has_option('s'):
                        lineno = _vim.buf.cursor.line
                        _vim.buf[lineno] = _vim.buf[lineno].rstrip()
                    _vim.select(ntab.start, ntab.end)
                    jumped = True
                    if (self._ctab is not None
                            and ntab.start - self._ctab.end == Position(0, 1)
                            and ntab.end - ntab.start == Position(0, 1)):
                        ntab_short_and_near = True
                    if ntab.number == 0:
                        self._current_snippet_is_done()
                    self._ctab = ntab
                else:
                    # This really shouldn't happen, because a snippet should
                    # have been popped when its final tabstop was used.
                    # Cleanup by removing current snippet and recursing.
                    self._current_snippet_is_done()
                    jumped = self._jump(backwards)
            if jumped:
                self._vstate.remember_position()
                self._vstate.remember_unnamed_register(self._ctab.current_text)
                if not ntab_short_and_near:
                    self._ignore_movements = True

            if len(stack_for_post_jump) > 0 and ntab is not None:
                with use_proxy_buffer(stack_for_post_jump, self._vstate):
                    snippet_for_action.snippet.do_post_jump(
                        ntab.number, -1 if backwards else 1,
                        stack_for_post_jump, snippet_for_action)

        return jumped
예제 #10
0
    def __init__(self, snippet, parent, initial_text, start, end,
                 visual_content, last_re, globals, context):
        if start is None:
            start = Position(0, 0)
        if end is None:
            end = Position(0, 0)
        self.snippet = snippet
        self._cts = 0

        self.locals = {'match': last_re, 'context': context}
        self.globals = globals
        self.visual_content = visual_content

        EditableTextObject.__init__(self, parent, start, end, initial_text)
예제 #11
0
    def __init__(self, expand_trigger, forward_trigger, backward_trigger):
        self.expand_trigger = expand_trigger
        self.forward_trigger = forward_trigger
        self.backward_trigger = backward_trigger
        self._inner_state_up = False
        self._supertab_keys = None

        self._active_snippets = []
        self._added_buffer_filetypes = defaultdict(lambda: [])

        self._vstate = VimState()
        self._visual_content = VisualContentPreserver()

        self._snippet_sources = []

        self._snip_expanded_in_action = False
        self._inside_action = False

        self._last_change = ("", Position(-1, -1))

        self._added_snippets_source = AddedSnippetsSource()
        self.register_snippet_source("ultisnips_files", UltiSnipsFileSource())
        self.register_snippet_source("added", self._added_snippets_source)

        enable_snipmate = "1"
        if vim_helper.eval("exists('g:UltiSnipsEnableSnipMate')") == "1":
            enable_snipmate = vim_helper.eval("g:UltiSnipsEnableSnipMate")
        if enable_snipmate == "1":
            self.register_snippet_source("snipmate_files",
                                         SnipMateFileSource())

        self._should_update_textobjects = False
        self._should_reset_visual = False

        self._reinit()
예제 #12
0
def finalize(all_tokens, seen_ts, snippet_instance):
    """Adds a tabstop 0 if non is in 'seen_ts' and brings the text of the
    snippet instance into Vim."""
    if 0 not in seen_ts:
        mark = all_tokens[-1][1].end  # Last token is always EndOfText
        m1 = Position(mark.line, mark.col)
        TabStop(snippet_instance, 0, mark, m1)
예제 #13
0
파일: lexer.py 프로젝트: Mike-ja/ultisnips
    def _parse(self, stream, indent):
        next(stream)  # $
        next(stream)  # {

        self.number = _parse_number(stream)

        if self.number == 0:
            raise RuntimeError("Choices selection is not supported on $0")

        next(stream)  # |

        choices_text = _parse_till_unescaped_char(stream, "|")[0]

        choice_list = []
        # inside choice item, comma can be escaped by "\,"
        # we need to do a little bit smarter parsing than simply splitting
        choice_stream = _TextIterator(choices_text, Position(0, 0))
        while True:
            cur_col = choice_stream.pos.col
            try:
                result = _parse_till_unescaped_char(choice_stream, ",")[0]
                if not result:
                    continue
                choice_list.append(self._get_unescaped_choice_item(result))
            except:
                last_choice_item = self._get_unescaped_choice_item(
                    choices_text[cur_col:])
                if last_choice_item:
                    choice_list.append(last_choice_item)
                break
        self.choice_list = choice_list
        self.initial_text = "|{0}|".format(",".join(choice_list))

        _parse_till_closing_brace(stream)
예제 #14
0
 def __init__(self, parent):
     NoneditableTextObject.__init__(
         self,
         parent,
         vim_helper.buf.cursor,
         vim_helper.buf.cursor,
         tiebreaker=Position(-1, -1),
     )
예제 #15
0
 def cursor(self):  # pylint:disable=no-self-use
     """
     The current windows cursor. Note that this is 0 based in col and 0
     based in line which is different from Vim's cursor.
     """
     line, nbyte = vim.current.window.cursor
     col = byte2col(line, nbyte)
     return Position(line - 1, col)
예제 #16
0
    def _do_snippet(self, snippet, before):
        """Expands the given snippet, and handles everything
        that needs to be done with it."""
        self._map_inner_keys()

        # Adjust before, maybe the trigger is not the complete word
        text_before = before
        if snippet.matched:
            text_before = before[:-len(snippet.matched)]

        if self._cs:
            start = Position(_vim.buf.cursor.line, len(text_before))
            end = Position(_vim.buf.cursor.line, len(before))

            # It could be that our trigger contains the content of TextObjects
            # in our containing snippet. If this is indeed the case, we have to
            # make sure that those are properly killed. We do this by
            # pretending that the user deleted and retyped the text that our
            # trigger matched.
            edit_actions = [
                ("D", start.line, start.col, snippet.matched),
                ("I", start.line, start.col, snippet.matched),
            ]
            self._csnippets[0].replay_user_edits(edit_actions)

            si = snippet.launch(text_before, self._visual_content,
                                self._cs.find_parent_for_new_to(start), start,
                                end)
        else:
            start = Position(_vim.buf.cursor.line, len(text_before))
            end = Position(_vim.buf.cursor.line, len(before))
            si = snippet.launch(text_before, self._visual_content, None, start,
                                end)

        self._visual_content.reset()
        self._csnippets.append(si)

        si.update_textobjects()

        self._ignore_movements = True
        self._vstate.remember_buffer(self._csnippets[0])

        self._jump()
예제 #17
0
파일: _base.py 프로젝트: erkaon23/dotfiles
    def __init__(self, parent, token, end=None,
            initial_text="", tiebreaker=None):
        self._parent = parent

        if end is not None: # Took 4 arguments
            self._start = token
            self._end = end
            self._initial_text = initial_text
        else: # Initialize from token
            self._start = token.start
            self._end = token.end
            self._initial_text = token.initial_text
        self._tiebreaker = tiebreaker or Position(
                self._start.line, self._end.line)
        if parent is not None:
            parent._add_child(self)
예제 #18
0
    def _execute_action(
        self, action, context, additional_locals={}, compiled_action=None
    ):
        mark_to_use = "`"
        with vim_helper.save_mark(mark_to_use):
            vim_helper.set_mark_from_pos(mark_to_use, vim_helper.get_cursor_pos())

            cursor_line_before = vim_helper.buf.line_till_cursor

            locals = {"context": context}

            locals.update(additional_locals)

            snip = self._eval_code(action, locals, compiled_action)

            if snip.cursor.is_set():
                vim_helper.buf.cursor = Position(
                    snip.cursor._cursor[0], snip.cursor._cursor[1]
                )
            else:
                new_mark_pos = vim_helper.get_mark_pos(mark_to_use)

                cursor_invalid = False

                if vim_helper._is_pos_zero(new_mark_pos):
                    cursor_invalid = True
                else:
                    vim_helper.set_cursor_from_pos(new_mark_pos)
                    if cursor_line_before != vim_helper.buf.line_till_cursor:
                        cursor_invalid = True

                if cursor_invalid:
                    raise PebkacError(
                        "line under the cursor was modified, but "
                        + '"snip.cursor" variable is not set; either set set '
                        + '"snip.cursor" to new cursor position, or do not '
                        + "modify cursor line"
                    )

        return snip
예제 #19
0
 def pos(self):
     """Current position in the text."""
     return Position(self._line, self._col)
예제 #20
0
def guess_edit(initial_line, last_text, current_text, vim_state):
    """Try to guess what the user might have done by heuristically looking at
    cursor movement, number of changed lines and if they got longer or shorter.
    This will detect most simple movements like insertion, deletion of a line
    or carriage return. 'initial_text' is the index of where the comparison
    starts, 'last_text' is the last text of the snippet, 'current_text' is the
    current text of the snippet and 'vim_state' is the cached vim state.

    Returns (True, edit_cmds) when the edit could be guessed, (False,
    None) otherwise.

    """
    if not len(last_text) and not len(current_text):
        return True, ()
    pos = vim_state.pos
    ppos = vim_state.ppos

    # All text deleted?
    if len(last_text) and (not current_text or
                           (len(current_text) == 1 and not current_text[0])):
        es = []
        if not current_text:
            current_text = [""]
        for i in last_text:
            es.append(("D", initial_line, 0, i))
            es.append(("D", initial_line, 0, "\n"))
        es.pop()  # Remove final \n because it is not really removed
        if is_complete_edit(initial_line, last_text, current_text, es):
            return True, es
    if ppos.mode == "v":  # Maybe selectmode?
        sv = list(map(int, vim_helper.eval("""getpos("'<")""")))
        sv = Position(sv[1] - 1, sv[2] - 1)
        ev = list(map(int, vim_helper.eval("""getpos("'>")""")))
        ev = Position(ev[1] - 1, ev[2] - 1)
        if "exclusive" in vim_helper.eval("&selection"):
            ppos.col -= 1  # We want to be inclusive, sorry.
            ev.col -= 1
        es = []
        if sv.line == ev.line:
            es.append((
                "D",
                sv.line,
                sv.col,
                last_text[sv.line - initial_line][sv.col:ev.col + 1],
            ))
            if sv != pos and sv.line == pos.line:
                es.append((
                    "I",
                    sv.line,
                    sv.col,
                    current_text[sv.line - initial_line][sv.col:pos.col + 1],
                ))
        if is_complete_edit(initial_line, last_text, current_text, es):
            return True, es
    if pos.line == ppos.line:
        if len(last_text) == len(current_text):  # Movement only in one line
            llen = len(last_text[ppos.line - initial_line])
            clen = len(current_text[pos.line - initial_line])
            if ppos < pos and clen > llen:  # maybe only chars have been added
                es = ((
                    "I",
                    ppos.line,
                    ppos.col,
                    current_text[ppos.line - initial_line][ppos.col:pos.col],
                ), )
                if is_complete_edit(initial_line, last_text, current_text, es):
                    return True, es
            if clen < llen:
                if ppos == pos:  # 'x' or DEL or dt or something
                    es = ((
                        "D",
                        pos.line,
                        pos.col,
                        last_text[ppos.line - initial_line][ppos.col:ppos.col +
                                                            (llen - clen)],
                    ), )
                    if is_complete_edit(initial_line, last_text, current_text,
                                        es):
                        return True, es
                if pos < ppos:  # Backspacing or dT dF?
                    es = ((
                        "D",
                        pos.line,
                        pos.col,
                        last_text[pos.line - initial_line][pos.col:pos.col +
                                                           llen - clen],
                    ), )
                    if is_complete_edit(initial_line, last_text, current_text,
                                        es):
                        return True, es
        elif len(current_text) < len(last_text):
            # were some lines deleted? (dd or so)
            es = []
            for i in range(len(last_text) - len(current_text)):
                es.append(
                    ("D", pos.line, 0, last_text[pos.line - initial_line + i]))
                es.append(("D", pos.line, 0, "\n"))
            if is_complete_edit(initial_line, last_text, current_text, es):
                return True, es
    else:
        # Movement in more than one line
        if ppos.line + 1 == pos.line and pos.col == 0:  # Carriage return?
            es = (("I", ppos.line, ppos.col, "\n"), )
            if is_complete_edit(initial_line, last_text, current_text, es):
                return True, es
    return False, None
예제 #21
0
    def _do_edit(self, cmd, ctab=None):
        if self._done:
            # do as what parent class do
            TabStop._do_edit(self, cmd, ctab)
            return

        ctype, line, col, cmd_text = cmd

        cursor = vim_helper.get_cursor_pos()
        [buf_num, cursor_line] = map(int, cursor[0:2])

        # trying to get what user inputted in current buffer
        if ctype == "I":
            self._input_chars.append(cmd_text)
        elif ctype == "D":
            line_text = vim_helper.buf[cursor_line - 1]
            self._input_chars = list(line_text[self._start.col:col])

        inputted_text = "".join(self._input_chars)

        if not self._input_chars:
            return

        # if there are more than 9 selection candidates,
        # may need to wait for 2 inputs to determine selection number
        is_all_digits = True
        has_selection_terminator = False

        # input string sub string of pure digits
        inputted_text_for_num = inputted_text
        for [i, s] in enumerate(self._input_chars):
            if s == " ":  # treat space as a terminator for selection
                has_selection_terminator = True
                inputted_text_for_num = inputted_text[0:i]
            elif not s.isdigit():
                is_all_digits = False

        should_continue_input = False
        if is_all_digits or has_selection_terminator:
            index_strs = [
                str(index)
                for index in list(range(1,
                                        len(self._choice_list) + 1))
            ]
            matched_index_strs = list(
                filter(lambda s: s.startswith(inputted_text_for_num),
                       index_strs))
            remained_choice_list = []
            if len(matched_index_strs) == 0:
                remained_choice_list = []
            elif has_selection_terminator:
                if inputted_text_for_num:
                    num = int(inputted_text_for_num)
                    remained_choice_list = list(self._choice_list)[num - 1:num]
            elif len(matched_index_strs) == 1:
                num = int(inputted_text_for_num)
                remained_choice_list = list(self._choice_list)[num - 1:num]
            else:
                should_continue_input = True
        else:
            remained_choice_list = []

        if should_continue_input:
            # will wait for further input
            return

        buf = vim_helper.buf
        if len(remained_choice_list) == 0:
            # no matched choice, should quit selection and go on with inputted text
            overwrite_text = inputted_text_for_num
            self._done = True
        elif len(remained_choice_list) == 1:
            # only one match
            matched_choice = remained_choice_list[0]
            overwrite_text = matched_choice
            self._done = True

        if overwrite_text is not None:
            old_end_col = self._end.col

            # change _end.col, thus `overwrite` won't alter texts after this tabstop
            displayed_text_end_col = self._start.col + len(inputted_text)
            self._end.col = displayed_text_end_col
            self.overwrite(buf, overwrite_text)

            # notify all tabstops those in the same line and after this to adjust their positions
            pivot = Position(line, old_end_col)
            diff_col = displayed_text_end_col - old_end_col
            self._parent._child_has_moved(self._parent.children.index(self),
                                          pivot, Position(0, diff_col))

            vim_helper.set_cursor_from_pos(
                [buf_num, cursor_line, self._end.col + 1])
예제 #22
0
    def _do_snippet(self, snippet, before):
        """Expands the given snippet, and handles everything that needs to be
        done with it."""
        self._setup_inner_state()

        self._snip_expanded_in_action = False
        self._should_update_textobjects = False

        # Adjust before, maybe the trigger is not the complete word
        text_before = before
        if snippet.matched:
            text_before = before[:-len(snippet.matched)]

        with use_proxy_buffer(self._csnippets, self._vstate):
            with self._action_context():
                cursor_set_in_action = snippet.do_pre_expand(
                    self._visual_content.text,
                    self._csnippets
                )

        if cursor_set_in_action:
            text_before = _vim.buf.line_till_cursor
            before = _vim.buf.line_till_cursor

        with suspend_proxy_edits():
            if self._cs:
                start = Position(_vim.buf.cursor.line, len(text_before))
                end = Position(_vim.buf.cursor.line, len(before))

                # If cursor is set in pre-action, then action was modified
                # cursor line, in that case we do not need to do any edits, it
                # can break snippet
                if not cursor_set_in_action:
                    # It could be that our trigger contains the content of
                    # TextObjects in our containing snippet. If this is indeed
                    # the case, we have to make sure that those are properly
                    # killed. We do this by pretending that the user deleted
                    # and retyped the text that our trigger matched.
                    edit_actions = [
                        ('D', start.line, start.col, snippet.matched),
                        ('I', start.line, start.col, snippet.matched),
                    ]
                    self._csnippets[0].replay_user_edits(edit_actions)

                si = snippet.launch(text_before, self._visual_content,
                    self._cs.find_parent_for_new_to(start),
                    start, end
                )
            else:
                start = Position(_vim.buf.cursor.line, len(text_before))
                end = Position(_vim.buf.cursor.line, len(before))
                si = snippet.launch(text_before, self._visual_content,
                                    None, start, end)

            self._visual_content.reset()
            self._csnippets.append(si)

            si.update_textobjects()

            with use_proxy_buffer(self._csnippets, self._vstate):
                with self._action_context():
                    snippet.do_post_expand(
                        si._start, si._end, self._csnippets
                    )

            self._vstate.remember_buffer(self._csnippets[0])

            if not self._snip_expanded_in_action:
                self._jump()
            elif self._cs.current_text != '':
                self._jump()
            else:
                self._current_snippet_is_done()

            if self._inside_action:
                self._snip_expanded_in_action = True
예제 #23
0
 def __init__(self):
     pos = vim_helper.buf.cursor
     self._mode = vim_helper.eval("mode()")
     Position.__init__(self, pos.line, pos.col)
예제 #24
0
    def _do_edit(self, cmd, ctab=None):
        """Apply the edit 'cmd' to this object."""
        ctype, line, col, text = cmd
        assert ('\n' not in text) or (text == '\n')
        pos = Position(line, col)

        to_kill = set()
        new_cmds = []
        for child in self._children:
            if ctype == 'I':  # Insertion
                if (child._start < pos < Position(child._end.line,
                                                  child._end.col)
                        and isinstance(child, NoneditableTextObject)):
                    to_kill.add(child)
                    new_cmds.append(cmd)
                    break
                elif ((child._start <= pos <= child._end)
                      and isinstance(child, EditableTextObject)):
                    if pos == child.end and not child.children:
                        try:
                            if ctab.number != child.number:
                                continue
                        except AttributeError:
                            pass
                    child._do_edit(cmd, ctab)
                    return
            else:  # Deletion
                delend = pos + Position(0, len(text)) if text != '\n' \
                    else Position(line + 1, 0)
                if ((child._start <= pos < child._end)
                        and (child._start < delend <= child._end)):
                    # this edit command is completely for the child
                    if isinstance(child, NoneditableTextObject):
                        to_kill.add(child)
                        new_cmds.append(cmd)
                        break
                    else:
                        child._do_edit(cmd, ctab)
                        return
                elif ((pos < child._start and child._end <= delend)
                      or (pos <= child._start and child._end < delend)):
                    # Case: this deletion removes the child
                    to_kill.add(child)
                    new_cmds.append(cmd)
                    break
                elif (pos < child._start
                      and (child._start < delend <= child._end)):
                    # Case: partially for us, partially for the child
                    my_text = text[:(child._start - pos).col]
                    c_text = text[(child._start - pos).col:]
                    new_cmds.append((ctype, line, col, my_text))
                    new_cmds.append((ctype, line, col, c_text))
                    break
                elif (delend >= child._end
                      and (child._start <= pos < child._end)):
                    # Case: partially for us, partially for the child
                    c_text = text[(child._end - pos).col:]
                    my_text = text[:(child._end - pos).col]
                    new_cmds.append((ctype, line, col, c_text))
                    new_cmds.append((ctype, line, col, my_text))
                    break

        for child in to_kill:
            self._del_child(child)
        if len(new_cmds):
            for child in new_cmds:
                self._do_edit(child)
            return

        # We have to handle this ourselves
        delta = Position(1, 0) if text == '\n' else Position(0, len(text))
        if ctype == 'D':
            # Makes no sense to delete in empty textobject
            if self._start == self._end:
                return
            delta.line *= -1
            delta.col *= -1
        pivot = Position(line, col)
        idx = -1
        for cidx, child in enumerate(self._children):
            if child._start < pivot <= child._end:
                idx = cidx
        self._child_has_moved(idx, pivot, delta)
예제 #25
0
파일: vim_state.py 프로젝트: lilijreey/.vim
 def __init__(self):
     pos = _vim.buf.cursor
     self._mode = _vim.eval("mode()")
     Position.__init__(self, pos.line, pos.col)
예제 #26
0
    def _jump(self, backwards=False):
        """Helper method that does the actual jump."""
        if self._should_update_textobjects:
            self._should_reset_visual = False
            self._cursor_moved()

        # we need to set 'onemore' there, because of limitations of the vim
        # API regarding cursor movements; without that test
        # 'CanExpandAnonSnippetInJumpActionWhileSelected' will fail
        with vim_helper.option_set_to("ve", "onemore"):
            jumped = False

            # We need to remember current snippets stack here because of
            # post-jump action on the last tabstop should be able to access
            # snippet instance which is ended just now.
            stack_for_post_jump = self._active_snippets[:]

            # If next tab has length 1 and the distance between itself and
            # self._ctab is 1 then there is 1 less CursorMove events.  We
            # cannot ignore next movement in such case.
            ntab_short_and_near = False

            if self._current_snippet:
                snippet_for_action = self._current_snippet
            elif stack_for_post_jump:
                snippet_for_action = stack_for_post_jump[-1]
            else:
                snippet_for_action = None

            if self._current_snippet:
                ntab = self._current_snippet.select_next_tab(backwards)
                if ntab:
                    if self._current_snippet.snippet.has_option("s"):
                        lineno = vim_helper.buf.cursor.line
                        vim_helper.buf[lineno] = vim_helper.buf[lineno].rstrip()
                    vim_helper.select(ntab.start, ntab.end)
                    jumped = True
                    if (
                        self._ctab is not None
                        and ntab.start - self._ctab.end == Position(0, 1)
                        and ntab.end - ntab.start == Position(0, 1)
                    ):
                        ntab_short_and_near = True

                    self._ctab = ntab

                    # Run interpolations again to update new placeholder
                    # values, binded to currently newly jumped placeholder.
                    self._visual_content.conserve_placeholder(self._ctab)
                    self._current_snippet.current_placeholder = (
                        self._visual_content.placeholder
                    )
                    self._should_reset_visual = False
                    self._active_snippets[0].update_textobjects(vim_helper.buf)
                    # Open any folds this might have created
                    vim_helper.command("normal! zv")
                    self._vstate.remember_buffer(self._active_snippets[0])

                    if ntab.number == 0 and self._active_snippets:
                        self._current_snippet_is_done()
                else:
                    # This really shouldn't happen, because a snippet should
                    # have been popped when its final tabstop was used.
                    # Cleanup by removing current snippet and recursing.
                    self._current_snippet_is_done()
                    jumped = self._jump(backwards)

            if jumped:
                if self._ctab:
                    self._vstate.remember_position()
                    self._vstate.remember_unnamed_register(self._ctab.current_text)
                if not ntab_short_and_near:
                    self._ignore_movements = True

            if len(stack_for_post_jump) > 0 and ntab is not None:
                with use_proxy_buffer(stack_for_post_jump, self._vstate):
                    snippet_for_action.snippet.do_post_jump(
                        ntab.number,
                        -1 if backwards else 1,
                        stack_for_post_jump,
                        snippet_for_action,
                    )

        return jumped
예제 #27
0
 def __init__(self):
     pos = _vim.buf.cursor
     self._mode = _vim.eval('mode()')
     Position.__init__(self, pos.line, pos.col)