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 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): 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(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_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 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 key_function(self, region: sublime.Region) -> Callable[[int], int]: return lambda i: -abs(self.matches[i][0] - region.begin())
def __init__(self, a, b, parent, folded=False): Region.__init__(self, a, b) self._parent = parent self._is_folded = folded
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()