def next_paragraph_start(view, pt, count=1, skip_empty=True): if utils.row_at(view, pt) == utils.last_row(view): if not view.line(view.size()).empty(): return view.size() - 1 return view.size() # skip empty rows before moving for the first time current_row = utils.row_at(view, pt) if (view.line(view.text_point(current_row + 1, 0)).empty() and view.line(pt).empty()): pt, _ = _next_non_empty_row(view, pt) for i in range(count): pt, eof = _next_empty_row(view, pt) if eof: if view.line(pt).empty(): return pt return pt - 1 if skip_empty and (i != (count - 1)): pt, eof = _next_non_empty_row(view, pt) if eof: if not view.line(pt).empty(): return pt - 1 return pt return pt
def _next_empty_row(view, pt): r = utils.row_at(view, pt) while True: r += 1 pt = view.text_point(r, 0) if utils.row_at(view, pt) == utils.last_row(view): return view.size(), True if view.line(pt).empty(): return pt, False
def resolve_line_reference(self, view, line_reference, current=0): """ Calculate the line offset determined by @line_reference. @view The view where the calculation is made. @line_reference The sequence of tokens defining the line range to be calculated. @current Line number where we are now. """ last_token = None # XXX: what happens if there is no selection in the view? current = row_at(view, first_sel(view).b) for token in line_reference: # Make sure a search forward doesn't overlap with a match obtained # right before this search. if isinstance(last_token, TokenOfSearch) and isinstance(token, TokenOfSearch): if isinstance(token, TokenSearchForward): current += 1 current = self.resolve_notation(view, token, current) last_token = token return current
def _prev_empty_row(view, pt): r = utils.row_at(view, pt) while True: r -= 1 if r == 0: return 0, True pt = view.text_point(r, 0) if view.line(pt).empty(): return pt, False
def _next_non_empty_row(view, pt): r = utils.row_at(view, pt) while True: r += 1 reg = view.line(view.text_point(r, 0)) if r >= utils.last_row(view): return view.size(), True if not reg.empty(): return reg.a, False
def get_visual_repeat_data(self): """ Return the data needed to restore visual selections. Before repeating a visual mode command in normal mode. """ if self.mode not in (modes.VISUAL, modes.VISUAL_LINE): return first = first_sel(self.view) lines = (utils.row_at(self.view, first.end()) - utils.row_at(self.view, first.begin())) if lines > 0: chars = utils.col_at(self.view, first.end()) else: chars = first.size() return (lines, chars, self.mode)
def _prev_non_empty_row(view, pt): r = utils.row_at(view, pt) while True: r -= 1 reg = view.line(view.text_point(r, 0)) # stop if we hit the first row if r <= 0: return 0, True if not reg.empty(): return reg.a, False
def resolve_mark(self, view, token): if token.content == '<': sel = list(view.sel())[0] view.sel().clear() view.sel().add(sel) if sel.a < sel.b: return row_at(view, sel.a) else: return row_at(view, sel.a - 1) if token.content == '>': sel = list(view.sel())[0] view.sel().clear() view.sel().add(sel) if sel.a < sel.b: return row_at(view, sel.b - 1) else: return row_at(view, sel.b) raise NotImplementedError()
def restore_visual_data(self, data): rows, chars, old_mode = data first = first_sel(self.view) if old_mode == modes.VISUAL: if rows > 0: end = self.view.text_point(utils.row_at(self.view, first.b) + rows, chars) else: end = first.b + chars self.view.sel().add(sublime.Region(first.b, end)) self.mode = modes.VISUAL elif old_mode == modes.VISUAL_LINE: rows, _, old_mode = data begin = self.view.line(first.b).a end = self.view.text_point(utils.row_at(self.view, begin) + (rows - 1), 0) end = self.view.full_line(end).b self.view.sel().add(sublime.Region(begin, end)) self.mode = modes.VISUAL_LINE
def lines(view, s, count=1): """ Return a region spanning @count full lines. Assumes we're operating in INTERNAL_NORMAL mode. @view Target view. @s Selection in @view taken as starting point. @count Number of lines to include in returned region. """ # assumes INTERNAL_NORMAL mode. a = view.line(s.b).a b = view.text_point(utils.row_at(view, s.b) + (count - 1), 0) # make sure we remove the last line if needed if ((utils.row_at(view, b) == utils.last_row(view)) and (view.substr(a - 1) == '\n')): a -= 1 return sublime.Region(a, view.full_line(b).b)
def resolve_notation(self, view, token, current): """Return a line number.""" if isinstance(token, TokenDot): pt = view.text_point(current, 0) return row_at(view, pt) if isinstance(token, TokenDigits): return max(int(str(token)) - 1, -1) if isinstance(token, TokenPercent): return row_at(view, view.size()) if isinstance(token, TokenDollar): return row_at(view, view.size()) if isinstance(token, TokenOffset): return current + sum(token.content) if isinstance(token, TokenSearchForward): start_pt = view.text_point(current, 0) match = view.find(str(token)[1:-1], start_pt) if not match: raise ValueError('pattern not found') return row_at(view, match.a) if isinstance(token, TokenSearchBackward): start_pt = view.text_point(current, 0) match = reverse_search_by_pt(view, str(token)[1:-1], 0, start_pt) if not match: raise ValueError('pattern not found') return row_at(view, match.a) if isinstance(token, TokenMark): return self.resolve_mark(view, token) raise NotImplementedError()
def prev_paragraph_start(view, pt, count=1, skip_empty=True): # first row? if utils.row_at(view, pt) == 0: return 0 current_row = utils.row_at(view, pt) if (view.line(view.text_point(current_row - 1, 0)).empty() and view.line(view.text_point(current_row, 0)).empty()): pt, bof = _prev_non_empty_row(view, pt) if bof: return 0 for i in range(count): pt, bof = _prev_empty_row(view, pt) if bof: return 0 if skip_empty and (count > 1) and (i != count - 1): pt, bof = _prev_non_empty_row(view, pt) if bof: return pt return view.text_point(utils.row_at(view, pt), 0)
def inner_lines(view, s, count=1): """ Return a region spanning @count inner lines. Inner lines are lines excluding leading/trailing whitespace at outer ends. Assumes we're operating in INTERNAL_NORMAL mode. @view Target view. @s Selection in @view taken as starting point. @count Number of lines to include in returned region. """ end = view.text_point(utils.row_at(view, s.b) + (count - 1), 0) begin = view.line(s.b).a begin = utils.next_non_white_space_char(view, begin, white_space=' \t') return sublime.Region(begin, view.line(end).b)