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 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 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 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 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 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 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 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 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 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, 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 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 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, 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 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, 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 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 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 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 state(self): return State(self.view)
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())