def on_done(self, idx): """Save selected value to `"` register.""" if idx == -1: return state = State(self.view) value = list(state.registers.to_dict().values())[idx] state.registers['"'] = value
def setUp(self): super().setUp() sublime.set_clipboard('') registers._REGISTER_DATA = {} self.view.settings().erase('vintage') self.view.settings().erase('vintageous_use_sys_clipboard') self.regs = State(self.view).registers self.regs.view = mock.Mock()
def run(self, key=None): state = State(self.window.active_view()) state.motion = cmd_defs[state.mode][cmds.QUESTION_MARK_IMPL] state.last_buffer_search = state.user_input or state.last_buffer_search # XXX: Is this right? if state.input_parsers: new_parsers = state.input_parsers new_parsers.pop() state.input_parsers = new_parsers
def setUp(self): super().setUp() sublime.set_clipboard('') registers._REGISTER_DATA = {} self.view.settings().erase('vintage') self.view.settings().erase('vintageous_use_sys_clipboard') # self.regs = Registers(view=self.view, # settings=SettingsManager(view=self.view)) self.regs = State(self.view).registers
def run(self, edit, line_range, register=None, count=None): if not register: register = '"' regs = get_region_by_range(self.view, line_range) text = '\n'.join([self.view.substr(line) for line in regs]) + '\n' state = State(self.view) state.registers[register] = [text] if register == '"': state.registers['0'] = [text]
def testFromVisualModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 1))) state = State(self.view) state.enter_visual_mode() prev_mode = state.mode self.view.run_command('ex_move', {'command_line': 'move3'}) state = State(self.view) new_mode = state.mode self.assertNotEqual(prev_mode, new_mode)
def testFromVisualModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 1))) state = State(self.view) state.enter_visual_mode() prev_mode = state.mode self.view.run_command('ex_copy', {'address': '3'}) state = State(self.view) new_mode = state.mode self.assertNotEqual(prev_mode, new_mode) self.assertEqual(new_mode, modes.NORMAL)
def select(self, regions, register): self.view.sel().clear() to_store = [] for r in regions: self.view.sel().add(r) if register: to_store.append(self.view.substr(self.view.full_line(r))) if register: text = ''.join(to_store) if not text.endswith('\n'): text = text + '\n' state = State(self.view) state.registers[register] = [text]
def testCaretEndsInExpectedRegion(self): self.write(''.join(('foo bar\nfoo bar\nfoo bar\n',))) self.clear_sel() self.add_sel(self.R((1, 3), (1, 0))) state = State(self.view) state.enter_visual_mode() # TODO: we should bypass vi_r and define the values directly. data = CmdData(state) # data = vi_r(data) data['action']['args']['character'] = 'X' self.view.run_command('vi_run', data) self.assertEqual(self.R((1, 0), (1, 0)), first_sel(self.view))
def testFromNormalModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 0))) state = State(self.view) state.enter_normal_mode() self.view.run_command('vi_enter_normal_mode') prev_mode = state.mode self.view.run_command('ex_move', {'address': '3'}) state = State(self.view) new_mode = state.mode self.assertEqual(prev_mode, new_mode)
def testCaretEndsInExpectedRegion(self): self.write("".join(("foo bar\nfoo bar\nfoo bar\n",))) self.clear_sel() self.add_sel(self.R((1, 3), (1, 0))) state = State(self.view) state.enter_visual_mode() # TODO: we should bypass vi_r and define the values directly. data = CmdData(state) # data = vi_r(data) data["action"]["args"]["character"] = "X" self.view.run_command("vi_run", data) self.assertEqual(self.R((1, 0), (1, 0)), first_sel(self.view))
def resolve_mark(self, view, token): if token.content == '<': sel = list(view.sel())[0] view.sel().clear() view.sel().add(sel) if sel.a < sel.b: return row_at(view, sel.a) else: return row_at(view, sel.a - 1) if token.content == '>': sel = list(view.sel())[0] view.sel().clear() view.sel().add(sel) if sel.a < sel.b: return row_at(view, sel.b - 1) else: return row_at(view, sel.b) st = State(view) rg = st.marks.get_as_encoded_address(token.content) if (isinstance(rg, sublime.Region)): return view.rowcol(rg.begin())[0] raise NotImplementedError()
def run(self, path=None, forced=False): if self.view.is_dirty() and not forced: ex_error.display_error(ex_error.ERR_UNSAVED_CHANGES) return state = State(self.view) if not path: state.settings.vi['_cmdline_cd'] = os.path.expanduser("~") self.view.run_command('ex_print_working_dir') return # TODO: It seems there a few symbols that are always substituted when they represent a # filename. We should have a global method of substiting them. if path == '%:h': fname = self.view.file_name() if fname: state.settings.vi['_cmdline_cd'] = os.path.dirname(fname) self.view.run_command('ex_print_working_dir') return path = os.path.realpath(os.path.expandvars(os.path.expanduser(path))) if not os.path.exists(path): # TODO: Add error number in ex_error.py. ex_error.display_error(ex_error.ERR_CANT_FIND_DIR_IN_CDPATH) return state.settings.vi['_cmdline_cd'] = path self.view.run_command('ex_print_working_dir')
def inner(*args, **kwargs): try: state = State(args[0].view) except AttributeError: state = State(args[0].window.active_view()) old = os.getcwd() try: # FIXME: Under some circumstances, like when switching projects to # a file whose _cmdline_cd has not been set, _cmdline_cd might # return 'None'. In such cases, change to the actual current # directory as a last measure. (We should probably fix this anyway). os.chdir(state.settings.vi['_cmdline_cd'] or old) f(*args, **kwargs) finally: os.chdir(old)
def testCaretEndsInExpectedRegion(self): self.write(''.join(('foo bar\nfoo bar\nfoo bar\n', ))) self.clear_sel() self.add_sel(self.R((1, 3), (1, 0))) state = State(self.view) state.enter_visual_mode() # TODO: we should bypass vi_r and define the values directly. data = CmdData(state) # data = vi_r(data) data['action']['args']['character'] = 'X' self.view.run_command('vi_run', data) self.assertEqual(self.R((1, 0), (1, 0)), first_sel(self.view))
def run(self, edit, line_range=None): if not line_range['text_range']: # No-op: user issued ":". return ranges, _ = ex_range.new_calculate_range(self.view, line_range) a, b = ranges[0] # FIXME: This should be handled by the parser. # FIXME: In Vim, 0 seems to equal 1 in ranges. b = b if line_range['text_range'] != '0' else 1 state = State(self.view) # FIXME: In Visual mode, goto line does some weird stuff. if state.mode == MODE_NORMAL: # TODO: push all this code down to ViGoToLine? self.view.window().run_command('_vi_add_to_jump_list') self.view.run_command('_vi_go_to_line', { 'line': b, 'mode': state.mode }) self.view.window().run_command('_vi_add_to_jump_list') self.view.show(self.view.sel()[0]) elif state.mode in (MODE_VISUAL, MODE_VISUAL_LINE) and line_range['right_offset']: # TODO: push all this code down to ViGoToLine? self.view.window().run_command('_vi_add_to_jump_list') # FIXME: The parser fails with '<,'>100. 100 is not the right_offset, but an argument. b = self.view.rowcol(self.view.sel()[0].b - 1)[0] + line_range['right_offset'] + 1 self.view.run_command('_vi_go_to_line', { 'line': b, 'mode': state.mode }) self.view.window().run_command('_vi_add_to_jump_list') self.view.show(self.view.sel()[0])
def on_text_command(self, view, command, args): if command == 'drag_select': state = State(view) if state.mode in (modes.VISUAL, modes.VISUAL_LINE, modes.VISUAL_BLOCK): if (args.get('extend') or (args.get('by') == 'words') or args.get('additive')): return elif not args.get('extend'): return ('sequence', { 'commands': [['drag_select', args], ['_enter_normal_mode', { 'mode': state.mode }]] }) elif state.mode == modes.NORMAL: # TODO(guillermooo): Dragging the mouse does not seem to # fire a different event than simply clicking. This makes it # hard to update the xpos. if args.get('extend') or (args.get('by') == 'words'): return ('sequence', { 'commands': [['drag_select', args], ['_enter_visual_mode', { 'mode': state.mode }]] })
def run(self, edit, mode=None, count=None, cmd=''): mappings = Mappings(State(self.view)) try: mappings.remove(modes.VISUAL, cmd) mappings.remove(modes.VISUAL_LINE, cmd) mappings.remove(modes.VISUAL_BLOCK, cmd) except KeyError: sublime.status_message('Vintageous: Mapping not found.')
def testCaretEndsInExpectedRegion(self): self.write('foo bar\nfoo bar\nfoo bar\n') self.clear_sel() self.add_sel(self.R((1, 0), (1, 3))) State(self.view).mode = MODE_VISUAL self.view.run_command('_enter_normal_mode', {'mode': MODE_VISUAL}) self.assertEqual(self.R((1, 2), (1, 2)), first_sel(self.view))
def run(self, forced=False): if self.view.is_dirty() and not forced: ex_error.display_error(ex_error.ERR_UNSAVED_CHANGES) return path = os.path.dirname(self.view.file_name()) state = State(self.view) try: state.settings.vi['_cmdline_cd'] = path self.view.run_command('ex_print_working_dir') except IOError: ex_error.display_error(ex_error.ERR_CANT_FIND_DIR_IN_CDPATH)
def run(self, edit, mode=None, count=None, cmd=''): try: keys, command = cmd.lstrip().split(' ', 1) except ValueError: sublime.status_message('Vintageous: Bad mapping format') return else: mappings = Mappings(State(self.view)) mappings.add(modes.NORMAL, keys, command) mappings.add(modes.OPERATOR_PENDING, keys, command) mappings.add(modes.VISUAL, keys, command)
def run(self, initial_text=':', cmd_line=''): # non-interactive call if cmd_line: self.non_interactive = True self.on_done(cmd_line) return FsCompletion.invalidate() state = State(self.window.active_view()) if state.mode in (modes.VISUAL, modes.VISUAL_LINE): initial_text = ":'<,'>" + initial_text[1:] v = mark_as_widget(show_ipanel(self.window, initial_text=initial_text, on_done=self.on_done, on_change=self.on_change)) v.set_syntax_file('Packages/Vintageous/VintageousEx Cmdline.tmLanguage') v.settings().set('gutter', False) v.settings().set('rulers', []) state.reset_during_init = False
def run(self, edit, mode=None, count=None, cmd=''): try: # TODO(guillermooo): Instead of parsing this here, add parsers # to ex command defs and reuse them here. keys, command = cmd.lstrip().split(' ', 1) except ValueError: sublime.status_message('Vintageous: Bad mapping format') return else: mappings = Mappings(State(self.view)) mappings.add(modes.NORMAL, keys, command) mappings.add(modes.OPERATOR_PENDING, keys, command) mappings.add(modes.VISUAL, keys, command)
def run(self, edit): if self.view.score_selector(0, 'text.excmdline') == 0: return state = State(self.view) FsCompletion.frozen_dir = (FsCompletion.frozen_dir or (state.settings.vi['_cmdline_cd'] + '/')) cmd, prefix, only_dirs = parse(self.view.substr(self.view.line(0))) if not cmd: return if not (FsCompletion.prefix or FsCompletion.items) and prefix: FsCompletion.prefix = prefix FsCompletion.is_stale = True if prefix == '..': FsCompletion.prefix = '../' self.view.run_command('write_fs_completion', { 'cmd': cmd, 'completion': '../' }) if prefix == '~': path = os.path.expanduser(prefix) + '/' FsCompletion.prefix = path self.view.run_command('write_fs_completion', { 'cmd': cmd, 'completion': path }) return if (not FsCompletion.items) or FsCompletion.is_stale: FsCompletion.items = iter_paths(from_dir=FsCompletion.frozen_dir, prefix=FsCompletion.prefix, only_dirs=only_dirs) FsCompletion.is_stale = False try: self.view.run_command('write_fs_completion', { 'cmd': cmd, 'completion': next(FsCompletion.items) }) except StopIteration: FsCompletion.items = iter_paths(prefix=FsCompletion.prefix, from_dir=FsCompletion.frozen_dir, only_dirs=only_dirs) self.view.run_command('write_fs_completion', { 'cmd': cmd, 'completion': FsCompletion.prefix })
def run(self, initial_text=':', cmd_line=''): if cmd_line: # The caller has provided a command, to we're not in interactive # mode -- just run the command. ViColonInput.interactive_call = False self.on_done(cmd_line) return else: ViColonInput.interactive_call = True FsCompletion.invalidate() v = mark_as_widget(show_ipanel(self.window, initial_text=self.adjust_initial_text(initial_text), on_done=self.on_done, on_change=self.on_change)) v.set_syntax_file('Packages/Vintageous/VintageousEx Cmdline.tmLanguage') v.settings().set('gutter', False) v.settings().set('rulers', []) state = State(self.window.active_view()) state.reset_during_init = False
def run(self, initial_text=':', cmd_line=''): # non-interactive call if cmd_line: self.non_interactive = True self.on_done(cmd_line) return FsCompletion.invalidate() state = State(self.window.active_view()) if state.mode in (modes.VISUAL, modes.VISUAL_LINE): initial_text = ":'<,'>" + initial_text[1:] v = mark_as_widget( show_ipanel(self.window, initial_text=initial_text, on_done=self.on_done, on_change=self.on_change)) v.set_syntax_file( 'Packages/Vintageous/VintageousEx Cmdline.tmLanguage') v.settings().set('gutter', False) v.settings().set('rulers', []) state.reset_during_init = False
def run(self, edit): def show_lines(line_count): lines_display = '... [+{0}]'.format(line_count - 1) return lines_display if line_count > 1 else '' state = State(self.view) pairs = [(k, v) for (k, v) in state.registers.to_dict().items() if v] pairs = [(k, repr(v[0]), len(v)) for (k, v) in pairs] pairs = [ '"{0} {1} {2}'.format(k, v, show_lines(lines)) for (k, v, lines) in pairs ] self.view.window().show_quick_panel(pairs, self.on_done, flags=sublime.MONOSPACE_FONT)
def run(self, forced=False, file_name=None): if file_name: file_name = os.path.expanduser(os.path.expandvars(file_name)) if self.view.is_dirty() and not forced: ex_error.display_error(ex_error.ERR_UNSAVED_CHANGES) return file_name = os.path.expanduser(file_name) if os.path.isdir(file_name): sublime.status_message( 'Vintageous: "{0}" is a directory'.format(file_name)) return message = '' if not os.path.isabs(file_name): file_name = os.path.join( State(self.view).settings.vi['_cmdline_cd'], file_name) if not os.path.exists(file_name): message = '[New File]' path = os.path.dirname(file_name) if path and not os.path.exists(path): message = '[New DIRECTORY]' self.view.window().open_file(file_name) # TODO: Collect message and show at the end of the command. def show_message(): sublime.status_message('Vintageous: "{0}" {1}'.format( (file_name, message))) sublime.set_timeout(show_message, 250) return else: if forced or not self.view.is_dirty(): self.view.run_command('revert') return elif not file_name and self.view.is_dirty(): ex_error.display_error(ex_error.ERR_UNSAVED_CHANGES) return if forced or not self.view.is_dirty(): self.view.window().open_file(file_name) return ex_error.display_error(ex_error.ERR_UNSAVED_CHANGES)
def testFromVisualModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 1))) state = State(self.view) state.enter_visual_mode() prev_mode = state.mode self.view.run_command('ex_move', {'address': '3'}) state = State(self.view) new_mode = state.mode self.assertNotEqual(prev_mode, new_mode)
def testFromVisualModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 1))) state = State(self.view) state.enter_visual_mode() prev_mode = state.mode self.view.run_command('ex_copy', {'command_line': 'copy3'}) state = State(self.view) new_mode = state.mode self.assertNotEqual(prev_mode, new_mode) self.assertEqual(new_mode, modes.NORMAL)
def testFromNormalModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 0))) state = State(self.view) state.enter_normal_mode() self.view.run_command('vi_enter_normal_mode') prev_mode = state.mode self.view.run_command('ex_copy', {'address': '3'}) state = State(self.view) new_mode = state.mode self.assertEqual(prev_mode, new_mode, modes.NORMAL)
def testFromNormalModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 0))) state = State(self.view) state.enter_normal_mode() self.view.run_command('vi_enter_normal_mode') prev_mode = state.mode self.range['left_offset'] = 2 self.range['text_range'] = '2' self.view.run_command('ex_delete', {'line_range': self.range}) state = State(self.view) new_mode = state.mode self.assertEqual(prev_mode, new_mode)
def testFromVisualModeToNormalMode(self): self.write('abc\nxxx\nabc\nabc') self.clear_sel() self.add_sel(self.R((1, 0), (1, 1))) state = State(self.view) state.enter_visual_mode() prev_mode = state.mode self.range['left_ref'] = "'<" self.range['right_ref'] = "'>" self.range['text_range'] = "'<,'>" self.view.run_command('ex_delete', {'line_range': self.range}) state = State(self.view) new_mode = state.mode self.assertNotEqual(prev_mode, new_mode) self.assertEqual(new_mode, MODE_NORMAL)
def run(self, line_range=None, forced=False, file_name='', plusplus_args='', operator='', target_redirect='', subcmd=''): if file_name and target_redirect: sublime.status_message('Vintageous: Too many arguments.') return appending = operator == '>>' a_range = line_range['text_range'] self.view = self.window.active_view() content = get_region_by_range(self.view, line_range=line_range) if a_range else \ [sublime.Region(0, self.view.size())] read_only = False if self.view.file_name(): mode = os.stat(self.view.file_name()) read_only = (stat.S_IMODE(mode.st_mode) & stat.S_IWUSR != stat.S_IWUSR) if target_redirect: target = self.window.new_file() target.set_name(target_redirect) elif file_name: def report_error(msg): sublime.status_message('Vintageous: %s' % msg) file_path = os.path.abspath(os.path.expanduser(file_name)) if os.path.exists(file_path) and (file_path != self.view.file_name()): # TODO add w! flag # TODO: Hook this up with ex error handling (ex/errors.py). msg = "File '{0}' already exists.".format(file_path) report_error(msg) return if not os.path.exists(os.path.dirname(file_path)): msg = "Directory '{0}' does not exist.".format(os.path.dirname(file_path)) report_error(msg) return try: # FIXME: We need to do some work with encodings here, don't we? with open(file_path, 'w+') as temp_file: for frag in reversed(content): temp_file.write(self.view.substr(frag)) temp_file.close() sublime.status_message("Vintageous: Saved {0}".format(file_path)) row, col = self.view.rowcol(self.view.sel()[0].b) encoded_fn = "{0}:{1}:{2}".format(file_path, row + 1, col + 1) self.view.set_scratch(True) w = self.window w.run_command('close') w.open_file(encoded_fn, sublime.ENCODED_POSITION) return except IOError as e: report_error( "Failed to create file '%s'." % file_name ) return window = self.window window.open_file(file_path) return else: target = self.view if (read_only or self.view.is_read_only()) and not forced: utils.blink() sublime.status_message("Vintageous: Can't write read-only file.") return start = 0 if not appending else target.size() prefix = '\n' if appending and target.size() > 0 else '' if appending or target_redirect: for frag in reversed(content): target.run_command('append', {'characters': prefix + self.view.substr(frag) + '\n'}) elif a_range: start_deleting = 0 text = '' for frag in content: text += self.view.substr(frag) + '\n' start_deleting = len(text) self.view.run_command('ex_replace_file', {'start': 0, 'end': 0, 'with_what': text}) else: dirname = os.path.dirname(self.view.file_name()) if not os.path.exists(dirname): os.makedirs(dirname) self.window.run_command('save') # This may unluckily prevent the user from seeing ST's feedback about saving the current # file. state = State(self.window.active_view()) if state.mode != MODE_NORMAL: state.enter_normal_mode() self.window.run_command('vi_enter_normal_mode')
def state(self): return State(self.view)
class TestCaseRegisters(ViewTest): def setUp(self): super().setUp() sublime.set_clipboard('') registers._REGISTER_DATA = {} self.view.settings().erase('vintage') self.view.settings().erase('vintageous_use_sys_clipboard') # self.regs = Registers(view=self.view, # settings=SettingsManager(view=self.view)) self.regs = State(self.view).registers def testCanInitializeClass(self): self.assertEqual(self.regs.view, self.view) self.assertTrue(getattr(self.regs, 'settings')) def testCanSetUnanmedRegister(self): self.regs._set_default_register(["foo"]) self.assertEqual(registers._REGISTER_DATA[registers.REG_UNNAMED], ["foo"]) def testSettingLongRegisterNameThrowsAssertionError(self): self.assertRaises(AssertionError, self.regs.set, "aa", "foo") def testSettingNonListValueThrowsAssertionError(self): self.assertRaises(AssertionError, self.regs.set, "a", "foo") @unittest.skip("Not implemented.") def testUnknownRegisterNameThrowsException(self): # XXX Doesn't pass at the moment. self.assertRaises(Exception, self.regs.set, "~", "foo") def testRegisterDataIsAlwaysStoredAsString(self): self.regs.set('"', [100]) self.assertEqual(registers._REGISTER_DATA[registers.REG_UNNAMED], ["100"]) def testSettingBlackHoleRegisterDoesNothing(self): registers._REGISTER_DATA[registers.REG_UNNAMED] = ["bar"] # In this case it doesn't matter whether we're setting a list or not, # because we are discarding the value anyway. self.regs.set(registers.REG_BLACK_HOLE, "foo") self.assertTrue(registers.REG_BLACK_HOLE not in registers._REGISTER_DATA) self.assertTrue(registers._REGISTER_DATA[registers.REG_UNNAMED], ["bar"]) def testSettingExpressionRegisterDoesntPopulateUnnamedRegister(self): self.regs.set("=", [100]) self.assertTrue(registers.REG_UNNAMED not in registers._REGISTER_DATA) self.assertEqual(registers._REGISTER_DATA[registers.REG_EXPRESSION], ["100"]) def testCanSetNormalRegisters(self): for name in registers.REG_VALID_NAMES: self.regs.set(name, [name]) for number in registers.REG_VALID_NUMBERS: self.regs.set(number, [number]) for name in registers.REG_VALID_NAMES: self.assertEqual(registers._REGISTER_DATA[name], [name]) for number in registers.REG_VALID_NUMBERS: self.assertEqual(registers._REGISTER_DATA[number], [number]) def testSettingNormalRegisterSetsUnnamedRegisterToo(self): self.regs.set('a', [100]) self.assertEqual(registers._REGISTER_DATA[registers.REG_UNNAMED], ['100']) self.regs.set('0', [200]) self.assertEqual(registers._REGISTER_DATA[registers.REG_UNNAMED], ['200']) def testSettingRegisterSetsClipboardIfNeeded(self): self.regs.settings.view['vintageous_use_sys_clipboard'] = True self.regs.set('a', [100]) self.assertEqual(sublime.get_clipboard(), '100') def testCanAppendToSingleValue(self): self.regs.set('a', ['foo']) self.regs.append_to('A', ['bar']) self.assertEqual(registers._REGISTER_DATA['a'], ['foobar']) def testCanAppendToMultipleBalancedValues(self): self.regs.set('a', ['foo', 'bar']) self.regs.append_to('A', ['fizz', 'buzz']) self.assertEqual(registers._REGISTER_DATA['a'], ['foofizz', 'barbuzz']) def testCanAppendToMultipleValuesMoreExistingValues(self): self.regs.set('a', ['foo', 'bar']) self.regs.append_to('A', ['fizz']) self.assertEqual(registers._REGISTER_DATA['a'], ['foofizz', 'bar']) def testCanAppendToMultipleValuesMoreNewValues(self): self.regs.set('a', ['foo']) self.regs.append_to('A', ['fizz', 'buzz']) self.assertEqual(registers._REGISTER_DATA['a'], ['foofizz', 'buzz']) def testAppendingSetsDefaultRegister(self): self.regs.set('a', ['foo']) self.regs.append_to('A', ['bar']) self.assertEqual(registers._REGISTER_DATA[registers.REG_UNNAMED], ['foobar']) def testAppendSetsClipboardIfNeeded(self): self.regs.settings.view['vintageous_use_sys_clipboard'] = True self.regs.set('a', ['foo']) self.regs.append_to('A', ['bar']) self.assertEqual(sublime.get_clipboard(), 'foobar') def testGetDefaultToUnnamedRegister(self): registers._REGISTER_DATA['"'] = ['foo'] self.view.settings().set('vintageous_use_sys_clipboard', False) self.assertEqual(self.regs.get(), ['foo']) def testGettingBlackHoleRegisterReturnsNone(self): self.assertEqual(self.regs.get(registers.REG_BLACK_HOLE), None) def testCanGetFileNameRegister(self): fname = self.regs.get(registers.REG_FILE_NAME) self.assertEqual(fname, [self.view.file_name()]) def testCanGetClipboardRegisters(self): self.regs.set(registers.REG_SYS_CLIPBOARD_1, ['foo']) self.assertEqual(self.regs.get(registers.REG_SYS_CLIPBOARD_1), ['foo']) self.assertEqual(self.regs.get(registers.REG_SYS_CLIPBOARD_2), ['foo']) self.regs.set(registers.REG_SYS_CLIPBOARD_2, ['bar']) self.assertEqual(self.regs.get(registers.REG_SYS_CLIPBOARD_1), ['bar']) self.assertEqual(self.regs.get(registers.REG_SYS_CLIPBOARD_2), ['bar']) def testGetSysClipboardAlwaysIfRequested(self): self.regs.settings.view['vintageous_use_sys_clipboard'] = True sublime.set_clipboard('foo') self.assertEqual(self.regs.get(), ['foo']) def testGettingExpressionRegisterClearsExpressionRegister(self): registers._REGISTER_DATA[registers.REG_EXPRESSION] = ['100'] self.view.settings().set('vintageous_use_sys_clipboard', False) self.assertEqual(self.regs.get(), ['100']) self.assertEqual(registers._REGISTER_DATA[registers.REG_EXPRESSION], '') def testCanGetNumberRegister(self): registers._REGISTER_DATA['5'] = ['foo'] self.assertEqual(self.regs.get('5'), ['foo']) def testCanGetRegisterEvenIfRequestingItThroughACapitalLetter(self): registers._REGISTER_DATA['a'] = ['foo'] self.assertEqual(self.regs.get('A'), ['foo']) def testCanGetRegistersWithDictSyntax(self): registers._REGISTER_DATA['a'] = ['foo'] self.assertEqual(self.regs.get('a'), self.regs['a']) def testCanSetRegistersWithDictSyntax(self): self.regs['a'] = ['100'] self.assertEqual(self.regs['a'], ['100']) def testCanAppendToRegisteWithDictSyntax(self): self.regs['a'] = ['100'] self.regs['A'] = ['100'] self.assertEqual(self.regs['a'], ['100100']) def testCanConvertToDict(self): self.regs['a'] = ['100'] self.regs['b'] = ['200'] values = {name: self.regs.get(name) for name in registers.REG_ALL} values.update({'a': ['100'], 'b': ['200']}) self.assertEqual(self.regs.to_dict(), values) def testGettingEmptyRegisterReturnsNone(self): self.assertEqual(self.regs.get('a'), None) def testCanSetSmallDeleteRegister(self): self.regs[registers.REG_SMALL_DELETE] = ['foo'] self.assertEqual(registers._REGISTER_DATA[registers.REG_SMALL_DELETE], ['foo']) def testCanGetSmallDeleteRegister(self): registers._REGISTER_DATA[registers.REG_SMALL_DELETE] = ['foo'] self.assertEqual(self.regs.get(registers.REG_SMALL_DELETE), ['foo'])
def run(self, line_range=None, forced=False, file_name='', plusplus_args='', operator='', target_redirect='', subcmd=''): if file_name and target_redirect: sublime.status_message('Vintageous: Too many arguments.') return appending = operator == '>>' a_range = line_range['text_range'] self.view = self.window.active_view() content = get_region_by_range(self.view, line_range=line_range) if a_range else \ [sublime.Region(0, self.view.size())] read_only = False if self.view.file_name(): mode = os.stat(self.view.file_name()) read_only = (stat.S_IMODE(mode.st_mode) & stat.S_IWUSR != stat.S_IWUSR) if target_redirect: target = self.window.new_file() target.set_name(target_redirect) elif file_name: def report_error(msg): sublime.status_message('Vintageous: %s' % msg) file_path = os.path.abspath(os.path.expanduser(file_name)) if os.path.exists(file_path) and (file_path != self.view.file_name()): # TODO add w! flag # TODO: Hook this up with ex error handling (ex/errors.py). msg = "File '{0}' already exists.".format(file_path) report_error(msg) return if not os.path.exists(os.path.dirname(file_path)): msg = "Directory '{0}' does not exist.".format( os.path.dirname(file_path)) report_error(msg) return try: # FIXME: We need to do some work with encodings here, don't we? with open(file_path, 'w+') as temp_file: for frag in reversed(content): temp_file.write(self.view.substr(frag)) temp_file.close() sublime.status_message( "Vintageous: Saved {0}".format(file_path)) row, col = self.view.rowcol(self.view.sel()[0].b) encoded_fn = "{0}:{1}:{2}".format(file_path, row + 1, col + 1) self.view.set_scratch(True) w = self.window w.run_command('close') w.open_file(encoded_fn, sublime.ENCODED_POSITION) return except IOError as e: report_error("Failed to create file '%s'." % file_name) return window = self.window window.open_file(file_path) return else: target = self.view if (read_only or self.view.is_read_only()) and not forced: utils.blink() sublime.status_message( "Vintageous: Can't write read-only file.") return start = 0 if not appending else target.size() prefix = '\n' if appending and target.size() > 0 else '' if appending or target_redirect: for frag in reversed(content): target.run_command( 'append', {'characters': prefix + self.view.substr(frag) + '\n'}) elif a_range: start_deleting = 0 text = '' for frag in content: text += self.view.substr(frag) + '\n' start_deleting = len(text) self.view.run_command('ex_replace_file', { 'start': 0, 'end': 0, 'with_what': text }) else: dirname = os.path.dirname(self.view.file_name()) if not os.path.exists(dirname): os.makedirs(dirname) self.window.run_command('save') # This may unluckily prevent the user from seeing ST's feedback about saving the current # file. state = State(self.window.active_view()) if state.mode != MODE_NORMAL: state.enter_normal_mode() self.window.run_command('vi_enter_normal_mode')
def run(self): state = State(self.view) sublime.status_message(os.getcwd())
class Test_get_selected_text(ViewTest): def setUp(self): super().setUp() sublime.set_clipboard('') registers._REGISTER_DATA = {} self.view.settings().erase('vintage') self.view.settings().erase('vintageous_use_sys_clipboard') self.regs = State(self.view).registers self.regs.view = mock.Mock() def testExtractsSubstrings(self): self.regs.view.sel.return_value = [10, 20, 30] class vi_cmd_data: _synthetize_new_line_at_eof = False _yanks_linewise = False self.regs.get_selected_text(vi_cmd_data) self.assertEqual(self.regs.view.substr.call_count, 3) def testReturnsFragments(self): self.regs.view.sel.return_value = [10, 20, 30] self.regs.view.substr.side_effect = lambda x: x class vi_cmd_data: _synthetize_new_line_at_eof = False _yanks_linewise = False rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, [10, 20, 30]) def testCanSynthetizeNewLineAtEof(self): self.regs.view.substr.return_value = "AAA" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] self.regs.view.size.return_value = 0 class vi_cmd_data: _synthetize_new_line_at_eof = True _yanks_linewise = False rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["AAA", "AAA\n"]) def testDoesntSynthetizeNewLineAtEofIfNotNeeded(self): self.regs.view.substr.return_value = "AAA\n" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] self.regs.view.size.return_value = 0 class vi_cmd_data: _synthetize_new_line_at_eof = True _yanks_linewise = False rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["AAA\n", "AAA\n"]) def testDoesntSynthetizeNewLineAtEofIfNotAtEof(self): self.regs.view.substr.return_value = "AAA" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] self.regs.view.size.return_value = 100 class vi_cmd_data: _synthetize_new_line_at_eof = True _yanks_linewise = False rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["AAA", "AAA"]) def testCanYankLinewise(self): self.regs.view.substr.return_value = "AAA" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] class vi_cmd_data: _synthetize_new_line_at_eof = False _yanks_linewise = True rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["AAA\n", "AAA\n"]) def testDoesNotYankLinewiseIfNonEmptyStringFollowedByNewLine(self): self.regs.view.substr.return_value = "AAA\n" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] class vi_cmd_data: _synthetize_new_line_at_eof = False _yanks_linewise = True rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["AAA\n", "AAA\n"]) def testYankLinewiseIfEmptyStringFollowedByNewLine(self): self.regs.view.substr.return_value = "\n" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] class vi_cmd_data: _synthetize_new_line_at_eof = False _yanks_linewise = True rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["\n\n", "\n\n"]) def testYankLinewiseIfTwoTrailingNewLines(self): self.regs.view.substr.return_value = "\n\n" self.regs.view.sel.return_value = [sublime.Region(10, 10), sublime.Region(10, 10)] class vi_cmd_data: _synthetize_new_line_at_eof = False _yanks_linewise = True rv = self.regs.get_selected_text(vi_cmd_data) self.assertEqual(rv, ["\n\n\n", "\n\n\n"])
class MarksTests(ViewTest): def setUp(self): super().setUp() marks._MARKS = {} self.view.sel().clear() self.view.sel().add(sublime.Region(0, 0)) self.marks = State(self.view).marks def testCanSetMark(self): self.marks.add('a', self.view) expected_win, expected_view, expected_region = (self.view.window(), self.view, (0, 0)) actual_win, actual_view, actual_region = marks._MARKS['a'] self.assertEqual((actual_win.id(), actual_view.view_id, actual_region), (expected_win.id(), expected_view.view_id, expected_region)) def testCanRetrieveMarkInTheCurrentBufferAsTuple(self): self.marks.add('a', self.view) # The caret's at the beginning of the buffer. self.assertEqual(self.marks.get_as_encoded_address('a'), sublime.Region(0, 0)) def testCanRetrieveMarkInTheCurrentBufferAsTuple2(self): set_text(self.view, ''.join(('foo bar\n') * 10)) self.view.sel().clear() self.view.sel().add(sublime.Region(30, 30)) self.marks.add('a', self.view) self.assertEqual(self.marks.get_as_encoded_address('a'), sublime.Region(24, 24)) def testCanRetrieveMarkInADifferentBufferAsEncodedMark(self): view = View(id_=self.view.view_id + 1, fname=r'C:\foo.txt') marks._MARKS['a'] = (Window(), view, (0, 0)) expected = "{0}:{1}".format(r'C:\foo.txt', "0:0") self.assertEqual(self.marks.get_as_encoded_address('a'), expected) def testCanRetrieveMarkInAnUntitledBufferAsEncodedMark(self): view = View(id_=self.view.view_id + 1, fname='', buffer_id=999) marks._MARKS['a'] = (Window(), view, (0, 0)) expected = "<untitled {0}>:{1}".format(999, "0:0") self.assertEqual(self.marks.get_as_encoded_address('a'), expected) def testCanRetrieveSingleQuoteMark(self): location = self.marks.get_as_encoded_address("'") self.assertEqual(location, '<command _vi_double_single_quote>')
def run(self, key=None): state = State(self.window.active_view()) if not state.user_input: state.user_input = utils.translate_char(key)
class Test_yank(ViewTest): def setUp(self): super().setUp() sublime.set_clipboard('') registers._REGISTER_DATA = {} self.view.settings().erase('vintage') self.view.settings().erase('vintageous_use_sys_clipboard') self.regs = State(self.view).registers self.regs.view = mock.Mock() def testDontYankIfWeDontHaveTo(self): class vi_cmd_data: _can_yank = False _populates_small_delete_register = False self.regs.yank(vi_cmd_data) self.assertEqual(registers._REGISTER_DATA, {}) def testYanksToUnnamedRegisterIfNoRegisterNameProvided(self): class vi_cmd_data: _can_yank = True _synthetize_new_line_at_eof = False _yanks_linewise = True register = None _populates_small_delete_register = False with mock.patch.object(self.regs, 'get_selected_text') as gst: gst.return_value = ['foo'] self.regs.yank(vi_cmd_data) self.assertEqual(registers._REGISTER_DATA, {'"': ['foo']}) def testYanksToRegisters(self): class vi_cmd_data: _can_yank = True _populates_small_delete_register = False with mock.patch.object(self.regs, 'get_selected_text') as gst: gst.return_value = ['foo'] self.regs.yank(vi_cmd_data, register='a') self.assertEqual(registers._REGISTER_DATA, {'"': ['foo'], 'a': ['foo']}) def testCanPopulateSmallDeleteRegister(self): class vi_cmd_data: _can_yank = True _populates_small_delete_register = True with mock.patch.object(builtins, 'all') as a, \ mock.patch.object(self.regs, 'get_selected_text') as gst: gst.return_value = ['foo'] self.regs.view.sel.return_value = range(1) a.return_value = True self.regs.yank(vi_cmd_data) self.assertEqual(registers._REGISTER_DATA, {'"': ['foo'], '-': ['foo']}) def testDoesNotPopulateSmallDeleteRegisterIfWeShouldNot(self): class vi_cmd_data: _can_yank = False _populates_small_delete_register = False with mock.patch.object(builtins, 'all') as a, \ mock.patch.object(self.regs, 'get_selected_text') as gst: gst.return_value = ['foo'] self.regs.view.sel.return_value = range(1) a.return_value = False self.regs.yank(vi_cmd_data) self.assertEqual(registers._REGISTER_DATA, {})
def setUp(self): super().setUp() marks._MARKS = {} self.view.sel().clear() self.view.sel().add(sublime.Region(0, 0)) self.marks = State(self.view).marks
def set_mode(self): state = State(self.view) state.enter_normal_mode() self.view.run_command('vi_enter_normal_mode')
def run(self, key=None): state = State(self.window.active_view()) state.motion = cmd_defs.ViSearchBackwardImpl() state.last_buffer_search = state.motion._inp or state.last_buffer_search