def _jump(self, backwards=False): jumped = False if self._cs: self._ctab = self._cs.select_next_tab(backwards) if self._ctab: before, after = _vim.buf.current_line_splitted if self._cs.snippet.has_option("s"): if after == "": m = re.match(r'(.*?)\s+$', before) if m: lineno = _vim.buf.cursor.line _vim.text_to_vim( Position(lineno, 0), Position(lineno, len(before) + len(after)), m.group(1)) _vim.select(self._ctab.start, self._ctab.end) jumped = True if self._ctab.no == 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) if jumped: self._vstate.remember_position() return jumped
def _do_snippet(self, snippet, before, after): """ Expands the given snippet, and handles everything that needs to be done with it. """ # 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)) 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 guess_edit(initial_line, lt, ct, vs): """ 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. """ if not len(lt) and not len(ct): return True, () pos = vs.pos ppos = vs.ppos if len(lt) and (not ct or (len(ct) == 1 and not ct[0])): # All text deleted? es = [] if not ct: ct = [''] for i in lt: 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, lt, ct, es): return True, es if ppos.mode == 'v': # Maybe selectmode? sv = list(map(int, _vim.eval("""getpos("'<")"""))); sv = Position(sv[1]-1,sv[2]-1) ev = list(map(int, _vim.eval("""getpos("'>")"""))); ev = Position(ev[1]-1,ev[2]-1) if "exclusive" in _vim.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, lt[sv.line - initial_line][sv.col:ev.col+1])) if sv != pos and sv.line == pos.line: es.append(("I", sv.line, sv.col, ct[sv.line - initial_line][sv.col:pos.col+1])) if is_complete_edit(initial_line, lt, ct, es): return True, es if pos.line == ppos.line: if len(lt) == len(ct): # Movement only in one line llen = len(lt[ppos.line - initial_line]) clen = len(ct[pos.line - initial_line]) if ppos < pos and clen > llen: # Likely that only characters have been added es = ( ("I", ppos.line, ppos.col, ct[ppos.line - initial_line][ppos.col:pos.col]), ) if is_complete_edit(initial_line, lt, ct, es): return True, es if clen < llen: if ppos == pos: # 'x' or DEL or dt or something es = ( ("D", pos.line, pos.col, lt[ppos.line - initial_line][ppos.col:ppos.col + (llen - clen)]), ) if is_complete_edit(initial_line, lt, ct, es): return True, es if pos < ppos: # Backspacing or dT dF? es = ( ("D", pos.line, pos.col, lt[pos.line - initial_line][pos.col:pos.col + llen - clen]), ) if is_complete_edit(initial_line, lt, ct, es): return True, es elif len(ct) < len(lt): # Maybe some lines were deleted? (dd or so) es = [] for i in range(len(lt)-len(ct)): es.append( ("D", pos.line, 0, lt[pos.line - initial_line + i])) es.append( ("D", pos.line, 0, '\n')) if is_complete_edit(initial_line, lt, ct, 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, lt, ct, es): return True, es return False, None
def __init__(self, parent): NoneditableTextObject.__init__( self, parent, _vim.buf.cursor, _vim.buf.cursor, tiebreaker=Position(0, 0), )
def __init__(self, parent, indent, initial_text, start, end, visual_content, last_re, globals): if start is None: start = Position(0,0) if end is None: end = Position(0,0) self._cts = 0 self.locals = {"match" : last_re} self.globals = globals self.visual_content = visual_content EditableTextObject.__init__(self, parent, start, end, initial_text) TOParser(self, initial_text, indent).parse(True) self.update_textobjects()
def _do_snippet(self, snippet, before, after): """ Expands the given snippet, and handles everything that needs to be done with it. """ # 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 parse(self, add_ts_zero=False): seen_ts = {} all_tokens = [] self._do_parse(all_tokens, seen_ts) self._resolve_ambiguity(all_tokens, seen_ts) self._create_objects_with_links_to_tabs(all_tokens, seen_ts) if add_ts_zero and 0 not in seen_ts: mark = all_tokens[-1][1].end # Last token is always EndOfText m1 = Position(mark.line, mark.col) TabStop(self._parent_to, 0, mark, m1) self._parent_to.replace_initital_text()
def __init__(self, parent, token, end = None, initial_text = "", tiebreaker = None): self._parent = parent ct = None 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 __init__(self): pos = _vim.buf.cursor self._mode = _vim.eval("mode()") self._visualmode = _vim.eval("visualmode()") Position.__init__(self, pos.line, pos.col)
def fget(self): line, nbyte = vim.current.window.cursor col = byte2col(line, nbyte) return Position(line - 1, col)
def _calc_end(lines, start): if len(lines) == 1: new_end = start + Position(0, len(lines[0])) else: new_end = Position(start.line + len(lines) - 1, len(lines[-1])) return new_end
def pos(self): return Position(self._line, self._col)
def _do_edit(self, cmd): ctype, line, col, text = cmd assert (('\n' not in text) or (text == "\n")) pos = Position(line, col) to_kill = set() new_cmds = [] for c in self._childs: if ctype == "I": # Insertion if c._start < pos < Position(c._end.line, c._end.col) and isinstance( c, NoneditableTextObject): to_kill.add(c) new_cmds.append(cmd) break elif (c._start <= pos <= c._end) and isinstance( c, EditableTextObject): c._do_edit(cmd) return else: # Deletion delend = pos + Position(0, len(text)) if text != "\n" \ else Position(line + 1, 0) if (c._start <= pos < c._end) and (c._start < delend <= c._end): # this edit command is completely for the child if isinstance(c, NoneditableTextObject): to_kill.add(c) new_cmds.append(cmd) break else: c._do_edit(cmd) return elif (pos < c._start and c._end <= delend) or (pos <= c._start and c._end < delend): # Case: this deletion removes the child to_kill.add(c) new_cmds.append(cmd) break elif (pos < c._start and (c._start < delend <= c._end)): # Case: partially for us, partially for the child my_text = text[:(c._start - pos).col] c_text = text[(c._start - pos).col:] new_cmds.append((ctype, line, col, my_text)) new_cmds.append((ctype, line, col, c_text)) break elif (delend >= c._end and (c._start <= pos < c._end)): # Case: partially for us, partially for the child c_text = text[(c._end - pos).col:] my_text = text[:(c._end - pos).col] new_cmds.append((ctype, line, col, c_text)) new_cmds.append((ctype, line, col, my_text)) break for c in to_kill: self._del_child(c) if len(new_cmds): for c in new_cmds: self._do_edit(c) return # We have to handle this ourselves delta = Position(1, 0) if text == "\n" else Position(0, len(text)) if ctype == "D": if self._start == self._end: # Makes no sense to delete in empty textobject return delta.line *= -1 delta.col *= -1 pivot = Position(line, col) idx = -1 for cidx, c in enumerate(self._childs): if c._start < pivot <= c._end: idx = cidx self._child_has_moved(idx, pivot, delta)