Beispiel #1
0
    def run(self):
        # We define our own transformer here because we want to handle undo as a special case.
        # TODO: I don't know if it needs to be an special case in reality.
        def f(view, s):
            # Compensates the move issued below.
            if s.a < s.b :
                return sublime.Region(s.a + 1, s.a + 1)
            else:
                return sublime.Region(s.a, s.a)

        state = VintageState(self.view)
        for i in range(state.count):
            self.view.run_command('undo')

        if self.view.has_non_empty_selection_region():
            regions_transformer(self.view, f)
            # !! HACK !! /////////////////////////////////////////////////////////
            # This is a hack to work around an issue in Sublime Text:
            # When undoing in normal mode, Sublime Text seems to prime a move by chars
            # forward that has never been requested by the user or Vintageous.
            # As far as I can tell, Vintageous isn't at fault here, but it seems weird
            # to think that Sublime Text is wrong.
            self.view.run_command('move', {'by': 'characters', 'forward': False})
            # ////////////////////////////////////////////////////////////////////

        state.update_xpos()
        # Ensure that we wipe the count, if any.
        state.reset()
    def run(self):
        # We define our own transformer here because we want to handle undo as a special case.
        # TODO: I don't know if it needs to be an special case in reality.
        def f(view, s):
            # Compensates the move issued below.
            if s.a < s.b:
                return sublime.Region(s.a + 1, s.a + 1)
            else:
                return sublime.Region(s.a, s.a)

        state = VintageState(self.view)
        for i in range(state.count):
            self.view.run_command('undo')

        if self.view.has_non_empty_selection_region():
            regions_transformer(self.view, f)
            # !! HACK !! /////////////////////////////////////////////////////////
            # This is a hack to work around an issue in Sublime Text:
            # When undoing in normal mode, Sublime Text seems to prime a move by chars
            # forward that has never been requested by the user or Vintageous.
            # As far as I can tell, Vintageous isn't at fault here, but it seems weird
            # to think that Sublime Text is wrong.
            self.view.run_command('move', {
                'by': 'characters',
                'forward': False
            })
            # ////////////////////////////////////////////////////////////////////

        state.update_xpos()
        # Ensure that we wipe the count, if any.
        state.reset()
    def run(self):
        state = VintageState(self.view)

        try:
            cmd, args, _ = state.repeat_command
        except TypeError:
            # Unreachable.
            return

        if not cmd:
            return
        elif cmd == 'vi_run':
            args['next_mode'] = MODE_NORMAL
            args['follow_up_mode'] = 'vi_enter_normal_mode'
            args['count'] = state.count * args['count']
            self.view.run_command(cmd, args)
        elif cmd == 'sequence':
            for i, _ in enumerate(args['commands']):
                # Access this shape: {"commands":[['vi_run', {"foo": 100}],...]}
                args['commands'][i][1]['next_mode'] = MODE_NORMAL
                args['commands'][i][1][
                    'follow_up_mode'] = 'vi_enter_normal_mode'

            # TODO: Implement counts properly for 'sequence' command.
            for i in range(state.count):
                self.view.run_command(cmd, args)

        # Ensure we wipe count data if any.
        state.reset()
        # XXX: Needed here? Maybe enter_... type commands should be IrreversibleTextCommands so we
        # must/can call them whenever we need them withouth affecting the undo stack.
        self.view.run_command('vi_enter_normal_mode')
Beispiel #4
0
 def run(self, edit):
     state = VintageState(self.view)
     state.enter_insert_mode()
     self.view.run_command('collapse_to_direction')
     # 5i and friends don't enter INSERTMODE through this command, so it's fine resetting here.
     # We need to reset so that things like CTRL+R,ESC (INSERTMODE) cancel pending state.
     state.reset()
