def run(self, edit, extend=False, character=None, mode=None, count=1):
        def f(view, s):
            line_text = view.substr(sublime.Region(view.line(s.b).a, s.b))
            a, b = view.line(s.b).a, s.b
            final_offset = -1

            try:
                for i in range(count):
                    line_text = view.substr(sublime.Region(a, b))
                    match_in_line = line_text.rindex(character)

                    final_offset = match_in_line

                    b = view.line(s.a).a + final_offset
            except ValueError:
                pass

            if final_offset > -1:
                pt = view.line(s.b).a + final_offset

                state = VintageState(view)
                if state.mode == MODE_VISUAL or mode == _MODE_INTERNAL_NORMAL:
                    return sublime.Region(s.a, pt + 1)

                return sublime.Region(pt + 1, pt + 1)

            return s

        if character is None:
            return
        else:
            state = VintageState(self.view)
            state.last_character_search = character

        regions_transformer(self.view, f)
Beispiel #2
0
    def run(self, edit, mode=None, count=1, extend=False):
        def f(view, s):

            pattern = r'\b{0}\b'.format(query)
            flags = sublime.IGNORECASE

            if mode == _MODE_INTERNAL_NORMAL:
                match = view.find(pattern, view.word(s.end()).end(), flags)
            else:
                match = view.find(pattern, view.word(s).end(), flags)

            if match:
                if mode == _MODE_INTERNAL_NORMAL:
                    return sublime.Region(s.a, match.begin())
                elif state.mode == MODE_VISUAL:
                    return sublime.Region(s.a, match.begin())
                elif state.mode == MODE_NORMAL:
                    return sublime.Region(match.begin(), match.begin())
            return s

        state = VintageState(self.view)
        # TODO: make sure we swallow any leading white space.
        query = self.view.substr(self.view.word(self.view.sel()[0].end()))
        if query:
            state.last_buffer_search = query

        regions_transformer(self.view, f)
    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):
        # 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()
Beispiel #5
0
 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 = VintageState(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': MODE_NORMAL
         })
         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.run_command('vi_enter_normal_mode')
         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': MODE_NORMAL
         })
         self.view.window().run_command('vi_add_to_jump_list')
         self.view.show(self.view.sel()[0])
         state.display_partial_command()
 def run(self, inclusive=False):
     state = VintageState(self.view)
     if inclusive:
         state.motion = 'vi_inclusive_text_object'
     else:
         state.motion = 'vi_exclusive_text_object'
     state.expecting_user_input = True
