def run(self, edit, range=".", pattern=""): range = range or "." # we either accept a full pattern plus flags and count arg # ... or ... # simply a command in the following forms: # :s # :s gi # :s gi 10 # :s 10 try: sep, left, _, right, _, flags, count = ExSubstitute.parts_rgex.search(pattern).groups() ExSubstitute.last_pattern = (left, right) ExSubstitute.last_flags = flags except AttributeError: if not ExSubstitute.last_pattern: sublime.status_message("VintageEx: No pattern available.") return left, _, right = pattern.strip().partition(" ") flags, count = "", None if left and left.strip().isalpha(): flags = left if right and right.isdigit(): count = int(right) elif right: sublime.status_message("VintageEx: Bad pattern.") return elif left and left.strip().isdigit(): count = int(left) if flags or count: pattern = "" if not pattern: left, right = ExSubstitute.last_pattern re_flags = 0 re_flags |= re.IGNORECASE if (flags and "i" in flags) else 0 left = re.compile(left, flags=re_flags) if count and range == ".": range = ".,.+%d" % int(count) elif count: a, b = ex_range.calculate_range(self.view, range) if not a and b: b = max(a, b) range = "%d,%d+%d" % (b, b, int(count)) target_region = get_region_by_range(self.view, range) replace_count = 0 if (flags and "g" in flags) else 1 for r in reversed(target_region): # be explicit about replacing the line, because we might be looking # at a Ctrl+D sequence of regions (not spanning a whole line) # TODO: Improve this: make sure view.line() doesn't extend past # the desired line. For example, in VISUAL LINE MODE. if self.view.substr(r.end() - 1) == "\n": r = sublime.Region(r.begin(), r.end() - 1) line_text = self.view.substr(self.view.line(r)) rv = re.sub(left, right, line_text, count=replace_count) self.view.replace(edit, self.view.line(r), rv)
def run(self, edit, range=''): if not range: # No-op: user issued ":". return a, b = ex_range.calculate_range(self.view, range, is_only_range=True) self.view.run_command('vi_goto_line', {'repeat': b}) self.view.show(self.view.sel()[0])
def run(self, edit, range=''): if not range: # No-op: user issued ":". return a, b = ex_range.calculate_range(self.view, range, is_only_range=True)[0] self.view.run_command('vi_goto_line', {'repeat': b}) self.view.show(self.view.sel()[0])
def run(self, edit, range='.', pattern=''): range = range or '.' # we either accept a full pattern plus flags and count arg # ... or ... # simply a command in the following forms: # :s # :s gi # :s gi 10 # :s 10 try: sep, left, _, right, _, flags, count = \ ExSubstitute.parts_rgex.search(pattern).groups() ExSubstitute.last_pattern = (left, right) ExSubstitute.last_flags = flags except AttributeError: if not ExSubstitute.last_pattern: sublime.status_message("VintageEx: No pattern available.") return left, _, right = pattern.strip().partition(' ') flags, count = '', None if left and left.strip().isalpha(): flags = left if right and right.isdigit(): count = int(right) elif right: sublime.status_message('VintageEx: Bad pattern.') return elif left and left.strip().isdigit(): count = int(left) if flags or count: pattern = '' if not pattern: left, right = ExSubstitute.last_pattern re_flags = 0 re_flags |= re.IGNORECASE if (flags and 'i' in flags) else 0 left = re.compile(left, flags=re_flags) if count and range == '.': range = '.,.+%d' % int(count) elif count: a, b = ex_range.calculate_range(self.view, range) if not a and b: b = max(a, b) range = "%d,%d+%d" % (b, b, int(count)) target_region = get_region_by_range(self.view, range) replace_count = 0 if (flags and 'g' in flags) else 1 for r in reversed(target_region): # be explicit about replacing the line, because we might be looking # at a Ctrl+D sequence of regions (not spanning a whole line) line_text = self.view.substr(self.view.line(r)) rv = re.sub(left, right, line_text, count=replace_count) self.view.replace(edit, self.view.line(r), rv)
def testCalculateCorrectRange(self): values = ( (calculate_range(g_test_view, '0'), [(0, 0)]), (calculate_range(g_test_view, '1'), [(1, 1)]), (calculate_range(g_test_view, '1,1'), [(1, 1)]), (calculate_range(g_test_view, '%,1'), [(1, 538)]), (calculate_range(g_test_view, '1,%'), [(1, 538)]), (calculate_range(g_test_view, '1+99,160-10'), [(100, 150)]), (calculate_range(g_test_view, '/THIRTY/+10,100'), [(40, 100)]), ) select_line(g_test_view, 31) values += ( (calculate_range(g_test_view, '10,/THIRTY/'), [(10, 31)]), (calculate_range(g_test_view, '10;/THIRTY/'), [(10, 30)]), ) for actual, expected in values: self.assertEquals(actual, expected)
def compute_address(view, text_range): """Computes a single-line address based on ``text_range``, which is a string that should be a valid Vi(m) address. Return values: - SUCCESS: address (positive integer) - ERROR: -1 (can't compute valid address) """ # xxx strip in the parsing phase instead text_range = text_range.strip() # Note that some address error checking is also performed at the parsing # stage, so that '%' doesn't reach here, for example. a, b = ex_range.calculate_range(view, text_range.strip()) address = (max(a, b) if all((a, b)) else (a or b)) or 0 return address - 1
def get_region_by_range(view, text_range, split_visual=False): # If GLOBAL_RANGES exists, the ExGlobal command has been run right before # the current command, and we know we must process these lines. # XXX move this further down into the range parsing? global GLOBAL_RANGES if GLOBAL_RANGES: rv = GLOBAL_RANGES[:] GLOBAL_RANGES = [] return rv regions = ex_range.calculate_range(view, text_range) lines = [] for region in regions: a, b = region r = sublime.Region(view.text_point(a - 1, 0), view.full_line(view.text_point(b - 1, 0)).end()) lines.extend(view.split_by_newlines(r)) return lines
def run(self, edit, range='', name='', plusplus_args='', forced=False): target_line = self.view.line(self.view.sel()[0].begin()) if range: range = max(ex_range.calculate_range(self.view, range)[0]) target_line = self.view.line(self.view.text_point(range, 0)) target_point = min(target_line.b + 1, self.view.size()) # cheat a little bit to get the parsing right: # - forced == True means we need to execute a command if forced: if sublime.platform() == 'linux': for s in self.view.sel(): the_shell = os.path.expandvars("$SHELL") p = subprocess.Popen([the_shell, '-c', name], stdout=subprocess.PIPE) self.view.insert(edit, s.begin(), p.communicate()[0][:-1]) elif sublime.platform() == 'windows': for s in self.view.sel(): p = subprocess.Popen(['cmd.exe', '/C', name], stdout=subprocess.PIPE, startupinfo=get_startup_info() ) cp = 'cp' + get_oem_cp() rv = p.communicate()[0].decode(cp)[:-2].strip() self.view.insert(edit, s.begin(), rv) else: ex_error.handle_not_implemented() # Read a file into the current view. else: # Read the current buffer's contents and insert below current line. if not name: new_contents = self.view.substr( sublime.Region(0, self.view.size())) if self.view.substr(target_line.b) != '\n': new_contents = '\n' + new_contents self.view.insert(edit, target_point, new_contents) return # XXX read file "name" # we need proper filesystem autocompletion here else: ex_error.handle_not_implemented() return
def get_region_by_range(view, text_range, split_visual=False): # xxx move this further down into the range parsing? global GLOBAL_RANGES if GLOBAL_RANGES: rv = GLOBAL_RANGES[:] GLOBAL_RANGES = [] return rv if text_range.replace(" ", "") == "'<,'>": if not split_visual: return list(view.sel()) else: rv = [] for r in list(view.sel()): rv.extend(view.split_by_newlines(r)) return rv a, b = ex_range.calculate_range(view, text_range) r = sublime.Region(view.text_point(a - 1, 0), view.full_line(view.text_point(b - 1, 0)).end()) return view.split_by_newlines(r)
def get_region_by_range(view, text_range, split_visual=False): # xxx move this further down into the range parsing? global GLOBAL_RANGES if GLOBAL_RANGES: rv = GLOBAL_RANGES[:] GLOBAL_RANGES = [] return rv if text_range.replace(' ', '') == "'<,'>": if not split_visual: return list(view.sel()) else: rv = [] for r in list(view.sel()): rv.extend(view.split_by_newlines(r)) return rv a, b = ex_range.calculate_range(view, text_range) r = sublime.Region(view.text_point(a - 1, 0), view.full_line(view.text_point(b - 1, 0)).end()) return view.split_by_newlines(r)
def get_region_by_range(view, text_range, split_visual=False): # If GLOBAL_RANGES exists, the ExGlobal command has been run right before # the current command, and we know we must process these lines. # XXX move this further down into the range parsing? global GLOBAL_RANGES if GLOBAL_RANGES: rv = GLOBAL_RANGES[:] GLOBAL_RANGES = [] return rv if text_range.replace(" ", "") == "'<,'>": if not split_visual: return list(view.sel()) else: rv = [] for r in list(view.sel()): rv.extend(view.split_by_newlines(r)) return rv a, b = ex_range.calculate_range(view, text_range) r = sublime.Region(view.text_point(a - 1, 0), view.full_line(view.text_point(b - 1, 0)).end()) return view.split_by_newlines(r)
def get_region_by_range(view, text_range, split_visual=False): # If GLOBAL_RANGES exists, the ExGlobal command has been run right before # the current command, and we know we must process these lines. # XXX move this further down into the range parsing? global GLOBAL_RANGES if GLOBAL_RANGES: rv = GLOBAL_RANGES[:] GLOBAL_RANGES = [] return rv if text_range.replace(' ', '') == "'<,'>": if not split_visual: return list(view.sel()) else: rv = [] for r in list(view.sel()): rv.extend(view.split_by_newlines(r)) return rv a, b = ex_range.calculate_range(view, text_range) r = sublime.Region(view.text_point(a - 1, 0), view.full_line(view.text_point(b - 1, 0)).end()) return view.split_by_newlines(r)
def run(self, edit, range=""): assert range, "Range required." a, b = ex_range.calculate_range(self.view, range, is_only_range=True) target = (max(a, b) if all((a, b)) else (a or b)) or 0 self.view.run_command("vi_goto_line", {"repeat": target}) self.view.show(self.view.sel()[0])
ExSubstitute.most_recent_replacement = replacement ExSubstitute.most_recent_flags = flags computed_flags = 0 computed_flags |= re.IGNORECASE if (flags and 'i' in flags) else 0 try: pattern = re.compile(pattern, flags=computed_flags) except Exception, e: sublime.status_message("VintageEx [regex error]: %s ... in pattern '%s'" % (e.message, pattern)) print "VintageEx [regex error]: %s ... in pattern '%s'" % (e.message, pattern) return if count and range == '.': range = '.,.+%d' % int(count) elif count: a, b = ex_range.calculate_range(self.view, range)[0] if not a and b: b = max(a, b) range = "%d,%d+%d" % (b, b, int(count)) target_region = get_region_by_range(self.view, range) replace_count = 0 if (flags and 'g' in flags) else 1 for r in reversed(target_region): # be explicit about replacing the line, because we might be looking # at a Ctrl+D sequence of regions (not spanning a whole line) # TODO: Improve this: make sure view.line() doesn't extend past # the desired line. For example, in VISUAL LINE MODE. if self.view.substr(r.end() - 1) == '\n': r = sublime.Region(r.begin(), r.end() - 1) line_text = self.view.substr(self.view.line(r)) rv = re.sub(pattern, replacement, line_text, count=replace_count)
computed_flags = 0 computed_flags |= re.IGNORECASE if (flags and 'i' in flags) else 0 try: pattern = re.compile(pattern, flags=computed_flags) except Exception, e: sublime.status_message( "VintageEx [regex error]: %s ... in pattern '%s'" % (e.message, pattern)) print "VintageEx [regex error]: %s ... in pattern '%s'" % ( e.message, pattern) return if count and range == '.': range = '.,.+%d' % int(count) elif count: a, b = ex_range.calculate_range(self.view, range)[0] if not a and b: b = max(a, b) range = "%d,%d+%d" % (b, b, int(count)) target_region = get_region_by_range(self.view, range) replace_count = 0 if (flags and 'g' in flags) else 1 for r in reversed(target_region): # be explicit about replacing the line, because we might be looking # at a Ctrl+D sequence of regions (not spanning a whole line) # TODO: Improve this: make sure view.line() doesn't extend past # the desired line. For example, in VISUAL LINE MODE. if self.view.substr(r.end() - 1) == '\n': r = sublime.Region(r.begin(), r.end() - 1) line_text = self.view.substr(self.view.line(r)) rv = re.sub(pattern, replacement, line_text, count=replace_count)
def run(self, edit, range=''): assert range, 'Range required.' a, b = ex_range.calculate_range(self.view, range, is_only_range=True) target = (max(a, b) if all((a, b)) else (a or b)) or 0 self.view.run_command('vi_goto_line', {'repeat': target}) self.view.show(self.view.sel()[0])