def resolve_internal_normal_target(view, s: Region, target: int, linewise: bool = None, inclusive: bool = None) -> None: # An Internal Normal resolver may have modifiers such as linewise, # inclusive, exclusive, etc. Modifiers determine how the selection, relative # to the target should be resolved. # XXX Should modifiers be a bitwise options param rather than indivisual # params? This can be easily refactored later! # * For the moment, ensure at least one modifier is specified! # * For the moment, modifier can only be used individually! if linewise is None and inclusive is None: raise NotImplementedError() if linewise is not None and inclusive is not None: raise NotImplementedError() if linewise: resolve_visual_target(s, target) if s.b >= s.a: s.a = view.line(s.a).a s.b = view.full_line(s.b).b else: s.b = view.line(s.b).a s.a = view.full_line(s.a).b if inclusive: s.b = target if s.b >= s.a: s.b += 1 else: s.a += 1
def _get_text_object_tag(view, s: Region, inclusive: bool, count: int) -> Region: # When the active cursor position is on leading whitespace before a tag on # the same line then the start point of the text object is the tag. line = view.line(get_insertion_point_at_b(s)) tag_in_line = view_find_in_range(view, '^\\s*<[^>]+>', line.begin(), line.end()) if tag_in_line: if s.b >= s.a and s.b < tag_in_line.end(): if s.empty(): s.a = s.b = tag_in_line.end() else: s.a = tag_in_line.end() s.b = tag_in_line.end() + 1 begin_tag, end_tag, _ = find_containing_tag(view, s.begin()) if not (begin_tag and end_tag): return s # The normal method is to select a <tag> until the matching </tag>. For "at" # the tags are included, for "it" they are excluded. But when "it" is # repeated the tags will be included (otherwise nothing would change). if not inclusive: if s == Region(begin_tag.end(), end_tag.begin()): inclusive = True if inclusive: return Region(begin_tag.a, end_tag.b) else: return Region(begin_tag.b, end_tag.a)
def resolve_visual_line_target(view, s: Region, target: int) -> None: if s.a < s.b: # A --> B if target < s.a: # TARGET < A --> B s.a = view.full_line(s.a).b s.b = view.line(target).a elif target > s.a: s.b = view.full_line(target).b elif target == s.a: s.b = s.a s.a = view.full_line(target).b elif s.a > s.b: # B <-- A if target > s.a: # B <-- A < TARGET s.a = view.line(s.a - 1).a s.b = view.full_line(target).b elif target < s.a: # TARGET < B <-- TARGET < A s.b = view.line(target).a elif target == s.a: # A === TARGET s.a = view.line(s.a - 1).a s.b = view.full_line(target).b elif s.a == s.b: # A === B # If A and B are equal, it means the Visual selection is not "well # formed". Instead of raising an error, or not resolving the selection, # the selection is coerced to be "well formed" and then resolved. if target > s.a: s.a = view.line(s.a).a s.b = view.full_line(target).b elif target < s.a: s.a = view.full_line(s.a).b s.b = view.line(target).a elif target == s.a: s.a = view.line(target).a s.b = view.full_line(target).b
def highlight_error(self, region: sublime.Region, message: str): self.phantom_set = sublime.PhantomSet(self.view, 'json_errors') char_match = self.json_char_matcher.search(message) if char_match: if region.a > region.b: region.b += int(char_match.group(1)) region.a = region.b + 1 else: region.a += int(char_match.group(1)) region.b = region.a + 1 self.phantoms.append( sublime.Phantom( region, self.create_phantom_html(message, 'error'), sublime.LAYOUT_BELOW, self.navigation, )) self.phantom_set.update(self.phantoms) self.view.show(region) self.view.set_status('json_errors', message)
def resolve_indent_text_object(view, s: Region, inclusive: bool = True, big: bool = False): # Look for the minimum indentation in the current visual region. idnt = 1000 idnt_pt = None for line in view.lines(s): if not re.match('^\\s*$', view.substr(line)): level = view.indentation_level(line.a) if level < idnt: idnt = min(idnt, level) idnt_pt = line.a # If the selection has no indentation at all, find which indentation level # is the largest, the previous non blank before tphe cursor or the next non # blank after the cursor, and start the selection from that point. if idnt == 1000: pnb_pt = prev_non_ws(view, s.begin()) pnb_indent_level = view_indentation_level(view, pnb_pt) nnb_pt = next_non_ws(view, s.end()) nnb_indent_level = view_indentation_level(view, nnb_pt) if pnb_indent_level > nnb_indent_level: idnt_pt = s.a = s.b = pnb_pt elif nnb_indent_level > pnb_indent_level: idnt_pt = s.a = s.b = nnb_pt else: idnt_pt = pnb_pt if idnt == 0 and idnt_pt is not None: expanded = view.expand_by_class(s, CLASS_EMPTY_LINE) s.a = expanded.a s.b = expanded.b if not inclusive: # Case: ii and iI. Strip any leading whitespace. leading_ws = view_find(view, '\\s*', s.a) if leading_ws is not None: s.a = view.line(leading_ws.b).a s.b = prev_non_blank(view, s.b) elif big: # Case: aI. Add a line below. if view.substr(s.b) == '\n': s.b += 1 elif idnt > 0 and idnt_pt is not None: indented_region = view_indented_region(view, idnt_pt, inclusive) if indented_region.begin() < s.begin(): s.a = indented_region.begin() if indented_region.end() > s.end(): s.b = indented_region.end() if inclusive: # Case: ai. Add a line above. s.a = view.line(view.text_point(view.rowcol(s.a)[0] - 1, 0)).a # Case: aI. Add a line below. if big: s.b = view.full_line(view.text_point(view.rowcol(s.b - 1)[0] + 1, 0)).b return s