Beispiel #5
0
    def run(self):
        state = VintageState(self.view)

        try:
            cmd, args, _ = state.repeat_command
        except TypeError:
            # Unreachable.
            return

        if not cmd:
            return
        elif cmd == 'vi_run':
            args['next_mode'] = MODE_NORMAL
            args['follow_up_mode'] = 'vi_enter_normal_mode'
            args['count'] = state.count * args['count']
            self.view.run_command(cmd, args)
        elif cmd == 'sequence':
            for i, _ in enumerate(args['commands']):
                # We can have either 'vi_run' commands or plain insert mode commands.
                if args['commands'][i][0] == 'vi_run':
                    # Access this shape: {"commands":[['vi_run', {"foo": 100}],...]}
                    args['commands'][i][1]['next_mode'] = MODE_NORMAL
                    args['commands'][i][1]['follow_up_mode'] = 'vi_enter_normal_mode'

            # TODO: Implement counts properly for 'sequence' command.
            for i in range(state.count):
                self.view.run_command(cmd, args)

        # Ensure we wipe count data if any.
        state.reset()
        # XXX: Needed here? Maybe enter_... type commands should be IrreversibleTextCommands so we
        # must/can call them whenever we need them withouth affecting the undo stack.
        self.view.run_command('vi_enter_normal_mode')
Beispiel #6
0
    def run(self, edit, **vi_cmd_data):
        self.debug("Data in ViRunCommand:", vi_cmd_data)

        try:
            if vi_cmd_data["restore_original_carets"]:
                self.save_caret_pos()

            # XXX: Fix this. When should we run the motion exactly?
            if vi_cmd_data["action"]:
                # If no motion is present, we know we just have to run the action (like ctrl+w, v).
                if (vi_cmd_data["motion"]) or (
                    vi_cmd_data["motion_required"] and not view.has_non_empty_selection_region()
                ):
                    self.enter_visual_mode_if_needed(vi_cmd_data)
                    self.do_whole_motion(vi_cmd_data)

                # The motion didn't change the selections: abort action if so required.
                # TODO: What to do with .post_action() and .do_follow_up_mode() in this event?
                if (
                    vi_cmd_data["mode"] == _MODE_INTERNAL_NORMAL
                    and all([v.empty() for v in self.view.sel()])
                    and vi_cmd_data["cancel_action_if_motion_fails"]
                ):
                    return

                self.do_action(vi_cmd_data)
            else:
                self.do_whole_motion(vi_cmd_data)

        finally:
            # XXX: post_action should be run only if do_action succeeds (?).
            self.do_post_action(vi_cmd_data)

            if vi_cmd_data["must_update_xpos"]:
                state = VintageState(self.view)

                first_sel = self.view.sel()[0]
                xpos = 0
                if state.mode == MODE_VISUAL:
                    if first_sel.a < first_sel.b:
                        xpos = self.view.rowcol(first_sel.b - 1)[1]
                    elif first_sel.a > first_sel.b:
                        xpos = self.view.rowcol(first_sel.b)[1]

                elif state.mode == MODE_NORMAL:
                    xpos = self.view.rowcol(first_sel.b)[1]

                state.xpos = xpos

            self.do_modify_selections(vi_cmd_data)
            self.do_follow_up_mode(vi_cmd_data)

            if vi_cmd_data["scroll_into_view"]:
                # TODO: If moving by lines, scroll the minimum amount to display the new sels.
                self.view.show(self.view.sel()[0])

            state = VintageState(self.view)
            state.reset(next_mode=vi_cmd_data["next_mode"])
Beispiel #7
0
    def run(self):
        state = VintageState(self.view)
        for i in range(state.count):
            self.view.run_command('redo')

        state.update_xpos()
        # Ensure that we wipe the count, if any.
        state.reset()
        self.view.run_command('vi_enter_normal_mode')
Beispiel #8
0
    def run(self):
        state = VintageState(self.view)
        for i in range(state.count):
            self.view.run_command('redo')

        state.update_xpos()
        # Ensure that we wipe the count, if any.
        state.reset()
        self.view.run_command('vi_enter_normal_mode')
