def snippets_in_current_scope(self): """Returns the snippets that could be expanded to Vim as a global variable.""" before = _vim.buf.line_till_cursor snippets = self._snips(before, True) # Sort snippets alphabetically snippets.sort(key=lambda x: x.trigger) for snip in snippets: description = snip.description[snip.description.find(snip.trigger) + len(snip.trigger) + 2:] key = as_unicode(snip.trigger) description = as_unicode(description) # remove surrounding "" or '' in snippet description if it exists if len(description) > 2: if (description[0] == description[-1] and description[0] in "'\""): description = description[1:-1] _vim.command(as_unicode( "let g:current_ulti_dict['{key}'] = '{val}'").format( key=key.replace("'", "''"), val=description.replace("'", "''")))
def _handle_failure(self, trigger): """Mainly make sure that we play well with SuperTab.""" if trigger.lower() == "<tab>": feedkey = "\\" + trigger elif trigger.lower() == "<s-tab>": feedkey = "\\" + trigger else: feedkey = None mode = "n" if not self._supertab_keys: if _vim.eval("exists('g:SuperTabMappingForward')") != "0": self._supertab_keys = ( _vim.eval("g:SuperTabMappingForward"), _vim.eval("g:SuperTabMappingBackward"), ) else: self._supertab_keys = ['', ''] for idx, sttrig in enumerate(self._supertab_keys): if trigger.lower() == sttrig.lower(): if idx == 0: feedkey = r"\<Plug>SuperTabForward" mode = "n" elif idx == 1: feedkey = r"\<Plug>SuperTabBackward" mode = "p" # Use remap mode so SuperTab mappings will be invoked. break if (feedkey == r"\<Plug>SuperTabForward" or feedkey == r"\<Plug>SuperTabBackward"): _vim.command("return SuperTab(%s)" % _vim.escape(mode)) elif feedkey: _vim.command("return %s" % _vim.escape(feedkey))
def restore_unnamed_register(self): """Restores the unnamed register and forgets what we cached.""" if not self._unnamed_reg_cached: return escaped_cache = self._unnamed_reg_cache.replace("'", "''") _vim.command("let @\"='%s'" % escaped_cache) self._unnamed_reg_cached = False
def _try_expand(self, autotrigger_only=False): """Try to expand a snippet in the current place.""" before = _vim.buf.line_till_cursor snippets = self._snips(before, False, autotrigger_only) if snippets: # prefer snippets with context if any snippets_with_context = [s for s in snippets if s.context] if snippets_with_context: snippets = snippets_with_context if not snippets: # No snippet found return False _vim.command("let &undolevels = &undolevels") if len(snippets) == 1: snippet = snippets[0] else: if self._ask_snippets: snippet = _ask_snippets(snippets) else: snippet = snippets[0] if not snippet: return True self._do_snippet(snippet, before) _vim.command("let &undolevels = &undolevels") return True
def remember_unnamed_register(self, text_to_expect): """Save the unnamed register. 'text_to_expect' is text that we expect to be contained in the register the next time this method is called - this could be text from the tabstop that was selected and might have been overwritten. We will not cache that then.""" self._unnamed_reg_cached = True escaped_text = self._text_to_expect.replace("'", "''") res = int(_vim.eval('@" != ' + "'" + escaped_text + "'")) if res: _vim.command('let g:_ultisnips_unnamed_reg_cache = @"') self._text_to_expect = text_to_expect
def expand_or_jump(self): """ This function is used for people who wants to have the same trigger for expansion and forward jumping. It first tries to expand a snippet, if this fails, it tries to jump forward. """ rv = self._try_expand() if rv == "ultilsnips_action_none": rv = self._jump() if rv == "ultilsnips_action_none": self._handle_failure(self.expand_trigger) _vim.command("let g:UltiSnips.pyResult = %s" % json.dumps(rv))
def __init__(self): self._poss = deque(maxlen=5) self._lvb = None self._text_to_expect = '' self._unnamed_reg_cached = False # We store the cached value of the unnamed register in Vim directly to # avoid any Unicode issues with saving and restoring the unnamed # register across the Python bindings. The unnamed register can contain # data that cannot be coerced to Unicode, and so a simple vim.eval('@"') # fails badly. Keeping the cached value in Vim directly, sidesteps the # problem. _vim.command('let g:_ultisnips_unnamed_reg_cache = ""')
def _handle_failure(self, trigger): """ Mainly make sure that we play well with SuperTab or pre-existing keymaps """ if trigger.lower() == _vim.eval("g:UltiSnipsExpandTrigger").lower() and _vim.eval("g:UltiSnipsExpandTriggerOverrides") != "": feedkey = "" + _vim.eval("g:UltiSnipsExpandTriggerOverrides") mode = "i" elif trigger.lower() == _vim.eval("g:UltiSnipsJumpForwardTrigger").lower() and _vim.eval("g:UltiSnipsJumpForwardTriggerOverrides") != "": feedkey = "" + _vim.eval("g:UltiSnipsJumpForwardTriggerOverrides") mode = "i" elif trigger.lower() == _vim.eval("g:UltiSnipsJumpBackwardTrigger").lower() and _vim.eval("g:UltiSnipsJumpBackwardTriggerOverrides") != "": feedkey = "" + _vim.eval("g:UltiSnipsJumpBackwardTriggerOverrides") mode = "i" elif trigger.lower() == "<tab>": feedkey = "\\" + trigger mode = "n" elif trigger.lower() == "<s-tab>": feedkey = "\\" + trigger mode = "n" else: feedkey = None mode = "n" if not self._supertab_keys: if _vim.eval("exists('g:SuperTabMappingForward')") != '0': self._supertab_keys = ( _vim.eval('g:SuperTabMappingForward'), _vim.eval('g:SuperTabMappingBackward'), ) else: self._supertab_keys = ['', ''] for idx, sttrig in enumerate(self._supertab_keys): if trigger.lower() == sttrig.lower(): if idx == 0: feedkey = r"\<Plug>SuperTabForward" mode = 'n' elif idx == 1: feedkey = r"\<Plug>SuperTabBackward" mode = 'p' # Use remap mode so SuperTab mappings will be invoked. break if (feedkey == r"\<Plug>SuperTabForward" or feedkey == r"\<Plug>SuperTabBackward"): _vim.command('return SuperTab(%s)' % _vim.escape(mode)) elif feedkey: _vim.command('return %s' % _vim.escape(feedkey))
def _map_inner_keys(self): """Map keys that should only be defined when a snippet is active.""" if self.expand_trigger != self.forward_trigger: _vim.command("inoremap <buffer> <silent> " + self.forward_trigger + " <C-R>=UltiSnips#JumpForwards()<cr>") _vim.command("snoremap <buffer> <silent> " + self.forward_trigger + " <Esc>:call UltiSnips#JumpForwards()<cr>") _vim.command("inoremap <buffer> <silent> " + self.backward_trigger + " <C-R>=UltiSnips#JumpBackwards()<cr>") _vim.command("snoremap <buffer> <silent> " + self.backward_trigger + " <Esc>:call UltiSnips#JumpBackwards()<cr>") self._inner_mappings_in_place = True
def list_snippets_dict(self): before, after = _vim.buf.current_line_splitted snippets = self._snips(before, True) # Sort snippets alphabetically snippets.sort(key=lambda x: x.trigger) for snip in snippets: description = snip.description[snip.description.find(snip.trigger) + len(snip.trigger) + 2:] key = as_unicode(snip.trigger) description = as_unicode(description) #remove surrounding "" or '' in snippet description if it exists if len(description) > 2: if description[0] == description[-1] and description[0] in ['"', "'"]: description = description[1:-1] _vim.command(as_unicode("let g:current_ulti_dict['{key}'] = '{val}'").format( key=key.replace("'", "''"), val=description.replace("'", "''")))
def jump_forwards(self): """Jumps to the next tabstop.""" _vim.command('let g:ulti_jump_forwards_res = 1') _vim.command('let &undolevels = &undolevels') if not self._jump(): _vim.command('let g:ulti_jump_forwards_res = 0') return self._handle_failure(self.forward_trigger)
def jump_backwards(self): """Jumps to the previous tabstop.""" _vim.command('let g:ulti_jump_backwards_res = 1') _vim.command('let &undolevels = &undolevels') if not self._jump(True): _vim.command('let g:ulti_jump_backwards_res = 0') return self._handle_failure(self.backward_trigger)
def _do_snippet(self, snippet, before): """Expands the given snippet, and handles everything that needs to be done with it.""" _vim.command("call UltiSnips#map_keys#MapInnerKeys()") # 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) self._ignore_movements = True self._vstate.remember_buffer(self._csnippets[0]) self._jump()
def _text_to_vim(start, end, text): """Copy the given text to the current buffer, overwriting the span 'start' to 'end'.""" lines = text.split('\n') new_end = _calc_end(lines, start) before = _vim.buf[start.line][:start.col] after = _vim.buf[end.line][end.col:] new_lines = [] if len(lines): new_lines.append(before + lines[0]) new_lines.extend(lines[1:]) new_lines[-1] += after _vim.buf[start.line:end.line + 1] = new_lines # Open any folds this might have created _vim.buf.cursor = start _vim.command("normal! zv") return new_end
def _unmap_inner_keys(self): """Unmap keys that should not be active when no snippet is active.""" if not self._inner_mappings_in_place: return try: if self.expand_trigger != self.forward_trigger: _vim.command("iunmap <buffer> %s" % self.forward_trigger) _vim.command("sunmap <buffer> %s" % self.forward_trigger) _vim.command("iunmap <buffer> %s" % self.backward_trigger) _vim.command("sunmap <buffer> %s" % self.backward_trigger) self._inner_mappings_in_place = False except _vim.error: # This happens when a preview window was opened. This issues # CursorMoved, but not BufLeave. We have no way to unmap, until we # are back in our buffer pass
def snippets_in_current_scope(self, searchAll): """Returns the snippets that could be expanded to Vim as a global variable.""" before = '' if searchAll else _vim.buf.line_till_cursor snippets = self._snips(before, True) # Sort snippets alphabetically snippets.sort(key=lambda x: x.trigger) for snip in snippets: description = snip.description[snip.description.find(snip.trigger) + len(snip.trigger) + 2:] location = snip.location if snip.location else '' key = as_unicode(snip.trigger) description = as_unicode(description) # remove surrounding "" or '' in snippet description if it exists if len(description) > 2: if (description[0] == description[-1] and description[0] in "'\""): description = description[1:-1] _vim.command(as_unicode( "let g:current_ulti_dict['{key}'] = '{val}'").format( key=key.replace("'", "''"), val=description.replace("'", "''"))) if searchAll: _vim.command(as_unicode( ("let g:current_ulti_dict_info['{key}'] = {{" "'description': '{description}'," "'location': '{location}'," "}}")).format( key=key.replace("'", "''"), location=location.replace("'", "''"), description=description.replace("'", "''")))
def _try_expand(self): """Try to expand a snippet in the current place.""" before = _vim.buf.line_till_cursor if not before: return False snippets = self._snips(before, False) if snippets: # prefer snippets with context if any snippets_with_context = [s for s in snippets if s.context] if snippets_with_context: snippets = snippets_with_context if not snippets: # No snippet found return False _vim.command('let &undolevels = &undolevels') if len(snippets) == 1: snippet = snippets[0] else: snippet = _ask_snippets(snippets) if not snippet: return True self._do_snippet(snippet, before) _vim.command('let &undolevels = &undolevels') return True
def _replace_text(buf, start, end, text): """Copy the given text to the current buffer, overwriting the span 'start' to 'end'.""" lines = text.split('\n') new_end = _calc_end(lines, start) before = buf[start.line][:start.col] after = buf[end.line][end.col:] new_lines = [] if len(lines): new_lines.append(before + lines[0]) new_lines.extend(lines[1:]) new_lines[-1] += after buf[start.line:end.line + 1] = new_lines # Open any folds this might have created # TODO(sirver): This leaks that we are still inside Vim, while this code should # only care that it is modifying 'buf'. _vim.buf.cursor = start _vim.command('normal! zv') return new_end
def expand_or_jump(self): """ This function is used for people who wants to have the same trigger for expansion and forward jumping. It first tries to expand a snippet, if this fails, it tries to jump forward. """ _vim.command('let g:ulti_expand_or_jump_res = 1') rv = self._try_expand() if not rv: _vim.command('let g:ulti_expand_or_jump_res = 2') rv = self._jump() if not rv: _vim.command('let g:ulti_expand_or_jump_res = 0') self._handle_failure(self.expand_trigger)
def expand(self): rv = self._try_expand() if rv == "ultisnips_action_none": self._handle_failure(self.expand_trigger) _vim.command("let g:UltiSnips.pyResult = %s" % json.dumps(rv))
def restore_unnamed_register(self): """Restores the unnamed register and forgets what we cached.""" if not self._unnamed_reg_cached: return _vim.command('let @" = g:_ultisnips_unnamed_reg_cache') self._unnamed_reg_cached = False
def jump_backwards(self): """Jumps to the previous tabstop.""" _vim.command("let g:ulti_jump_backwards_res = 1") if not self._jump(True): _vim.command("let g:ulti_jump_backwards_res = 0") return self._handle_failure(self.backward_trigger)
def expand(self): """Try to expand a snippet at the current position.""" _vim.command("let g:ulti_expand_res = 1") if not self._try_expand(): _vim.command("let g:ulti_expand_res = 0") self._handle_failure(self.expand_trigger)
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._active_snippets, self._vstate): with self._action_context(): cursor_set_in_action = snippet.do_pre_expand( self._visual_content.text, self._active_snippets ) if cursor_set_in_action: text_before = _vim.buf.line_till_cursor before = _vim.buf.line_till_cursor with suspend_proxy_edits(): start = Position(_vim.buf.cursor.line, len(text_before)) end = Position(_vim.buf.cursor.line, len(before)) parent = None if self._current_snippet: # 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._active_snippets[0].replay_user_edits(edit_actions) parent = self._current_snippet.find_parent_for_new_to(start) snippet_instance = snippet.launch(text_before, self._visual_content, parent, start, end) # Open any folds this might have created _vim.command('normal! zv') self._visual_content.reset() self._active_snippets.append(snippet_instance) with use_proxy_buffer(self._active_snippets, self._vstate): with self._action_context(): snippet.do_post_expand( snippet_instance._start, snippet_instance._end, self._active_snippets ) self._vstate.remember_buffer(self._active_snippets[0]) if not self._snip_expanded_in_action: self._jump() elif self._current_snippet.current_text != '': self._jump() else: self._current_snippet_is_done() if self._inside_action: self._snip_expanded_in_action = True
def expand(self): _vim.command("let g:ulti_expand_res = 1") if not self._try_expand(): _vim.command("let g:ulti_expand_res = 0") self._handle_failure(self.expand_trigger)
def _setup_inner_state(self): """Map keys and create autocommands that should only be defined when a snippet is active.""" if self._inner_state_up: return if self.expand_trigger != self.forward_trigger: _vim.command('inoremap <buffer> <silent> ' + self.forward_trigger + ' <C-R>=UltiSnips#JumpForwards()<cr>') _vim.command('snoremap <buffer> <silent> ' + self.forward_trigger + ' <Esc>:call UltiSnips#JumpForwards()<cr>') _vim.command('inoremap <buffer> <silent> ' + self.backward_trigger + ' <C-R>=UltiSnips#JumpBackwards()<cr>') _vim.command('snoremap <buffer> <silent> ' + self.backward_trigger + ' <Esc>:call UltiSnips#JumpBackwards()<cr>') # Setup the autogroups. _vim.command('augroup UltiSnips') _vim.command('autocmd!') _vim.command('autocmd CursorMovedI * call UltiSnips#CursorMoved()') _vim.command('autocmd CursorMoved * call UltiSnips#CursorMoved()') _vim.command( 'autocmd InsertLeave * call UltiSnips#LeavingInsertMode()') _vim.command('autocmd BufLeave * call UltiSnips#LeavingBuffer()') _vim.command( 'autocmd CmdwinEnter * call UltiSnips#LeavingBuffer()') _vim.command( 'autocmd CmdwinLeave * call UltiSnips#LeavingBuffer()') # Also exit the snippet when we enter a unite complete buffer. _vim.command('autocmd Filetype unite call UltiSnips#LeavingBuffer()') _vim.command('augroup END') _vim.command('silent doautocmd <nomodeline> User UltiSnipsEnterFirstSnippet') self._inner_state_up = True
def _error(self, msg): msg = _vim.escape("UltiSnips: " + msg) if self._test_error: msg = msg.replace('"', r'\"') msg = msg.replace('|', r'\|') _vim.command("let saved_pos=getpos('.')") _vim.command("$:put =%s" % msg) _vim.command("call setpos('.', saved_pos)") elif False: _vim.command("echohl WarningMsg") _vim.command("echomsg %s" % msg) _vim.command("echohl None") else: _vim.command("echoerr %s" % msg)
def jump_backwards(self): _vim.command("let g:ulti_jump_backwards_res = 1") if not self._jump(True): _vim.command("let g:ulti_jump_backwards_res = 0") return self._handle_failure(self.backward_trigger)
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.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.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 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.buf) # Open any folds this might have created _vim.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 jump_forwards(self): """Jumps to the next tabstop.""" _vim.command("let g:ulti_jump_forwards_res = 1") if not self._jump(): _vim.command("let g:ulti_jump_forwards_res = 0") return self._handle_failure(self.forward_trigger)
def expand(self): """Try to expand a snippet at the current position.""" _vim.command('let g:ulti_expand_res = 1') if not self._try_expand(): _vim.command('let g:ulti_expand_res = 0') self._handle_failure(self.expand_trigger)
def jump_backwards(self): rv = self._jump(True) if rv == "ultisnips_action_none": return self._handle_failure(self.backward_trigger) _vim.command("let g:UltiSnips.pyResult = %s" % json.dumps(rv))
def _current_snippet_is_done(self): """The current snippet should be terminated.""" self._csnippets.pop() if not self._csnippets: _vim.command("call UltiSnips#map_keys#RestoreInnerKeys()")
def _teardown_inner_state(self): """Reverse _setup_inner_state.""" if not self._inner_state_up: return try: _vim.command('silent doautocmd <nomodeline> User UltiSnipsExitLastSnippet') if self.expand_trigger != self.forward_trigger: _vim.command('iunmap <buffer> %s' % self.forward_trigger) _vim.command('sunmap <buffer> %s' % self.forward_trigger) _vim.command('iunmap <buffer> %s' % self.backward_trigger) _vim.command('sunmap <buffer> %s' % self.backward_trigger) _vim.command('augroup UltiSnips') _vim.command('autocmd!') _vim.command('augroup END') self._inner_state_up = False except _vim.error: # This happens when a preview window was opened. This issues # CursorMoved, but not BufLeave. We have no way to unmap, until we # are back in our buffer pass
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.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.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 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.buf) # Open any folds this might have created _vim.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 _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._active_snippets, self._vstate): with self._action_context(): cursor_set_in_action = snippet.do_pre_expand( self._visual_content.text, self._active_snippets) if cursor_set_in_action: text_before = _vim.buf.line_till_cursor before = _vim.buf.line_till_cursor with suspend_proxy_edits(): start = Position(_vim.buf.cursor.line, len(text_before)) end = Position(_vim.buf.cursor.line, len(before)) parent = None if self._current_snippet: # 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._active_snippets[0].replay_user_edits(edit_actions) parent = self._current_snippet.find_parent_for_new_to(start) snippet_instance = snippet.launch(text_before, self._visual_content, parent, start, end) # Open any folds this might have created _vim.command('normal! zv') self._visual_content.reset() self._active_snippets.append(snippet_instance) with use_proxy_buffer(self._active_snippets, self._vstate): with self._action_context(): snippet.do_post_expand(snippet_instance._start, snippet_instance._end, self._active_snippets) self._vstate.remember_buffer(self._active_snippets[0]) if not self._snip_expanded_in_action: self._jump() elif self._current_snippet.current_text != '': self._jump() else: self._current_snippet_is_done() if self._inside_action: self._snip_expanded_in_action = True