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])
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)
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)
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
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
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]
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
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)
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
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)
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()
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)
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)
def __init__(self, parent): NoneditableTextObject.__init__( self, parent, vim_helper.buf.cursor, vim_helper.buf.cursor, tiebreaker=Position(-1, -1), )
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)
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()
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)
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
def pos(self): """Current position in the text.""" return Position(self._line, self._col)
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
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])
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
def __init__(self): pos = vim_helper.buf.cursor self._mode = vim_helper.eval("mode()") Position.__init__(self, pos.line, pos.col)
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)
def __init__(self): pos = _vim.buf.cursor self._mode = _vim.eval("mode()") Position.__init__(self, pos.line, pos.col)
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
def __init__(self): pos = _vim.buf.cursor self._mode = _vim.eval('mode()') Position.__init__(self, pos.line, pos.col)