Beispiel #9
0
 def on_done(s):
     state = VintageState(self.view)
     try:
         rv = [str(eval(s, None, None)),]
         if not insert:
             # TODO: We need to sort out the values received and sent to registers. When pasting,
             # we assume a list... This should be encapsulated in Registers.
             state.registers[REG_EXPRESSION] = rv
         else:
             self.view.run_command('insert_snippet', {'contents': str(rv[0])})
             state.reset()
     except:
         sublime.status_message("Vintageous: Invalid expression.")
         on_cancel()
Beispiel #10
0
    def run(self, edit):
        state = VintageState(self.view)
        # We've recorded what the user has typed into the buffer. Turn macro recording off.
        self.view.run_command('toggle_record_macro')

        for i in range(state.count - 1):
            self.view.run_command('run_macro')

        # Ensure the count will be deleted.
        state.mode = MODE_NORMAL
        # Delete the count now.
        state.reset()

        self.view.run_command('vi_enter_normal_mode_from_insert_mode')
Beispiel #11
0
 def on_done(s):
     state = VintageState(self.view)
     try:
         rv = [str(eval(s, None, None)),]
         if not insert:
             # TODO: We need to sort out the values received and sent to registers. When pasting,
             # we assume a list... This should be encapsulated in Registers.
             state.registers[REG_EXPRESSION] = rv
         else:
             self.view.run_command('insert_snippet', {'contents': str(rv[0])})
             state.reset()
     except:
         sublime.status_message("Vintageous: Invalid expression.")
         on_cancel()
Beispiel #12
0
    def run(self, edit):
        state = VintageState(self.view)
        # We've recorded what the user has typed into the buffer. Turn macro recording off.
        self.view.run_command('glue_marked_undo_groups')

        # FIXME: We can't repeat 5ifoo<esc> after we're done.
        for i in range(state.count - 1):
            self.view.run_command('repeat')

        # Ensure the count will be deleted.
        state.mode = MODE_NORMAL
        # Delete the count now.
        state.reset()

        self.view.run_command('vi_enter_normal_mode_from_insert_mode')
    def run(self, edit):
        state = VintageState(self.view)
        # We've recorded what the user has typed into the buffer. Turn macro recording off.
        self.view.run_command('glue_marked_undo_groups')

        # FIXME: We can't repeat 5ifoo<esc> after we're done.
        for i in range(state.count - 1):
            self.view.run_command('repeat')

        # Ensure the count will be deleted.
        state.mode = MODE_NORMAL
        # Delete the count now.
        state.reset()

        self.view.run_command('vi_enter_normal_mode_from_insert_mode')
Beispiel #14
0
    def run(self, name=None):
        state = VintageState(self.view)

        if name == None and not state.is_recording:
            return

        if not state.is_recording:
            state._latest_macro_name = name
            state.is_recording = True
            self.view.run_command('start_record_macro')
            return

        if state.is_recording:
            self.view.run_command('stop_record_macro')
            state.is_recording = False
            state.reset()

            # Store the macro away.
            modifying_cmd = self.view.command_history(0, True)
            state.latest_macro = modifying_cmd
    def run(self, name=None):
        state = VintageState(self.view)

        if name == None and not state.is_recording:
            return

        if not state.is_recording:
            self.view.run_command('unmark_undo_groups_for_gluing')
            state.latest_macro_name = name
            state.is_recording = True
            self.view.run_command('start_record_macro')
            return

        if state.is_recording:
            self.view.run_command('stop_record_macro')
            state.is_recording = False
            self.view.run_command('unmark_undo_groups_for_gluing')
            state.reset()

            # Store the macro away.
            state.macros[state.latest_macro_name] = sublime.get_macro()