Beispiel #7
0
 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 = VintageState(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': MODE_NORMAL})
         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.run_command('vi_enter_normal_mode')
         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': MODE_NORMAL})
         self.view.window().run_command('vi_add_to_jump_list')
         self.view.show(self.view.sel()[0])
         state.display_partial_command()
Beispiel #8
0
    def run(self, edit, extend=False, character=None, mode=None, count=1):
        def f(view, s):
            line_text = view.substr(sublime.Region(view.line(s.b).a, s.b))
            a, b = view.line(s.b).a, s.b
            final_offset = -1

            try:
                for i in range(count):
                    line_text = view.substr(sublime.Region(a, b))
                    match_in_line = line_text.rindex(character)

                    final_offset = match_in_line

                    b = view.line(s.a).a + final_offset
            except ValueError:
                pass

            if final_offset > -1:
                pt = view.line(s.b).a + final_offset

                state = VintageState(view)
                if state.mode == MODE_VISUAL or mode == _MODE_INTERNAL_NORMAL:
                    return sublime.Region(s.a, pt + 1)

                return sublime.Region(pt + 1, pt + 1)

            return s

        if character is None:
            return
        else:
            state = VintageState(self.view)
            state.last_character_search = character

        regions_transformer(self.view, f)
Beispiel #9
0
    def run(self, edit, mode=None, extend=False, exact_word=True):
        def f(view, s):

            if exact_word:
                pattern = r'\b{0}\b'.format(query)
            else:
                pattern = query

            flags = sublime.IGNORECASE

            if mode == _MODE_INTERNAL_NORMAL:
                match = reverse_search(view, pattern, 0, current_sel.a, flags)
            else:
                match = reverse_search(view, pattern, 0, current_sel.a, flags)

            if match:
                if mode == _MODE_INTERNAL_NORMAL:
                    return sublime.Region(s.b, match.begin())
                elif state.mode == MODE_VISUAL:
                    return sublime.Region(s.b, match.begin())
                elif state.mode == MODE_NORMAL:
                    return sublime.Region(match.begin(), match.begin())
            return s

        state = VintageState(self.view)
        # TODO: make sure we swallow any leading white space.
        query = self.view.substr(self.view.word(self.view.sel()[0].end()))
        if query:
            state.last_buffer_search = query

        current_sel = self.view.sel()[0]

        regions_transformer(self.view, f)
Beispiel #10
0
class Test_parse_action(unittest.TestCase):
    def setUp(self):
        TestsState.view.settings().erase('vintage')
        TestsState.view.window().settings().erase('vintage')
        TestsState.view.settings().erase('is_widget')
        self.state = VintageState(TestsState.view)

    def tearDown(self):
        self.state.view.sel().clear()
        self.state.view.sel().add(sublime.Region(0, 0))

    def testCantParseWithUnknownMotion(self):
        self.state.action = 'foobar'
        cmd_data = CmdData(self.state)
        self.assertRaises(AttributeError, self.state.parse_action, cmd_data)

    def testCanParseNoneMotion(self):
        cmd_data = CmdData(self.state)
        self.assertRaises(TypeError, self.state.parse_action, cmd_data)

    def testCmdDataIsntModifiedIfThereIsNoAction(self):
        # FIXME: The following creates a dependency in this test.
        self.state.action = 'vi_d'
        new_cmd_data = self.state.parse_action(CmdData(self.state))
        self.assertEqual(new_cmd_data['action']['command'], 'left_delete')

    def testCanRunActionWhenThereAreNonEmptySelections(self):
        self.state.action = 'vi_d'
        self.state.view.sel().clear()
        self.state.view.sel().add(sublime.Region(10, 20))
        new_cmd_data = self.state.parse_action(CmdData(self.state))
        self.assertFalse(new_cmd_data['motion_required'])
Beispiel #11
0
 def run(self, inclusive=False):
     state = VintageState(self.view)
     if inclusive:
         state.motion = 'vi_inclusive_text_object'
     else:
         state.motion = 'vi_exclusive_text_object'
     state.expecting_user_input = True
Beispiel #12
0
    def run(self, edit, mode=None, extend=False, exact_word=True):
        def f(view, s):

            if exact_word:
                pattern = r'\b{0}\b'.format(query)
            else:
                pattern = query

            flags = sublime.IGNORECASE

            if mode == _MODE_INTERNAL_NORMAL:
                match = reverse_search(view, pattern, 0, current_sel.a, flags)
            else:
                match = reverse_search(view, pattern, 0, current_sel.a, flags)

            if match:
                if mode == _MODE_INTERNAL_NORMAL:
                    return sublime.Region(s.b, match.begin())
                elif state.mode == MODE_VISUAL:
                    return sublime.Region(s.b, match.begin())
                elif state.mode == MODE_NORMAL:
                    return sublime.Region(match.begin(), match.begin())
            return s

        state = VintageState(self.view)
        # TODO: make sure we swallow any leading white space.
        query = self.view.substr(self.view.word(self.view.sel()[0].end()))
        if query:
            state.last_buffer_search = query

        current_sel = self.view.sel()[0]

        regions_transformer(self.view, f)
Beispiel #13
0
 def run(self, edit, character=None):
     state = VintageState(self.view)
     if character is None:
         state.expecting_register = True
     else:
         state.register = character
         state.expecting_register = False
Beispiel #14
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 #15
0
 def setUp(self):
     sublime.set_clipboard('')
     registers._REGISTER_DATA = {}
     TestsState.view.settings().erase('vintage')
     TestsState.view.settings().erase('vintageous_use_sys_clipboard')
     self.regs = VintageState(TestsState.view).registers
     self.regs.view = mock.Mock()
Beispiel #16
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 #17
0
    def do_action(self, vi_cmd_data):
        self.debug("Vintageous: Action command: ", vi_cmd_data["action"])
        if vi_cmd_data["action"]:

            # Populate registers if we have to.
            if vi_cmd_data["can_yank"]:
                state = VintageState(self.view)
                if vi_cmd_data["register"]:
                    state.registers[vi_cmd_data["register"]] = self.get_selected_text(vi_cmd_data)
                else:
                    # TODO: Encapsulate this in registers.py. We could have a
                    # .yank() method there that knows about all the details.
                    state.registers[REG_UNNAMED] = self.get_selected_text(vi_cmd_data)

            # XXX: Small register delete. Improve this implementation.
            if vi_cmd_data["populates_small_delete_register"]:
                state = VintageState(self.view)
                is_same_line = lambda r: self.view.line(r.begin()) == self.view.line(r.end() - 1)
                if all(is_same_line(x) for x in list(self.view.sel())):
                    state.registers[REG_SMALL_DELETE] = self.get_selected_text(vi_cmd_data)

            cmd = vi_cmd_data["action"]["command"]
            args = vi_cmd_data["action"]["args"]

            # Some actions that don't take a motion apply the count to the action. For example,
            # > in visual mode.
            i = vi_cmd_data["count"] if vi_cmd_data["_repeat_action"] else 1
            for t in range(i):
                self.view.run_command(cmd, args)
Beispiel #18
0
    def on_done(self, idx):
        """Save selected value to `"` register."""
        if idx == -1:
            return

        state = VintageState(self.view)
        value = list(state.registers.to_dict().values())[idx]
        state.registers['"'] = value
Beispiel #19
0
    def on_done(self, idx):
        """Save selected value to `"` register."""
        if idx == -1:
            return

        state = VintageState(self.view)
        value = list(state.registers.to_dict().values())[idx]
        state.registers['"'] = value
Beispiel #20
0
 def setUp(self):
     sublime.set_clipboard('')
     registers._REGISTER_DATA = {}
     TestsState.view.settings().erase('vintage')
     TestsState.view.settings().erase('vintageous_use_sys_clipboard')
     # self.regs = Registers(view=TestsState.view,
     # settings=SettingsManager(view=TestsState.view))
     self.regs = VintageState(TestsState.view).registers
Beispiel #21
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"])
    def run(self, edit):
        state = VintageState(self.view)

        if state.mode == MODE_VISUAL:
            state.store_visual_selections()

        self.view.run_command('collapse_to_direction')
        self.view.run_command('dont_stay_on_eol_backward')
        state.enter_normal_mode()
Beispiel #23
0
    def run(self, edit, extend=False):
        def f(view, s):
            hard_eol = self.view.line(s.b).end()
            return sublime.Region(hard_eol, hard_eol)

        regions_transformer(self.view, f)

        state = VintageState(self.view)
        state.enter_insert_mode()
    def run(self, edit, commands):
        for cmd, args in commands:
            self.view.run_command(cmd, args)

        # XXX: Sequence is a special case in that it doesn't run through vi_run, so we need to
        # ensure the next mode is correct. Maybe we can improve this by making it more similar to
        # regular commands?
        state = VintageState(self.view)
        state.enter_normal_mode()
Beispiel #25
0
    def run(self, edit):
        # Handling multiple visual blocks seems quite hard, so ensure we only have one.
        first = list(self.view.sel())[0]
        self.view.sel().clear()
        self.view.sel().add(first)

        state = VintageState(self.view)
        state.enter_visual_block_mode()
        self.view.run_command('extend_to_minimal_width')
Beispiel #26
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 #27
0
    def run(self, edit):
        # Handling multiple visual blocks seems quite hard, so ensure we only have one.
        first = list(self.view.sel())[0]
        self.view.sel().clear()
        self.view.sel().add(first)

        state = VintageState(self.view)
        state.enter_visual_block_mode()
        self.view.run_command('extend_to_minimal_width')
Beispiel #28
0
    def run(self, edit, commands):
        for cmd, args in commands:
            self.view.run_command(cmd, args)

        # XXX: Sequence is a special case in that it doesn't run through vi_run, so we need to
        # ensure the next mode is correct. Maybe we can improve this by making it more similar to
        # regular commands?
        state = VintageState(self.view)
        state.enter_normal_mode()
Beispiel #29
0
 def run(self, edit, character=None):
     state = VintageState(self.view)
     if character is None:
         state.expecting_register = True
     else:
         if character not in (REG_EXPRESSION,):
             state.register = character
             state.expecting_register = False
         else:
             self.view.run_command('vi_expression_register')
    def run(self, edit, extend=False):
        def f(view, s):
            line = view.line(s.b)
            pt = utils.next_non_white_space_char(view, line.a)
            return sublime.Region(pt, pt)

        state = VintageState(self.view)
        state.enter_insert_mode()

        regions_transformer(self.view, f)
 def run(self, edit, character=None):
     state = VintageState(self.view)
     if character is None:
         state.expecting_register = True
     else:
         if character not in (REG_EXPRESSION, ):
             state.register = character
             state.expecting_register = False
         else:
             self.view.run_command('vi_expression_register')
Beispiel #32
0
    def run(self, edit, extend=False):
        def f(view, s):
            line = view.line(s.b)
            pt = utils.next_non_white_space_char(view, line.a)
            return sublime.Region(pt, pt)

        state = VintageState(self.view)
        state.enter_insert_mode()

        regions_transformer(self.view, f)
Beispiel #33
0
    def run(self, edit, count=None):
        def f(view, s):
            return sublime.Region(s.a, s.b + (count - 1))

        state = VintageState(self.view)
        state.enter_visual_mode()
        self.view.run_command('extend_to_minimal_width')

        if count > 1:
            regions_transformer(self.view, f)
Beispiel #34
0
    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 = VintageState(self.view)
        state.registers[register] = [text]
        if register == '"':
            state.registers['0'] = [text]
Beispiel #35
0
    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 = VintageState(self.view)
        state.registers[register] = [text]
        if register == '"':
            state.registers['0'] = [text]
Beispiel #36
0
    def on_done(self, s):
        state = VintageState(self.view)
        state.motion = 'vi_question_mark'

        state.user_input = s
        # Equivalent to ?<CR>, which must repeat the last search.
        if s == '':
            state.user_input = state.last_buffer_search

        if s != '':
            state.last_buffer_search = s
        state.eval()
Beispiel #37
0
    def run(self, edit):
        state = VintageState(self.view)

        if state.mode == MODE_VISUAL:
            state.store_visual_selections()

        # When returning to normal mode from select mode, we want to keep the non-Vintageous
        # selections just created unless it's the last one.
        if not (state.mode == MODE_SELECT and len(self.view.sel()) > 1):
            self.view.run_command('collapse_to_direction')
            self.view.run_command('dont_stay_on_eol_backward')
        state.enter_normal_mode()
    def on_done(self, s):
        self.view.erase_regions("vi_inc_search")
        state = VintageState(self.view)
        state.motion = "vi_question_mark"

        state.user_input = s
        # Equivalent to ?<CR>, which must repeat the last search.
        if s == "":
            state.user_input = state.last_buffer_search

        if s != "":
            state.last_buffer_search = s
        state.eval()
Beispiel #39
0
    def run(self, edit, extend=False, mode=None):
        def f(view, s):
            if mode == MODE_VISUAL_BLOCK:
                return sublime.Region(s.end())
            elif mode != _MODE_INTERNAL_NORMAL:
                return s
            hard_eol = self.view.line(s.b).end()
            return sublime.Region(hard_eol, hard_eol)

        regions_transformer(self.view, f)

        state = VintageState(self.view)
        state.enter_insert_mode()
Beispiel #40
0
    def on_done(self, s):
        self.view.erase_regions('vi_inc_search')
        state = VintageState(self.view)
        state.motion = 'vi_forward_slash'

        state.user_input = s
        # Equivalent to /<CR>, which must repeat the last search.
        if s == '':
            state.user_input = state.last_buffer_search

        if s != '':
            state.last_buffer_search = s
        state.eval()
Beispiel #41
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 #42
0
    def testFromVisualModeToNormalMode(self):
        set_text(self.view, 'abc\nxxx\nabc\nabc')
        add_sel(self.view, self.R((1, 0), (1, 1)))

        state = VintageState(self.view)
        state.enter_visual_mode()
        prev_mode = state.mode

        self.view.run_command('ex_copy', {'address': '3'})

        state = VintageState(self.view)
        new_mode = state.mode
        self.assertNotEqual(prev_mode, new_mode)
        self.assertEqual(new_mode, MODE_NORMAL)
Beispiel #43
0
    def testFromVisualModeToNormalMode(self):
        self.write("abc\nxxx\nabc\nabc")
        self.clear_sel()
        self.add_sel(self.R((1, 0), (1, 1)))

        state = VintageState(self.view)
        state.enter_visual_mode()
        prev_mode = state.mode

        self.view.run_command("ex_move", {"address": "3"})

        state = VintageState(self.view)
        new_mode = state.mode
        self.assertNotEqual(prev_mode, new_mode)
Beispiel #44
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 #45
0
    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 = VintageState(self.view)
            state.registers[register] = [text]
    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 #47
0
    def testCaretEndsInExpectedRegion(self):
        set_text(self.view, ''.join(('foo bar\nfoo bar\nfoo bar\n', )))
        add_sel(self.view, self.R((1, 3), (1, 0)))

        state = VintageState(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))
