def find_next_lone_bracket(view, start, items, unbalanced=0): # TODO: Extract common functionality from here and the % motion instead of duplicating code. new_start = start for i in range(unbalanced or 1): next_closing_bracket = find_in_range(view, items[1], start=start, end=view.size(), flags=sublime.IGNORECASE) if next_closing_bracket is None: # Unbalanced items; nothing we can do. return new_start = next_closing_bracket.end() nested = 0 while True: next_opening_bracket = find_in_range(view, items[0], start=start, end=next_closing_bracket.b, flags=sublime.IGNORECASE) if not next_opening_bracket: break nested += 1 start = next_opening_bracket.end() if nested > 0: return find_next_lone_bracket(view, next_closing_bracket.end(), items, nested) else: return next_closing_bracket
def find_balanced_closing_bracket(self, start, brackets, unbalanced=0): new_start = start for i in range(unbalanced or 1): next_closing_bracket = find_in_range( self.view, brackets[1], start=new_start, end=self.view.size(), flags=sublime.LITERAL ) if next_closing_bracket is None: # Unbalanced brackets; nothing we can do. return new_start = next_closing_bracket.end() nested = 0 while True: next_opening_bracket = find_in_range( self.view, brackets[0], start=start, end=next_closing_bracket.end(), flags=sublime.LITERAL ) if not next_opening_bracket: break nested += 1 start = next_opening_bracket.end() if nested > 0: return self.find_balanced_closing_bracket(next_closing_bracket.end(), brackets, nested) else: return next_closing_bracket.begin()
def find_balanced_closing_bracket(self, start, brackets, unbalanced=0): new_start = start for i in range(unbalanced or 1): next_closing_bracket = find_in_range(self.view, brackets[1], start=new_start, end=self.view.size(), flags=sublime.LITERAL) if next_closing_bracket is None: # Unbalanced brackets; nothing we can do. return new_start = next_closing_bracket.end() nested = 0 while True: next_opening_bracket = find_in_range( self.view, brackets[0], start=start, end=next_closing_bracket.end(), flags=sublime.LITERAL) if not next_opening_bracket: break nested += 1 start = next_opening_bracket.end() if nested > 0: return self.find_balanced_closing_bracket( next_closing_bracket.end(), brackets, nested) else: return next_closing_bracket.begin()
def f(view, s): eol = view.line(s.b).end() if not s.empty(): eol = view.line(s.b - 1).end() match = s for i in range(count): # Define search range as 'rest of the line to the right'. if state.mode != MODE_VISUAL: search_range = sublime.Region(min(match.b + 1, eol), eol) else: search_range = sublime.Region(min(match.b, eol), eol) match = find_in_range(view, character, search_range.a, search_range.b, sublime.LITERAL) # Count too high or simply no match; break. if match is None: match = s break if state.mode == MODE_VISUAL or mode == _MODE_INTERNAL_NORMAL: if match == s: # FIXME: It won't blink because the current light can't be highlighted right # now (we are in command mode and there is a selection on the screen. Perhaps # we can make the gutter blink instead.) utils.blink() return sublime.Region(s.a, match.b) if match == s: utils.blink() return sublime.Region(match.a, match.a)
def get_text_object_region(view, s, text_object, inclusive=False): try: delims, type_ = PAIRS[text_object] except KeyError: return s if type_ == TAG: return find_tag_text_object(view, s, inclusive) if type_ == BRACKET: opening = find_prev_lone_bracket(view, s.b, delims) closing = find_next_lone_bracket(view, s.b, delims) if not (opening and closing): return s if inclusive: return sublime.Region(opening.a, closing.b) return sublime.Region(opening.a + 1, closing.b - 1) if type_ == QUOTE: prev_quote = reverse_search_by_pt(view, delims[0], start=0, end=s.b, flags=sublime.IGNORECASE) next_quote = find_in_range(view, delims[0], start=s.b, end=view.size(), flags=sublime.IGNORECASE) if not (prev_quote and next_quote): return s if inclusive: return sublime.Region(prev_quote.a, next_quote.b) return sublime.Region(prev_quote.a + 1, next_quote.b - 1) if type_ == WORD: # TODO: Improve this -- specify word separators. word_start = view.find_by_class(s.b, forward=True, classes=sublime.CLASS_WORD_START) w = view.word(s.b) # XXX: I don't think this is necessary? if not w: return s if inclusive: return sublime.Region(w.a, word_start) else: return w if type_ == SENTENCE: # FIXME: This doesn't work well. # TODO: Improve this. sentence_start = view.find_by_class(s.b, forward=False, classes=sublime.CLASS_EMPTY_LINE) sentence_start_2 = reverse_search_by_pt(view, "[.?!:]\s+|[.?!:]$", start=0, end=s.b) if sentence_start_2: sentence_start = sentence_start + 1 if sentence_start > sentence_start_2.b else sentence_start_2.b else: sentence_start = sentence_start + 1 sentence_end = find_in_range(view, "[.?!:)](?=\s)|[.?!:)]$", start=s.b, end=view.size()) if not (sentence_end): return s if inclusive: return sublime.Region(sentence_start, sentence_end.b) else: return sublime.Region(sentence_start, sentence_end.b) return s
def get_text_object_region(view, s, text_object, inclusive=False, count=1): try: delims, type_ = PAIRS[text_object] except KeyError: return s if type_ == TAG: begin_tag, end_tag, _ = find_containing_tag(view, s.b) if inclusive: return sublime.Region(begin_tag.a, end_tag.b) else: return sublime.Region(begin_tag.b, end_tag.a) if type_ == PARAGRAPH: return find_paragraph_text_object(view, s, inclusive=inclusive, count=count) if type_ == BRACKET: opening = find_prev_lone_bracket(view, s.b, delims) closing = find_next_lone_bracket(view, s.b, delims) if not (opening and closing): return s if inclusive: return sublime.Region(opening.a, closing.b) return sublime.Region(opening.a + 1, closing.b - 1) if type_ == QUOTE: # Vim only operates on the current line. line = view.line(s) # FIXME: Escape sequences like \" are probably syntax-dependant. prev_quote = reverse_search_by_pt(view, r'(?<!\\\\)' + delims[0], start=line.a, end=s.b) next_quote = find_in_range(view, r'(?<!\\\\)' + delims[0], start=s.b, end=line.b) if next_quote and not prev_quote: prev_quote = next_quote next_quote = find_in_range(view, r'(?<!\\\\)' + delims[0], start=prev_quote.b, end=line.b) if not (prev_quote and next_quote): return s if inclusive: return sublime.Region(prev_quote.a, next_quote.b) return sublime.Region(prev_quote.a + 1, next_quote.b - 1) if type_ == WORD: w = a_word(view, s.b, inclusive=inclusive, count=count) if not w: return s if s.size() <= 1: return w return sublime.Region(s.a, w.b) if type_ == BIG_WORD: w = a_big_word(view, s.b, inclusive=inclusive, count=count) if not w: return s if s.size() <= 1: return w return sublime.Region(s.a, w.b) if type_ == SENTENCE: # FIXME: This doesn't work well. # TODO: Improve this. sentence_start = view.find_by_class(s.b, forward=False, classes=sublime.CLASS_EMPTY_LINE) sentence_start_2 = reverse_search_by_pt(view, r'[.?!:]\s+|[.?!:]$', start=0, end=s.b) if sentence_start_2: sentence_start = (sentence_start + 1 if (sentence_start > sentence_start_2.b) else sentence_start_2.b) else: sentence_start = sentence_start + 1 sentence_end = find_in_range(view, r'([.?!:)](?=\s))|([.?!:)]$)', start=s.b, end=view.size()) if not (sentence_end): return s if inclusive: return sublime.Region(sentence_start, sentence_end.b) else: return sublime.Region(sentence_start, sentence_end.b) return s
def get_text_object_region(view, s, text_object, inclusive=False, count=1): try: delims, type_ = PAIRS[text_object] except KeyError: return s if type_ == TAG: return find_tag_text_object(view, s, inclusive) if type_ == BRACKET: opening = find_prev_lone_bracket(view, s.b, delims) closing = find_next_lone_bracket(view, s.b, delims) if not (opening and closing): return s if inclusive: return sublime.Region(opening.a, closing.b) return sublime.Region(opening.a + 1, closing.b - 1) if type_ == QUOTE: # Vim only operates on the current line. line = view.line(s) # FIXME: Escape sequences like \" are probably syntax-dependant. prev_quote = reverse_search_by_pt(view, '(?<!\\\\)' + delims[0], start=line.a, end=s.b) next_quote = find_in_range(view, '(?<!\\\\)' + delims[0], start=s.b, end=line.b) if next_quote and not prev_quote: prev_quote = next_quote next_quote = find_in_range(view, '(?<!\\\\)' + delims[0], start=prev_quote.b, end=line.b) if not (prev_quote and next_quote): return s if inclusive: return sublime.Region(prev_quote.a, next_quote.b) return sublime.Region(prev_quote.a + 1, next_quote.b - 1) if type_ == WORD: w = a_word(view, s.b, inclusive=inclusive, count=count) if not w: return s return w if type_ == BIG_WORD: w = a_big_word(view, s.b, inclusive=inclusive, count=count) if not w: return s return w if type_ == SENTENCE: # FIXME: This doesn't work well. # TODO: Improve this. sentence_start = view.find_by_class(s.b, forward=False, classes=sublime.CLASS_EMPTY_LINE) sentence_start_2 = reverse_search_by_pt(view, "[.?!:]\s+|[.?!:]$", start=0, end=s.b) if sentence_start_2: sentence_start = sentence_start + 1 if sentence_start > sentence_start_2.b else sentence_start_2.b else: sentence_start = sentence_start + 1 sentence_end = find_in_range(view, "[.?!:)](?=\s)|[.?!:)]$", start=s.b, end=view.size()) if not (sentence_end): return s if inclusive: return sublime.Region(sentence_start, sentence_end.b) else: return sublime.Region(sentence_start, sentence_end.b) return s
def get_text_object_region(view, s, text_object, inclusive=False, count=1): try: delims, type_ = PAIRS[text_object] except KeyError: return s if type_ == TAG: return find_tag_text_object(view, s, inclusive) if type_ == BRACKET: opening = find_prev_lone_bracket(view, s.b, delims) closing = find_next_lone_bracket(view, s.b, delims) if not (opening and closing): return s if inclusive: return sublime.Region(opening.a, closing.b) return sublime.Region(opening.a + 1, closing.b - 1) if type_ == QUOTE: # FIXME: Escape sequences like \" are probably syntax-dependant. prev_quote = reverse_search_by_pt(view, '(?<!\\\\)' + delims[0], start=0, end=s.b) next_quote = find_in_range(view, '(?<!\\\\)' + delims[0], start=s.b, end=view.size()) if not (prev_quote and next_quote): return s if inclusive: return sublime.Region(prev_quote.a, next_quote.b) return sublime.Region(prev_quote.a + 1, next_quote.b - 1) if type_ == WORD: w = a_word(view, s.b, inclusive=inclusive, count=count) if not w: return s return w if type_ == BIG_WORD: w = a_big_word(view, s.b, inclusive=inclusive, count=count) if not w: return s return w if type_ == SENTENCE: # FIXME: This doesn't work well. # TODO: Improve this. sentence_start = view.find_by_class(s.b, forward=False, classes=sublime.CLASS_EMPTY_LINE) sentence_start_2 = reverse_search_by_pt(view, "[.?!:]\s+|[.?!:]$", start=0, end=s.b) if sentence_start_2: sentence_start = sentence_start + 1 if sentence_start > sentence_start_2.b else sentence_start_2.b else: sentence_start = sentence_start + 1 sentence_end = find_in_range(view, "[.?!:)](?=\s)|[.?!:)]$", start=s.b, end=view.size()) if not (sentence_end): return s if inclusive: return sublime.Region(sentence_start, sentence_end.b) else: return sublime.Region(sentence_start, sentence_end.b) return s