Beispiel #16
0
    def run(self, name=None):
        state = VintageState(self.view)

        if name == None and not state.is_recording:
            return

        if not state.is_recording:
            self.view.run_command('unmark_undo_groups_for_gluing')
            state.latest_macro_name = name
            state.is_recording = True
            self.view.run_command('start_record_macro')
            return

        if state.is_recording:
            self.view.run_command('stop_record_macro')
            state.is_recording = False
            self.view.run_command('unmark_undo_groups_for_gluing')
            state.reset()

            # Store the macro away.
            state.macros[state.latest_macro_name] = sublime.get_macro()
Beispiel #17
0
    def run(self):
        state = VintageState(self.view)

        try:
            cmd, args, _ = state.repeat_command
        except TypeError:
            # Unreachable.
            return

        # Signal that we're not simply issuing an interactive command, but rather repeating one.
        # This is necessary, for example, to notify _vi_k that it should become _vi_j instead
        # if the former was run in visual mode.
        state.settings.vi['_is_repeating'] = True

        if not cmd:
            return
        elif cmd == 'vi_run':
            args['next_mode'] = MODE_NORMAL
            args['follow_up_mode'] = 'vi_enter_normal_mode'
            args['count'] = state.count * args['count']
            self.view.run_command(cmd, args)
        elif cmd == 'sequence':
            for i, _ in enumerate(args['commands']):
                # We can have either 'vi_run' commands or plain insert mode commands.
                if args['commands'][i][0] == 'vi_run':
                    # Access this shape: {"commands":[['vi_run', {"foo": 100}],...]}
                    args['commands'][i][1]['next_mode'] = MODE_NORMAL
                    args['commands'][i][1][
                        'follow_up_mode'] = 'vi_enter_normal_mode'

            # TODO: Implement counts properly for 'sequence' command.
            for i in range(state.count):
                self.view.run_command(cmd, args)

        # Ensure we wipe count data if any.
        state.reset()
        # XXX: Needed here? Maybe enter_... type commands should be IrreversibleTextCommands so we
        # must/can call them whenever we need them withouth affecting the undo stack.
        self.view.run_command('vi_enter_normal_mode')
        state.settings.vi['_is_repeating'] = False
Beispiel #18
0
    def run(self):
        state = VintageState(self.view)

        try:
            cmd, args, _ = state.repeat_command
        except TypeError:
            # Unreachable.
            return

        # Signal that we're not simply issuing an interactive command, but rather repeating one.
        # This is necessary, for example, to notify _vi_k that it should become _vi_j instead
        # if the former was run in visual mode.
        state.settings.vi['_is_repeating'] = True

        if not cmd:
            return
        elif cmd == 'vi_run':
            args['next_mode'] = MODE_NORMAL
            args['follow_up_mode'] = 'vi_enter_normal_mode'
            args['count'] = state.count * args['count']
            self.view.run_command(cmd, args)
        elif cmd == 'sequence':
            for i, _ in enumerate(args['commands']):
                # We can have either 'vi_run' commands or plain insert mode commands.
                if args['commands'][i][0] == 'vi_run':
                    # Access this shape: {"commands":[['vi_run', {"foo": 100}],...]}
                    args['commands'][i][1]['next_mode'] = MODE_NORMAL
                    args['commands'][i][1]['follow_up_mode'] = 'vi_enter_normal_mode'

            # TODO: Implement counts properly for 'sequence' command.
            for i in range(state.count):
                self.view.run_command(cmd, args)

        # Ensure we wipe count data if any.
        state.reset()
        # XXX: Needed here? Maybe enter_... type commands should be IrreversibleTextCommands so we
        # must/can call them whenever we need them withouth affecting the undo stack.
        self.view.run_command('vi_enter_normal_mode')
        state.settings.vi['_is_repeating'] = False
Beispiel #19
0
 def run(self, edit):
     state = VintageState(self.view)
     state.enter_replace_mode()
     # XXX: Shouldn't this be done from within VintageState?
     self.view.run_command('collapse_to_direction')
     state.reset()