Beispiel #48
0
class Test_push_action_digit(unittest.TestCase):
    def setUp(self):
        TestsState.view.settings().erase('vintage')
        TestsState.view.window().settings().erase('vintage')
        TestsState.view.settings().erase('is_widget')
        self.state = VintageState(TestsState.view)

    def testCanAddOneItemWhenListIsEmpty(self):
        self.state.push_action_digit("1")
        self.assertEqual(self.state.action_digits, ["1"])

    def testCanAppendMoreDigits(self):
        self.state.push_action_digit("1")
        self.state.push_action_digit("1")
        self.assertEqual(self.state.action_digits, ["1", "1"])
Beispiel #49
0
    def run(self, edit, extend=False, character=None, mode=None, count=1):
        def f(view, s):
            eol = view.line(s.b).end()
            if not s.empty():
                eol = view.line(s.b - 1).end()

            match = s
            offset = 1 if count > 1 else 0
            for i in range(count):

                # Define search range as 'rest of the line to the right'.
                if state.mode != MODE_VISUAL:
                    search_range = sublime.Region(
                        min(match.b + 1 + offset, eol), eol)
                else:
                    search_range = sublime.Region(min(match.b + offset, eol),
                                                  eol)

                match = find_in_range(view, character, search_range.a,
                                      search_range.b, sublime.LITERAL)

                # Count too high or simply no match; break.
                if match is None:
                    match = s
                    break

            if state.mode == MODE_VISUAL or mode == _MODE_INTERNAL_NORMAL:
                if match == s:
                    # FIXME: It won't blink because the current light can't be highlighted right
                    # now (we are in command mode and there is a selection on the screen. Perhaps
                    # we can make the gutter blink instead.)
                    utils.blink()
                    return s
                return sublime.Region(s.a, match.b - 1)

            if match == s:
                utils.blink()
                return s
            return sublime.Region(match.a - 1, match.a - 1)

        # TODO: Give feedback to the user that the search failed?
        if character is None:
            return
        else:
            state = VintageState(self.view)
            state.last_character_search = character

        regions_transformer(self.view, f)
