def run(self, edit, **kwargs): v = self.view if v.sel()[0].size() == 0: v.run_command('expand_selection', {'to': 'scope'}) for sel in v.sel(): text = v.substr(sel) res = re_quotes.match(text) if not res: # the current selection doesn't begin and end with a quote. # let's expand the selection one character each direction and try again sel = Region(sel.begin() - 1, sel.end() + 1) text = v.substr(sel) res = re_quotes.match(text) if not res: # still no match... skip it! continue oldQuotes = res.group(1) if 'key' in kwargs: newQuotes = kwargs['key'] else: newQuotes = quoteList[(quoteList.index(oldQuotes) + 1) % len(quoteList)] text = res.group(2) text = text.replace(newQuotes, "\\" + newQuotes) text = text.replace("\\" + oldQuotes, oldQuotes) text = newQuotes + text + newQuotes v.replace(edit, sel, text)
def run(self, edit): sel = self.view.sel() current = sel[0].begin() line = self.view.line(current) length = line.end() - line.begin() upper = '/*==' + ('-' * (length - 1)) bottom = '/' + ('-' * (length - 1)) + '==*/' added = self.view.insert(edit, line.begin(), upper + '\n/ ') line = Region(line.begin() + added, line.end() + added) self.view.insert(edit, line.end(), '\n' + bottom)
def run(self, edit, forward=None): assert forward in (True, False), 'forward must be set to True or False' count = self.view.settings().get('dired_project_count', 0) files = Region(self.view.text_point(3, 0), self.view.text_point(count+3-1, 0)) if files.empty(): return pt = self.view.sel()[0].a line = self.next_line(forward, pt, files) self.view.sel().clear() self.view.sel().add(Region(line.a, line.a))
def get_punctuation_region(view, pt: int) -> Region: start = view.find_by_class(pt + 1, forward=False, classes=CLASS_PUNCTUATION_START) end = view.find_by_class(pt, forward=True, classes=CLASS_PUNCTUATION_END) return Region(start, end)
def test_beginning_of_document(self): """Test word wrapping at the beginning of the document. Test word wrapping of a section of line comments that starts at the beginning of the document. """ view = self._view self._set_up_cpp() view.settings().set('rulers', [60]) comment_start_point = 0 self._insert( comment_start_point, '// Lorem ipsum dolor sit amet, iudicabit interpretaris ius eu, ' 'et sit iudico aperiri scaevola. Ad solum eleifend sea, ex ius ' 'graeci alienum accusamus, diam mandamus expetenda quo ei.\n') expected_text = ( '// Lorem ipsum dolor sit amet, iudicabit interpretaris ius\n' '// eu, et sit iudico aperiri scaevola. Ad solum eleifend\n' '// sea, ex ius graeci alienum accusamus, diam mandamus\n' '// expetenda quo ei.\n') actual_text = view.substr(Region(0, view.size())) self.assertEqual(actual_text, expected_text) point = view.find(r'aperiri scaevola\.', 0).end() self._insert( point, ' Vim case eros choro et, te deserunt iudicabit assentior eum, id ' 'his assum nobis primis.') expected_text = ( '// Lorem ipsum dolor sit amet, iudicabit interpretaris ius\n' '// eu, et sit iudico aperiri scaevola. Vim case eros choro\n' '// et, te deserunt iudicabit assentior eum, id his assum\n' '// nobis primis. Ad solum eleifend sea, ex ius graeci\n' '// alienum accusamus, diam mandamus expetenda quo ei.\n') actual_text = view.substr(Region(0, view.size())) self.assertEqual(actual_text, expected_text) point = view.find('Lorem ipsum', 0).begin() self._delete(point, 92) expected_text = ( '// Vim case eros choro et, te deserunt iudicabit assentior\n' '// eum, id his assum nobis primis. Ad solum eleifend sea, ex\n' '// ius graeci alienum accusamus, diam mandamus expetenda quo\n' '// ei.\n') actual_text = view.substr(Region(0, view.size())) self.assertEqual(actual_text, expected_text)
def toggle_fold(self, i): v = self.view tester = self.tester _inp = self.tester.tests[i].test_string _outp = self.tester.prog_out[i] text = _inp + '\n' + _outp.rstrip() + '\n' + '\n' tie_pos = self.get_tie_pos(i) if tester.tests[i].fold: v.run_command('test_manager', { 'action': 'replace', 'region': (tie_pos + 1, tie_pos + 1), 'text': text }) v.add_regions(self.REGION_BEGIN_KEY % i, \ [Region(tie_pos + 1)], *self.REGION_BEGIN_PROP) v.add_regions('test_end_%d' % i, \ [Region(tie_pos + len(_inp) + 2, tie_pos + len(_inp) + 2)], \ *self.REGION_END_PROP) d = len(text) for j in range(i + 1, self.tester.test_iter): self.tester.tests[j].tie_pos += d tester.tests[i].fold = False else: v.run_command('test_manager', { 'action': 'replace', 'region': (tie_pos + 1, tie_pos + 1 + len(text)), 'text': '' }) v.erase_regions(self.REGION_BEGIN_KEY % i) v.erase_regions('test_end_%d' % i) d = len(text) for j in range(i + 1, tester.test_iter): tester.tests[j].tie_pos -= d tester.tests[i].fold = True v.sel().clear() v.sel().add(Region(v.size())) self.update_configs()
def thread_unthreaded(): characters = "({} {} ".format(arrow, view.substr(form)) insert = view.insert(edit, innermost.open.begin(), characters) begin = insert + form.begin() view.insert(edit, innermost.close.end() + insert, ")") erase = Region(begin - 1, begin + form.size()) view.erase(edit, erase)
def replacements_for_dedent(self): row = row_at(cxt.view, self.begin) row_end = row_at(cxt.view, self.end) while row < row_end: row += 1 start = cxt.view.text_point(row, 0) yield Region(start, start + cxt.tab_size), ''
def recompile(self): view = self.view unsaved_files = [(view.file_name(), view.substr(Region(0, view.size())))] if not tuCache.reparse(view, view.file_name(), unsaved_files, self.reparse_done): # Already parsing so retry in a bit self.restart_recompile_timer(1)
def run(self, edit): regions = self.view.lines(Region(0, self.view.size())) for idx, region in enumerate(regions): line = Line(self.view, region, self.view.buffer_id(), None, idx) line.erase_region() del file_cacher_dict[self.view.file_name()]
def _write_to_ex_cmdline(view, edit, cmd: str, completion: str) -> None: # Mark the window to ignore updates during view changes. For example, when # changes may trigger an input panel on_change() event, which could then # trigger a prefix update. See: on_change_cmdline_completion_prefix(). view.window().settings().set('_nv_ignore_next_on_change', True) view.sel().clear() view.replace(edit, view_to_region(view), cmd + ' ' + completion) view.sel().add(Region(view.size()))
def contents(self): split = self._view.split_by_newlines(self._region) if len(split) == 1: return self._view.substr( Region(self.contents_begin(), self.contents_end())) else: return '\n'.join( [self.strip_delim(self._view.substr(r)) for r in split])
def backward_move_form(view, edit): for region, sel in iterate(view): point = region.begin() form = forms.find_adjacent(view, point) if form: previous_form = forms.find_previous(view, form.begin()) if previous_form: sel.append(previous_form.begin()) form_str = view.substr(form) previous_form_str = view.substr(previous_form) between = view.substr(Region(previous_form.end(), form.begin())) view.erase(edit, Region(previous_form.begin(), form.end())) view.insert(edit, previous_form.begin(), form_str + between + previous_form_str)
def fold_accept_tests(self): v = self.view cur_test = self.tester.test_iter for i in range(cur_test): if self.tester.check_test(i): beg = v.get_regions(self.REGION_BEGIN_KEY % i)[0].begin() end = v.line(v.get_regions(self.REGION_END_KEY % i)[0].begin()).end() v.fold(Region(v.word(beg + 5).end(), end))
def f(view, s): b = s.b if ((view.substr(b) == '\n' or b == view.size()) and not view.line(b).empty()): return Region(b - 1) return s
def narrow_to_non_space(view: sublime.View, region: sublime.Region) -> sublime.Region: "Returns copy of region which starts and ends at non-space character" begin = region.begin() end = region.end() while begin < end: if not view.substr(begin).isspace(): break begin += 1 while end > begin: if not view.substr(end - 1).isspace(): break end -= 1 return sublime.Region(begin, end)
def run(self, edit): view = self.view unsaved_files = [] if view.is_dirty(): unsaved_files.append( (view.file_name(), view.substr(Region(0, view.size())))) translationunitcache.tuCache.reparse(view, view.file_name(), unsaved_files)
def find_paragraph_text_object(view, s: Region, inclusive: bool = True, count: int = 1) -> Region: # In Vim, `vip` will select an inner paragraph -- all the lines having the # same whitespace status of the current location. And a `vap` will select # both the current inner paragraph (either whitespace or not) and the next # inner paragraph (the opposite). begin = None end = s.a for _ in range(count): b1, e1 = find_inner_paragraph(view, end) b2, end = find_inner_paragraph(view, e1) if inclusive else (b1, e1) if begin is None: begin = b1 if begin is None: return Region(end) return Region(begin, end)
def indent_region(view, edit, region, prune=False): if region and not view.match_selector(region.begin(), IGNORE_SELECTORS): new_lines = [] for line in view.lines(region): replacee = line if new_lines: if previous := new_lines.pop(): begin = previous.end() end = begin + line.size() replacee = Region(begin, end) if replacer := get_indented_string(view, replacee, prune=prune): view.replace(edit, replacee, replacer) new_lines.append(view.full_line(replacee.begin())) restore_cursors(view)
def _rfind(view, sub, start, end, flags=0): # TODO Make start and end optional arguments interpreted as in slice notation. # TODO [refactor] into reusable api. res = reverse_search(view, sub, start, end, flags) if res is None: return Region(-1) return res
def finish(self): """Things that are required to use the output panel properly. Set the selection to the start, so that next_result will work as expected. """ self.view.sel().clear() self.view.sel().add(Region(0))
def apply_change(self, region: sublime.Region, replacement: str, edit: Any) -> None: if region.empty(): self.view.insert(edit, region.a, replacement) else: if len(replacement) > 0: self.view.replace(edit, region, replacement) else: self.view.erase(edit, region)
def new_uri_phantom(view: sublime.View, uri_region: sublime.Region) -> sublime.Phantom: return sublime.Phantom( sublime.Region(uri_region.end()), generate_phantom_html(view, uri_region), layout=sublime.LAYOUT_INLINE, on_navigate=open_uri_with_browser, )
def f(view, s): if mode in (NORMAL, INTERNAL_NORMAL): pt = s.b if ((view.substr(pt) == '\n' or pt == view.size()) and not view.line(pt).empty()): return Region(pt - 1) return s
def imports(self, view): imports = [] regions = view.split_by_newlines(Region(0, 1024)) for region in regions: line = view.substr(region) if line[0:11] == '// #import ': imports.append(line[11:]) return set(imports)
def resolve(self, view) -> Region: # Return a Vim line range that the ex command should operate on. start = _resolve_line_reference(view, self.start or [TokenDot()]) if not self.separator: if start == -1: return Region(-1, -1) if len(self.start) == 1 and isinstance(self.start[0], TokenPercent): return view_to_region(view) return view.full_line(view.text_point(start, 0)) new_start = start if self.separator == ';' else 0 end = _resolve_line_reference(view, self.end or [TokenDot()], current=new_start) return view.full_line(Region(view.text_point(start, 0), view.text_point(end, 0)))
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 insert_best_cmdline_completion(view, edit, forward: bool = True) -> None: if is_ex_mode(view): if _is_setting_completion(view): _SettingCompletion(view).run(edit) elif _is_fs_completion(view): _FsCompletion(view).run(edit) else: cmdline = view_to_str(view) if len(cmdline) < 1: return prefix = cmdline[1:] if prefix not in _current_cmdline_completions: prefix_completions = [ x for x in _CMDLINE_COMPLETIONS if x.startswith(prefix) and x != prefix ] if prefix_completions: _current_cmdline_completions[:] = [prefix ] + prefix_completions try: prefix_index = _current_cmdline_completions.index(prefix) except ValueError: view.window().settings().set('_nv_ignore_next_on_change', True) view.insert(edit, view.size(), "\t") _current_cmdline_completions.clear() return next_index = prefix_index + 1 if forward else prefix_index - 1 if forward: idx = next_index if len( _current_cmdline_completions) > next_index else 0 else: idx = next_index if next_index >= 0 else len( _current_cmdline_completions) - 1 completion = _current_cmdline_completions[idx] view.window().settings().set('_nv_ignore_next_on_change', True) view.sel().clear() view.replace(edit, Region(1, view.size()), completion) view.sel().add(Region(view.size()))
def to_region(self, view): """ Returns: None if the line or column are invalid or an empty region with """ if self.is_valid(): return Region(self.to_point(view)) return None
def run(self, edit): # Select all the text in the current document text = self.view.substr(Region(0, self.view.size())) # Write that RST text as HTML html = rst_to_html(text) render_in_browser(html)
def to_visual(self): if self.is_direction_down(): a = self.begin() b = self.end() else: a = self.end() b = self.begin() return Region(a, b)
def restore_cursors(view): # I have no idea why I need to do this, but if I don't, after this # command has finished executing, the view will be in a state where # the indentation we just added is selected. ends = [region.end() for region in view.sel()] view.sel().clear() for end in ends: view.sel().add(Region(end, end))
def run(self, edit, symlist=None, symkeys=None, path=None, to_expand=None, toggle=None): self.view.erase(edit, Region(0, self.view.size())) if symlist and self.view.settings().get('outline_alphabetical'): symlist, symkeys = (list(t) for t in zip(*sorted(zip(symlist, symkeys)))) self.view.insert(edit, 0, "\n".join(symlist)) self.view.settings().set('symlist', symlist) self.view.settings().set('symkeys', symkeys) self.view.settings().set('current_file', path) self.view.sel().clear()
def toggle_word(self, view, region, words_dict, cursorPos=-1): editor_word = self.view.substr(region) toggle_groups = words_dict for toggle_group in toggle_groups: toggle_group_word_count = len(toggle_group) toggle_group.sort(key=len, reverse=True) for cur_word in range(0,toggle_group_word_count): next_word = (cur_word+1) % toggle_group_word_count if cursorPos != -1: #selected == false lineRegion = self.view.line(region) line = self.view.substr(lineRegion) lineBegin = lineRegion.a for line_finding in re.finditer(re.escape(toggle_group[cur_word]), line, flags=re.IGNORECASE): lf_a = line_finding.span()[0] lf_b = line_finding.span()[1] finding_region = Region(lineBegin + lf_a, lineBegin + lf_b) if finding_region.contains(cursorPos): editor_word = self.view.substr(finding_region) region = finding_region if editor_word == toggle_group[cur_word]: self.view.replace(view, region, toggle_group[next_word]) return if editor_word == toggle_group[cur_word].lower(): self.view.replace(view, region, toggle_group[next_word].lower()) return if editor_word == toggle_group[cur_word].capitalize(): self.view.replace(view, region, toggle_group[next_word].capitalize()) return if editor_word == toggle_group[cur_word].upper(): self.view.replace(view, region, toggle_group[next_word].upper()) return # Word not found? Show message sublime.status_message( "{0}: Can't find toggles for '{1}'".format(PLUGIN_NAME, editor_word) )
def run(self, edit): v = self.view if v.sel()[0].size() == 0: v.run_command("expand_selection", {"to": "word"}) cur_start = v.sel()[0].begin() cur_end = v.sel()[0].end() for sel in v.sel(): text = v.substr(sel) res = self.matcher(text) if not res: #first check one character to the left to see if its a symbol sel = Region(sel.begin() - 1, sel.end()) text = v.substr(sel) res = self.matcher(text) if not res: #now expand selection one character to the right to see if its a string sel = Region(sel.begin(), sel.end() + 1) text = v.substr(sel) res = self.matcher(text) if not res: #this is a mute point continue self.replacer(v, edit, sel, text, res) v.sel().clear() v.sel().add(Region(cur_start, cur_end))
def run(self, edit, forward=None): assert forward in (True, False), 'forward must be set to True or False' count = self.view.settings().get('dired_project_count', 0) files = Region(self.view.text_point(3, 0), self.view.text_point(count+3-1, 0)) if files.empty(): return pt = self.view.sel()[0].a if files.contains(pt): # Try moving by one line. line = self.view.line(pt) pt = forward and (line.b + 1) or (line.a - 1) if not files.contains(pt): # Not (or no longer) in the list of files, so move to the closest edge. pt = (pt > files.b) and files.b or files.a # print(pt) line = self.view.line(pt) self.view.sel().clear() self.view.sel().add(Region(line.a, line.a))
def run(self, edit): v = self.view if v.sel()[0].size() == 0: v.run_command("expand_selection", {"to": "scope"}) for sel in v.sel(): text = v.substr(sel) res = re_quotes.match(text) if not res: # the current selection doesn't begin and end with a quote. # let's expand the selection one character each direction and try again sel = Region(sel.begin() - 1, sel.end() + 1) text = v.substr(sel) res = re_quotes.match(text) if not res: # still no match... skip it! continue oldQuotes = res.group(1) newQuotes = "'" if oldQuotes == '"' else '"' text = res.group(2) text = string.replace(text, newQuotes, "\\" + newQuotes) text = string.replace(text, "\\" + oldQuotes, oldQuotes) text = newQuotes + text + newQuotes v.replace(edit, sel, text)
def run_each(self, edit, region, braces="{}", pressed=None, unindent=False, select=False, replace=False): """ Options: braces a list of matching braces or a string containing the pair pressed the key pressed; used for closing vs opening logic unindent removes one "tab" from a newline. true for braces that handle indent, like {} select whether to select the region inside the braces replace whether to insert new braces where the old braces were """ if self.view.settings().get("translate_tabs_to_spaces"): tab = " " * self.view.settings().get("tab_size") else: tab = "\t" row, col = self.view.rowcol(region.begin()) indent_point = self.view.text_point(row, 0) if indent_point < region.begin(): indent = self.view.substr(Region(indent_point, region.begin())) indent = re.match("[ \t]*", indent).group(0) else: indent = "" line = self.view.substr(self.view.line(region.a)) selection = self.view.substr(region) # for braces that have newlines ("""), insert the current line's indent if isinstance(braces, list): l_brace = braces[0] r_brace = braces[1] braces = "".join(braces) braces = braces.replace("\n", "\n" + indent) length = len(l_brace) else: braces = braces.replace("\n", "\n" + indent) length = len(braces) // 2 l_brace = braces[:length] r_brace = braces[length:] if region.empty(): after = self.view.substr(Region(region.a, region.a + length)) insert_braces = braces complicated_check = self.complicated_quote_checker(insert_braces, region, pressed, after, r_brace) if complicated_check: insert_braces = complicated_check elif ( pressed and after == r_brace and r_brace[-1] == pressed ): # and (pressed not in QUOTING_BRACKETS or in_string_scope): # in this case we pressed the closing character, and that's the character that is to the right # so do nothing except advance cursor position insert_braces = False elif unindent and row > 0 and indent and line == indent: # indent has the current line's indent # get previous line's indent: prev_point = self.view.text_point(row - 1, 0) prev_line = self.view.line(prev_point) prev_indent = self.view.substr(prev_line) prev_indent = re.match("[ \t]*", prev_indent).group(0) if ( (not pressed or pressed == l_brace) and len(indent) > len(prev_indent) and indent[len(prev_indent) :] == tab ): # move region.a back by 'indent' amount region = Region(region.a - len(tab), region.b - len(tab)) # and remove the tab self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), "") elif pressed and pressed == r_brace: if len(indent) == len(prev_indent): # move region.a back by 'indent' amount region = Region(region.a - len(tab), region.b - len(tab)) # and remove the tab self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), "") insert_braces = r_brace elif pressed and pressed != l_brace: # we pressed the closing bracket or quote. This *never* insert_braces = r_brace if insert_braces: self.view.insert(edit, region.a, insert_braces) self.view.sel().add(Region(region.a + length, region.a + length)) elif selection in QUOTING_BRACKETS and pressed in QUOTING_BRACKETS and selection != pressed: # changing a quote from single <=> double, just insert the quote. self.view.replace(edit, region, pressed) self.view.sel().add(Region(region.end(), region.end())) elif pressed and pressed != l_brace: b = region.begin() + len(r_brace) self.view.replace(edit, region, r_brace) self.view.sel().add(Region(b, b)) else: substitute = self.view.substr(region) replacement = l_brace + substitute + r_brace # if we're inserting "real" brackets, not quotes: real_brackets = l_brace in OPENING_BRACKETS and r_brace in CLOSING_BRACKETS # check to see if entire lines are selected, and if so do some smart indenting # bol_is_nl => allman style {} # bol_at_nl => kernigan&ritchie if region.begin() == 0: bol_is_nl = True bol_at_nl = False elif len(self.view) == region.begin() + 1: bol_is_nl = False bol_at_nl = False else: bol_is_nl = self.view.substr(region.begin() - 1) == "\n" bol_at_nl = ( l_brace == "{" and self.view.substr(region.begin()) == "\n" and self.view.substr(region.begin() - 1) != "\n" ) eol_is_nl = region.end() == self.view.size() or self.view.substr(region.end()) == "\n" eol_at_nl = self.view.substr(region.end() - 1) == "\n" if eol_is_nl: eol_is_nl = self.view.line(region.begin()) != self.view.line(region.end()) if real_brackets and (bol_is_nl or bol_at_nl) and (eol_is_nl or eol_at_nl): indent = "" if bol_at_nl and substitute: substitute = substitute[1:] m = re.match("([ \t]*)" + tab, substitute) if m: indent = m.group(1) else: substitute = tab + substitute b = region.begin() - len("\n" + indent + r_brace) if bol_at_nl: replacement = l_brace + "\n" + substitute if eol_at_nl: replacement += indent + r_brace + "\n" b -= 1 else: replacement += r_brace + "\n" b += len(indent) if not self.view.substr(region.begin() - 1) == " ": replacement = " " + replacement else: replacement = indent + l_brace + "\n" + substitute + indent + r_brace + "\n" b -= 1 b += len(replacement) else: b = region.begin() + len(replacement) if ( replace and self.view.substr(region.begin() - 1) in OPENING_BRACKET_LIKE and self.view.substr(region.end()) in CLOSING_BRACKET_LIKE ): b -= 1 self.view.replace(edit, Region(region.begin() - 1, region.end() + 1), replacement) elif ( replace and self.view.substr(region.begin()) in OPENING_BRACKET_LIKE and self.view.substr(region.end() - 1) in CLOSING_BRACKET_LIKE ): replacement = l_brace + replacement[2:-2] + r_brace b -= 2 self.view.replace(edit, region, replacement) l_brace = r_brace = "" else: self.view.replace(edit, region, replacement) if select: self.view.sel().add(Region(b - len(replacement) + len(l_brace), b - len(r_brace))) else: self.view.sel().add(Region(b, b))
def key_function(self, region: sublime.Region) -> Callable[[int], int]: return lambda i: -abs(self.matches[i][0] - region.begin())
def run_each(self, edit, region, braces='{}', pressed=None, unindent=False, select=False, replace=False): self.view.sel().subtract(region) if self.view.settings().get('translate_tabs_to_spaces'): tab = ' ' * self.view.settings().get('tab_size') else: tab = "\t" row, col = self.view.rowcol(region.begin()) indent_point = self.view.text_point(row, 0) if indent_point < region.begin(): indent = self.view.substr(Region(indent_point, region.begin())) indent = re.match('[ \t]*', indent).group(0) else: indent = '' line = self.view.substr(self.view.line(region.a)) selection = self.view.substr(region) # for braces that have newlines ("""), insert the current line's indent braces = braces.replace("\n", "\n" + indent) length = len(braces) / 2 l_brace = braces[:length] r_brace = braces[length:] if region.empty(): after = self.view.substr(Region(region.a, region.a + length)) insert_braces = braces complicated_check = self.complicated_quote_checker(insert_braces, region, pressed, after, r_brace) if complicated_check: insert_braces = complicated_check elif pressed and after == r_brace and r_brace[-1] == pressed: # and (pressed not in QUOTING_BRACKETS or in_string_scope): # in this case we pressed the closing character, and that's the character that is to the right # so do nothing except advance cursor position insert_braces = False elif unindent and row > 0 and indent and line == indent: # indent has the current line's indent # get previous line's indent: prev_point = self.view.text_point(row - 1, 0) prev_line = self.view.line(prev_point) prev_indent = self.view.substr(prev_line) prev_indent = re.match('[ \t]*', prev_indent).group(0) if (not pressed or pressed == l_brace) and len(indent) > len(prev_indent) and indent[len(prev_indent):] == tab: # move region.a back by 'indent' amount region = Region(region.a - len(tab), region.b - len(tab)) # and remove the tab self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), '') elif pressed and pressed == r_brace: if len(indent) == len(prev_indent): # move region.a back by 'indent' amount region = Region(region.a - len(tab), region.b - len(tab)) # and remove the tab self.view.replace(edit, Region(region.a, region.a + len(tab) - 1), '') insert_braces = r_brace elif pressed and pressed != l_brace: # we pressed the closing bracket or quote. This *never* insert_braces = r_brace if insert_braces: self.view.insert(edit, region.a, insert_braces) self.view.sel().add(Region(region.a + length, region.a + length)) elif selection in QUOTING_BRACKETS and pressed in QUOTING_BRACKETS and selection != pressed: # changing a quote from single <=> double, just insert the quote. self.view.replace(edit, region, pressed) self.view.sel().add(Region(region.end(), region.end())) elif pressed and pressed != l_brace: b = region.begin() + len(r_brace) self.view.replace(edit, region, r_brace) self.view.sel().add(Region(b, b)) else: substitute = self.view.substr(region) replacement = l_brace + substitute + r_brace # if we're inserting "real" brackets, not quotes: real_brackets = l_brace in OPENING_BRACKETS and r_brace in CLOSING_BRACKETS # check to see if entire lines are selected, and if so do some smart indenting bol_is_nl = region.begin() == 0 or self.view.substr(region.begin() - 1) == "\n" eol_is_nl = region.end() == self.view.size() - 1 or self.view.substr(region.end() - 1) == "\n" if real_brackets and bol_is_nl and eol_is_nl: indent = '' final = '' m = re.match('([ \t]*)' + tab, self.view.substr(region)) if m: indent = m.group(1) final = "\n" else: substitute = tab + substitute replacement = indent + l_brace + "\n" + substitute + indent + r_brace + final b = region.begin() + len(replacement) - len("\n" + indent + r_brace + final) else: b = region.begin() + len(replacement) if replace and self.view.substr(region.begin() - 1) in OPENING_BRACKET_LIKE and self.view.substr(region.end()) in CLOSING_BRACKET_LIKE: b -= 1 self.view.replace(edit, Region(region.begin() - 1, region.end() + 1), replacement) elif replace and self.view.substr(region.begin()) in OPENING_BRACKET_LIKE and self.view.substr(region.end() - 1) in CLOSING_BRACKET_LIKE: replacement = l_brace + replacement[2:-2] + r_brace b -= 2 self.view.replace(edit, region, replacement) l_brace = r_brace = '' else: self.view.replace(edit, region, replacement) if select: self.view.sel().add(Region(b - len(replacement) + len(l_brace), b - len(r_brace))) else: self.view.sel().add(Region(b, b))
def uncomment_region(view, edit, region): begin = region.begin() end = region.end() - 1 # We will loop backwards, this means that it will hit the closing # punctuation for block comments first. i = end + 1 while i > begin: i -= 1 scopes = view.scope_name(i) # Not a punctuation, ignore it. if 'punctuation.definition.comment' not in scopes: continue # Found the second forward slash for the “// ” comment. if 'comment.line' in scopes: punctuation_region = generate_comment_punctuation_region(view, i) view.erase(edit, punctuation_region) i = punctuation_region.begin() continue # We found the beginning of the block comment first, this means that # there’s no end to it and we can easily remove it. It can be “/* ”, # “/** ”, “{/* ” or “{/** ”. if 'punctuation.definition.comment.begin' in scopes: punctuation_region = generate_jsjsx_comment_punctuation_region( view, i ) view.erase(edit, punctuation_region) i = punctuation_region.begin() continue # We are looping backwards, so it is expected to find the closing # punctuation first which can be “ */” or “ */}”. possible_jsx_comment = False if i < view.size() and is_jsx_close_brace(view, i + 1): possible_jsx_comment = True closing_punctuation_region = generate_comment_punctuation_region( view, i ) # Move the cursor 1 character after the beginning punctuation. i = scan_reverse(view, i, not_predicate(has_scope_predicate( 'punctuation.definition.comment.begin' ))) open_punctuation_region = generate_comment_punctuation_region( view, i - 1 ) # Correct the regions to include the JSX braces if necessary. if possible_jsx_comment: if is_jsx_open_brace(view, open_punctuation_region.begin() - 1): open_punctuation_region = Region( open_punctuation_region.begin() - 1, open_punctuation_region.end() ) closing_punctuation_region = Region( closing_punctuation_region.begin(), closing_punctuation_region.end() + 1 ) view.erase(edit, closing_punctuation_region) view.erase(edit, open_punctuation_region) # Move the cursor to the beginning of the block to “consume” it. i = open_punctuation_region.begin()
def __init__(self, a, b, parent, folded=False): Region.__init__(self, a, b) self._parent = parent self._is_folded = folded