Beispiel #20
0
 def on_cancel():
     state = VintageState(self.view)
     state.reset(next_mode=MODE_INSERT)
 def on_cancel():
     state = VintageState(self.view)
     state.reset()
 def run(self, edit):
     state = VintageState(self.view)
     state.enter_replace_mode()
     self.view.run_command('collapse_to_direction')
     state.reset()
Beispiel #23
0
 def run(self, edit):
     state = VintageState(self.view)
     self.view.run_command('collapse_to_direction')
     self.view.run_command('dont_stay_on_eol_backward')
     state.reset()
     state.enter_normal_mode()
Beispiel #24
0
class Test_reset(unittest.TestCase):
    def setUp(self):
        TestsState.view.settings().erase('vintage')
        TestsState.view.window().settings().erase('vintage')
        self.state = VintageState(TestsState.view)

    def testResetsData(self):
        self.state.action = 'action'
        self.state.motion = 'motion'
        self.state.register = 'register'
        self.state.user_input = 'user_input'
        self.state.expecting_register = 'expecting_register'
        self.state.expecting_user_input = 'expecting_user_input'
        self.state.cancel_action = 'cancel_action'
        self.state.mode = 'mode'
        self.state.next_mode = 'next_mode'
        self.state.next_mode_command = 'next_mode_command'

        self.state.reset()

        self.assertEqual(self.state.action, None)
        self.assertEqual(self.state.motion, None)
        self.assertEqual(self.state.register, None)
        self.assertEqual(self.state.user_input, None)
        self.assertEqual(self.state.expecting_register, False)
        self.assertEqual(self.state.expecting_user_input, False)
        self.assertEqual(self.state.cancel_action, False)
        self.assertEqual(self.state.mode, 'mode')
        self.assertEqual(self.state.next_mode, MODE_NORMAL)
        self.assertEqual(self.state.next_mode_command, None)

    def testCallsCorrectModeChangeMethod(self):
        self.state.next_mode = MODE_INSERT
        self.state.next_mode_command = 'foo'

        # XXX Check the code. Do we actually need to call this method at this point?
        with mock.patch.object(self.state.view, 'run_command') as rc:
            self.state.reset()
            rc.assert_called_once_with('foo')

        self.state.reset()

        self.state.next_mode = MODE_NORMAL
        self.state.next_mode_command = 'bar'

        with mock.patch.object(self.state.view, 'run_command') as m:
            self.state.reset()
            m.assert_called_once_with('bar')

    def testDoesNotCallAnyModeChangeCommandForOtherModes(self):
        self.state.next_mode = MODE_VISUAL_LINE
        self.state.next_mode_command = 'foo'

        with mock.patch.object(self.state.view, 'run_command') as rc:
            self.state.reset()
            self.assertEqual(rc.call_count, 0)

    def testDoesNotCallAnyModeChangeCommandIfNotSpecified(self):
        self.state.next_mode = MODE_NORMAL

        with mock.patch.object(self.state.view, 'run_command') as rc:
            self.state.reset()
            self.assertEqual(rc.call_count, 0)

        self.state.next_mode = MODE_VISUAL

        with mock.patch.object(self.state.view, 'run_command') as rc:
            self.state.reset()
            self.assertEqual(rc.call_count, 0)

    def testUpdatesRepeatCommandIfThereWasAnAction(self):
        self.state.action = 'foo'

        with mock.patch.object(self.state, 'update_repeat_command') as m:
            self.state.reset()
            self.assertEqual(m.call_count, 1)

    def testDoesNotUpdateRepeatCommandIfThereWasNoAction(self):
        with mock.patch.object(self.state, 'update_repeat_command') as m:
            self.state.reset()
            self.assertEqual(m.call_count, 0)
Beispiel #25
0
 def on_cancel():
     state = VintageState(self.view)
     state.reset()
Beispiel #26
0
 def run(self, edit):
     state = VintageState(self.view)
     state.enter_replace_mode()
     self.view.run_command('collapse_to_direction')
     state.reset()