Beispiel #50
0
    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 = VintageState(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')
Beispiel #51
0
        def f(view, s):
            line_text = view.substr(sublime.Region(view.line(s.b).a, s.b))
            a, b = view.line(s.b).a, s.b
            final_offset = -1

            try:
                for i in range(count):
                    line_text = view.substr(sublime.Region(a, b))
                    match_in_line = line_text.rindex(character)

                    final_offset = match_in_line

                    b = view.line(s.a).a + final_offset
            except ValueError:
                pass

            if final_offset > -1:
                pt = view.line(s.b).a + final_offset

                state = VintageState(view)
                if state.mode == MODE_VISUAL or mode == _MODE_INTERNAL_NORMAL:
                    return sublime.Region(s.a, pt + 1)

                return sublime.Region(pt + 1, pt + 1)

            return s
Beispiel #52
0
    def run(self):
        Vintageous.state._dont_reset_during_init = True

        state = VintageState(self.view)
        on_change = self.on_change if state.settings.vi['incsearch'] else None
        self.view.window().show_input_panel('', '', self.on_done, on_change,
                                            self.on_cancel)
Beispiel #53
0
    def on_cancel(self):
        self.view.erase_regions('vi_inc_search')
        state = VintageState(self.view)
        state.reset()

        if not self.view.visible_region().contains(self.view.sel()[0]):
            self.view.show(self.view.sel()[0])
Beispiel #54
0
        def f(view, s):
            # TODO: Refactor this mess.
            line_text = view.substr(sublime.Region(view.line(s.b).a, s.b))
            offset = 0
            a, b = view.line(s.b).a, s.b
            final_offset = -1

            try:
                for i in range(count):
                    line_text = view.substr(sublime.Region(a, b))
                    match_in_line = line_text.rindex(character)

                    final_offset = match_in_line

                    b = view.line(s.a).a + final_offset
            except ValueError:
                pass

            if final_offset > -1:
                pt = view.line(s.b).a + final_offset

                state = VintageState(view)
                if state.mode == MODE_VISUAL or mode == _MODE_INTERNAL_NORMAL:
                    if sublime.Region(s.b, pt) == s:
                        utils.blink()
                        return s
                    return sublime.Region(s.a, pt)

                if pt == s.b:
                    utils.blink()
                    return s
                return sublime.Region(pt, pt)

            return s
 def run(self, edit):
     state = VintageState(self.view)
     pairs = [
         '"{0}   {1}'.format(k, v)
         for k, v in state.registers.to_dict().items() if v
     ]
     self.view.window().show_quick_panel(pairs, self.on_done)
    def run(self, edit, mode=None, character=None, extend=False):
        def f(view, s):
            if mode == MODE_VISUAL:
                if s.a <= s.b:
                    if address.b < s.b:
                        return sublime.Region(s.a + 1, address.b)
                    else:
                        return sublime.Region(s.a, address.b)
                else:
                    return sublime.Region(s.a + 1, address.b)
            elif mode == MODE_NORMAL:
                return address
            elif mode == _MODE_INTERNAL_NORMAL:
                return sublime.Region(s.a, address.b)

            return s

        state = VintageState(self.view)
        address = state.marks.get_as_encoded_address(character)

        if address is None:
            return

        if isinstance(address, str):
            if not address.startswith('<command'):
                self.view.window().open_file(address, sublime.ENCODED_POSITION)
            else:
                # We get a command in this form: <command _vi_double_quote>
                self.view.run_command(address.split(' ')[1][:-1])
            return

        # This is a motion in a composite command.
        regions_transformer(self.view, f)
Beispiel #57
0
    def inner(*args, **kwargs):
        try:
            state = VintageState(args[0].view)
        except AttributeError:
            state = VintageState(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 run(self, edit, register=None, count=1):
        state = VintageState(self.view)

        if register:
            fragments = state.registers[register]
        else:
            # TODO: There should be a simpler way of getting the unnamed register's content.
            fragments = state.registers['"']

        sels = list(self.view.sel())

        if len(sels) == len(fragments):
            sel_frag = zip(sels, fragments)
        else:
            sel_frag = zip(sels, [
                fragments[0],
            ] * len(sels))

        offset = 0
        for s, text in sel_frag:
            if text.endswith('\n'):
                if utils.is_at_eol(self.view, s) or utils.is_at_bol(
                        self.view, s):
                    self.paste_all(edit, s, self.view.line(s.b).a, text, count)
                else:
                    self.paste_all(edit, s,
                                   self.view.line(s.b - 1).a, text, count)
            else:
                self.paste_all(edit, s, s.b + offset, text, count)
                offset += len(text) * count
    def paste_all(self, edit, sel, at, text, count):
        state = VintageState(self.view)
        if state.mode not in (MODE_VISUAL, MODE_VISUAL_LINE):
            # TODO: generate string first, then insert?
            # Make sure we can paste at EOF.
            at = at if at <= self.view.size() else self.view.size()
            for x in range(count):
                self.view.insert(edit, at, text)
                # Return position at which we have just pasted.
                return at
        else:
            if text.startswith('\n'):
                text = text * count
                if not text.endswith('\n'):
                    text = text + '\n'
            else:
                text = text * count

            if state.mode == MODE_VISUAL_LINE:
                if text.startswith('\n'):
                    text = text[1:]

            self.view.replace(edit, sel, text)
            # Return position at which we have just pasted.
            return sel.a
    def run(self, edit, extend=False):
        state = VintageState(self.view)
        state.enter_insert_mode()

        self.view.run_command('collapse_to_direction')

        sels = list(self.view.sel())
        self.view.sel().clear()

        new_sels = []
        for s in sels:
            hard_eol = self.view.line(s.b).end()
            new_sels.append(sublime.Region(hard_eol, hard_eol))

        for s in new_sels:
            self.view.sel().add(s)