コード例 #1
0
ファイル: motion_cmds.py プロジェクト: structAnkit/Vintageous
        def f(view, s):
            eol = view.line(s.b).end()
            if not s.empty():
                eol = view.line(s.b - 1).end()

            match = s
            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, eol), eol)
                else:
                    search_range = sublime.Region(min(match.b, 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 sublime.Region(s.a, match.b)

            if match == s:
                utils.blink()
            return sublime.Region(match.a, match.a)
コード例 #2
0
        def f(view, s):
            if mode == _MODE_INTERNAL_NORMAL:
                x_limit = max(view.line(s.b).a, s.b - count)
                return sublime.Region(s.a, x_limit)

            elif mode == MODE_VISUAL:
                if s.a < s.b:
                    x_limit = max(view.line(s.b - 1).a + 1, s.b - count)
                    if view.line(s.a) == view.line(s.b - 1) and count >= s.size():
                        x_limit = max(view.line(s.b - 1).a, s.b - count - 1)
                        return sublime.Region(s.a + 1, x_limit)
                    return sublime.Region(s.a, x_limit)

                if s.a > s.b:
                    x_limit = max(view.line(s.b).a, s.b - count)
                    return sublime.Region(s.a, x_limit)

            elif mode == MODE_NORMAL:
                x_limit = max(view.line(s.b).a, s.b - count)
                if s.b == x_limit:
                    utils.blink()
                return sublime.Region(x_limit, x_limit)

            # XXX: We should never reach this.
            return s
コード例 #3
0
ファイル: motion_cmds.py プロジェクト: structAnkit/Vintageous
        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
コード例 #4
0
ファイル: state.py プロジェクト: quarnster/Vintageous
    def do_full_command(self):
        """Evaluates a command like 3dj, where there is an action as well as a motion.
        """
        vi_cmd_data = self.parse_motion()
        vi_cmd_data = self.parse_action(vi_cmd_data)

        if not vi_cmd_data['is_digraph_start']:
            # We are about to run an action, so let Sublime Text know we want all editing
            # steps folded into a single sequence. "All editing steps" means slightly different
            # things depending on the mode we are in.
            if vi_cmd_data['_mark_groups_for_gluing']:
                self.view.run_command('maybe_mark_undo_groups_for_gluing')
            self.view.run_command('vi_run', vi_cmd_data)
            self.reset()
        else:
            # If we have a digraph start, the global data is in an invalid state because we
            # are still missing the complete digraph. Abort and clean up.
            if vi_cmd_data['_exit_mode'] == MODE_INSERT:
                # We've been requested to change to this mode. For example, we're looking at
                # CTRL+r,j in INSERTMODE, which is an invalid sequence.
                # !!! This could be simplified using parameters in .reset(), but then it
                # wouldn't be obvious what was going on. Don't refactor. !!!
                utils.blink()
                self.reset()
                self.enter_insert_mode()
            elif self.mode != MODE_NORMAL:
                # Normally we'd go back to normal mode.
                self.enter_normal_mode()
                self.reset()
コード例 #5
0
ファイル: actions.py プロジェクト: nelk/Vintageous
    def run(self, edit, count=1, mode=None, subtract=False):
        if mode != _MODE_INTERNAL_NORMAL:
            return

        # TODO: Deal with octal, hex notations.
        # TODO: Improve detection of numbers.
        regs = list(self.view.sel())

        pts = self.find_next_num(regs)
        if not pts:
            utils.blink()
            return

        count = count if not subtract else -count
        end_sels = []
        for pt in reversed(pts):
            sign, num, tail = self.get_editable_data(pt)

            num_as_text = str((sign * num) + count)
            new_text = num_as_text + self.view.substr(tail)

            offset = 0
            if sign == -1:
                offset = -1
                self.view.replace(edit, sublime.Region(pt - 1, tail.b), new_text)
            else:
                self.view.replace(edit, sublime.Region(pt, tail.b), new_text)

            rowcol = self.view.rowcol(pt + len(num_as_text) - 1 + offset)
            end_sels.append(rowcol)

        self.view.sel().clear()
        for (row, col) in end_sels:
            self.view.sel().add(sublime.Region(self.view.text_point(row, col)))
コード例 #6
0
        def f(view, s):
            if mode == MODE_NORMAL:
                if view.line(s.b).empty():
                    utils.blink()
                    return s

                x_limit = min(view.line(s.b).b - 1, s.b + count, view.size())
                if s.b == x_limit:
                    utils.blink()
                return sublime.Region(x_limit, x_limit)

            if mode == _MODE_INTERNAL_NORMAL:
                x_limit = min(view.line(s.b).b, s.b + count)
                x_limit = max(0, x_limit)
                return sublime.Region(s.a, x_limit)

            if mode == MODE_VISUAL:
                if s.a < s.b:
                    x_limit = min(view.full_line(s.b - 1).b, s.b + count)
                    return sublime.Region(s.a, x_limit)

                if s.a > s.b:
                    x_limit = min(view.full_line(s.b).b - 1, s.b + count)
                    if view.substr(s.b) == "\n":
                        return s

                    if view.line(s.a) == view.line(s.b) and count >= s.size():
                        x_limit = min(view.full_line(s.b).b, s.b + count + 1)
                        return sublime.Region(s.a - 1, x_limit)

                    return sublime.Region(s.a, x_limit)

            return s
コード例 #7
0
ファイル: state.py プロジェクト: werkzeugh/Vintageous
    def eval(self):
        """Examines the current state and decides whether to actually run the action/motion.
        """

        if self.cancel_action:
            self.eval_cancel_action()
            self.reset()
            utils.blink()

        elif self.expecting_user_input:
            return

        # Action + motion, like in '3dj'.
        elif self.action and self.motion:
            self.eval_full_command()

        # Motion only, like in '3j'.
        elif self.motion:
            vi_cmd_data = self.parse_motion()
            self.view.run_command('vi_run', vi_cmd_data)
            self.reset()

        # Action only, like in 'd' or 'esc'. Some actions can be executed without a motion.
        elif self.action:
            self.eval_lone_action()
コード例 #8
0
ファイル: state.py プロジェクト: ahnan4arch/Vintageous
 def eval_cancel_action(self):
     """Cancels the whole run of the command.
     """
     # TODO: add a .parse() method that includes boths steps?
     vi_cmd_data = self.parse_motion()
     vi_cmd_data = self.parse_action(vi_cmd_data)
     if vi_cmd_data['must_blink_on_error']:
         utils.blink()
     # Modify the data that determines the mode we'll end up in when the command finishes.
     self.next_mode = vi_cmd_data['_exit_mode']
     # Since we are exiting early, ensure we leave the selections as the commands wants them.
     if vi_cmd_data['_exit_mode_command']:
         self.view.run_command(vi_cmd_data['_exit_mode_command'])
コード例 #9
0
ファイル: contexts.py プロジェクト: structAnkit/Vintageous
    def vi_can_enter_any_visual_mode(self, key, operator, operand, match_all):
        sels = self.state.view.sel()
        rv = True
        for sel in sels:
            # We're assuming we are in normal mode.
            if sel.b == self.state.view.size() and self.state.view.line(sel.b).empty():
                rv = False
                break

        if not rv:
            print("Vintageous: Can't enter visual mode at EOF if last line is empty.")
            utils.blink()

        return self._check(rv, operator, operand, match_all)
コード例 #10
0
    def vi_can_enter_any_visual_mode(self, key, operator, operand, match_all):
        sels = self.state.view.sel()
        rv = True
        for sel in sels:
            # We're assuming we are in normal mode.
            if sel.b == self.state.view.size() and self.state.view.line(sel.b).empty():
                rv = False
                break

        if not rv:
            print("Vintageous: Can't enter visual mode at EOF if last line is empty.")
            utils.blink()

        return self._check(rv, operator, operand, match_all)
コード例 #11
0
ファイル: actions.py プロジェクト: ahnan4arch/Vintageous
    def run(self, edit, count=1, mode=None):
        def f(view, s):
            if mode == _MODE_INTERNAL_NORMAL:

                word, match = next(pairs)
                sign, amount, suffix = match.groups()
                sign = -1 if sign else 1
                suffix = suffix or ''

                new_digit = (sign * int(amount)) - count
                view.replace(edit, word, str(new_digit) + suffix)

                offset = len(str(new_digit))
                # FIXME: Deal with multiple sels as we should.
                if len(view.sel()) == 1:
                    return sublime.Region(word.a + offset - 1)
                # return sublime.Region(word.b - len(suffix) - 1)

            return s

        if mode != _MODE_INTERNAL_NORMAL:
            return

        # TODO: Deal with octal, hex notations.
        # TODO: Improve detection of numbers.
        pairs = list(self.check_words(list(self.view.sel())))
        if not pairs:
            next_nums = self.find_next_num(list(self.view.sel()))
            if not next_nums:
                utils.blink()
                return
            pairs = iter(reversed(list(self.check_words(next_nums))))
        else:
            pairs = iter(reversed(list(self.check_words(self.view.sel()))))

        try:
            xpos = []
            if len(self.view.sel()) > 1:
                rowcols = [self.view.rowcol(s.b - 1) for s in self.view.sel()]
            regions_transformer_reversed(self.view, f)
            if len(self.view.sel()) > 1:
                regs = [sublime.Region(self.view.text_point(*rc)) for rc in rowcols]
                next_nums = self.find_next_num(regs)
                if next_nums:
                    self.view.sel().clear()
                    self.view.sel().add_all(next_nums)
        except StopIteration:
            utils.blink()
            return
コード例 #12
0
    def run(self, name=None):
        state = VintageState(self.view)
        state.cancel_macro = False
        if not (name and state.latest_macro_name):
            return

        if name == '@':
            # Run the macro recorded latest.
            commands = state.macros[state.latest_macro_name]
        else:
            try:
                commands = state.macros[name]
            except KeyError:
                # TODO: Add 'delayed message' support to VintageState.
                return

        for cmd in commands:
            if state.cancel_macro:
                utils.blink()
                break
            self.view.run_command(cmd['command'], cmd['args'])
コード例 #13
0
    def run(self, edit, count=1, mode=None):
        def f(view, s):
            if mode == _MODE_INTERNAL_NORMAL:
                word = view.word(s.a)
                new_digit = int(view.substr(word)) - count
                view.replace(edit, word, str(new_digit))

            return s

        if mode != _MODE_INTERNAL_NORMAL:
            return

        # TODO: Deal with octal, hex notations.
        # TODO: Improve detection of numbers.
        # TODO: Find the next numeric word in the line if none is found under the caret.
        words = [self.view.substr(self.view.word(s)) for s in self.view.sel()]
        if not all([w.isdigit() for w in words]):
            utils.blink()
            return

        regions_transformer(self.view, f)
コード例 #14
0
ファイル: actions.py プロジェクト: ahnan4arch/Vintageous
    def run(self, name=None):
        state = VintageState(self.view)
        state.cancel_macro = False
        if not (name and state.latest_macro_name):
            return

        if name == '@':
            # Run the macro recorded latest.
            commands = state.macros[state.latest_macro_name]
        else:
            try:
                commands = state.macros[name]
            except KeyError:
                # TODO: Add 'delayed message' support to VintageState.
                return

        for cmd in commands:
            if state.cancel_macro:
                utils.blink()
                break
            self.view.run_command(cmd['command'], cmd['args'])
コード例 #15
0
ファイル: actions.py プロジェクト: ahnan4arch/Vintageous
    def run(self, edit, count=1, mode=None):
        def f(view, s):
            if mode == _MODE_INTERNAL_NORMAL:
                word = view.word(s.a)
                new_digit = int(view.substr(word)) + count
                view.replace(edit, word, str(new_digit))

            return s

        if mode != _MODE_INTERNAL_NORMAL:
            return

        # TODO: Deal with octal, hex notations.
        # TODO: Improve detection of numbers.
        # TODO: Find the next numeric word in the line if none is found under the caret.
        words = [self.view.substr(self.view.word(s)) for s in self.view.sel()]
        if not all([w.isdigit() for w in words]):
            utils.blink()
            return

        regions_transformer(self.view, f)
コード例 #16
0
ファイル: motion_cmds.py プロジェクト: typopl/Vintageous
        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)
コード例 #17
0
ファイル: state.py プロジェクト: typopl/Vintageous
    def eval(self):
        """Examines the current state and decides whether to actually run the action/motion.
        """

        if self.cancel_action:
            self.eval_cancel_action()
            self.reset()
            utils.blink()

        # Action + motion, like in '3dj'.
        elif self.action and self.motion:
            self.eval_full_command()

        # Motion only, like in '3j'.
        elif self.motion:
            vi_cmd_data = self.parse_motion()
            self.view.run_command('vi_run', vi_cmd_data)
            self.reset()
            self.update_status()

        # Action only, like in 'd' or 'esc'. Some actions can be executed without a motion.
        elif self.action:
            self.eval_lone_action()
コード例 #18
0
ファイル: state.py プロジェクト: werkzeugh/Vintageous
    def eval_full_command(self):
        """Evaluates a command like 3dj, where there is an action as well as a motion.
        """
        vi_cmd_data = self.parse_motion()

        # Sometimes we'll have an incomplete motion, like in dg leading up to dgg. In this case,
        # we don't want the vi command evaluated just yet.
        if vi_cmd_data['is_digraph_start']:
            return

        vi_cmd_data = self.parse_action(vi_cmd_data)

        if not vi_cmd_data['is_digraph_start']:
            # We are about to run an action, so let Sublime Text know we want all editing
            # steps folded into a single sequence. "All editing steps" means slightly different
            # things depending on the mode we are in.
            if vi_cmd_data['_mark_groups_for_gluing']:
                self.view.run_command('maybe_mark_undo_groups_for_gluing')
            self.view.run_command('vi_run', vi_cmd_data)
            self.reset()
        else:
            # If we have a digraph start, the global data is in an invalid state because we
            # are still missing the complete digraph. Abort and clean up.
            if vi_cmd_data['_exit_mode'] == MODE_INSERT:
                # We've been requested to change to this mode. For example, we're looking at
                # CTRL+r,j in INSERTMODE, which is an invalid sequence.
                utils.blink()
                self.reset()
                self.enter_insert_mode()
            # We have an invalid command which consists in an action and a motion, like gl. Abort.
            elif (self.mode == MODE_NORMAL) and self.motion:
                utils.blink()
                self.reset()
            elif self.mode != MODE_NORMAL:
                # Normally we'd go back to normal mode.
                self.enter_normal_mode()
                self.reset()
コード例 #19
0
ファイル: state.py プロジェクト: DylanBruzenak/Vintageous
    def eval_full_command(self):
        """Evaluates a command like 3dj, where there is an action as well as a motion.
        """
        vi_cmd_data = self.parse_motion()

        # Sometimes we'll have an incomplete motion, like in dg leading up to dgg. In this case,
        # we don't want the vi command evaluated just yet.
        if vi_cmd_data['is_digraph_start']:
            return

        vi_cmd_data = self.parse_action(vi_cmd_data)

        if not vi_cmd_data['is_digraph_start']:
            # We are about to run an action, so let Sublime Text know we want all editing
            # steps folded into a single sequence. "All editing steps" means slightly different
            # things depending on the mode we are in.
            if vi_cmd_data['_mark_groups_for_gluing']:
                self.view.run_command('maybe_mark_undo_groups_for_gluing')
            self.view.run_command('vi_run', vi_cmd_data)
            self.reset()
        else:
            # If we have a digraph start, the global data is in an invalid state because we
            # are still missing the complete digraph. Abort and clean up.
            if vi_cmd_data['_exit_mode'] == MODE_INSERT:
                # We've been requested to change to this mode. For example, we're looking at
                # CTRL+r,j in INSERTMODE, which is an invalid sequence.
                utils.blink()
                self.reset()
                self.enter_insert_mode()
            # We have an invalid command which consists in an action and a motion, like gl. Abort.
            elif (self.mode == MODE_NORMAL) and self.motion:
                utils.blink()
                self.reset()
            elif self.mode != MODE_NORMAL:
                # Normally we'd go back to normal mode.
                self.enter_normal_mode()
                self.reset()
コード例 #20
0
ファイル: state.py プロジェクト: bahtou/sublConfig
    def eval(self):
        """Examines the current state and decides whether to actually run the action/motion.
        """

        if self.cancel_action:
            self.eval_cancel_action()
            self.reset()
            utils.blink()

        elif self.expecting_user_input:
            return

        # Action + motion, like in '3dj'.
        elif self.action and self.motion:
            # TODO: abstract this away into a function.
            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 read_only or self.view.is_read_only():
                self.reset()
                utils.blink()
                sublime.status_message("Vintageous: Readonly file.")
                return
            self.eval_full_command()

        # Motion only, like in '3j'.
        elif self.motion:
            vi_cmd_data = self.parse_motion()
            self.view.run_command('vi_run', vi_cmd_data)
            self.reset()

        # Action only, like in 'd' or 'esc'. Some actions can be executed without a motion.
        elif self.action:
            # TODO: abstract this away into a function.
            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 read_only or self.view.is_read_only():
                self.reset()
                utils.blink()
                sublime.status_message("Vintageous: Readonly file.")
                return
            self.eval_lone_action()
コード例 #21
0
    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')
コード例 #22
0
ファイル: run.py プロジェクト: ahnan4arch/Vintageous
    def run(self, edit, **vi_cmd_data):
        self.debug("Data in ViRunCommand:", vi_cmd_data)

        state = VintageState(self.view)

        try:
            # Always save carets just in case.
            self.save_caret_pos()

            # If we're about to jump, we need to remember the current position so we can jump back
            # here. XXX creates_jump_at_current_position might be redundant.
            # TODO: Extract method.
            if vi_cmd_data['creates_jump_at_current_position'] or vi_cmd_data['is_jump']:
                self.add_to_jump_list(vi_cmd_data)

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

            # 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.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 .restore_original_carets_if_needed() in this event?
                        if (vi_cmd_data['mode'] in (_MODE_INTERNAL_NORMAL, MODE_VISUAL) and
                            any([(old == new) for (old, new) in zip(sels_before_motion, list(self.view.sel()))]) and
                            vi_cmd_data['cancel_action_if_motion_fails']):
                                # TODO: There should be a method that lets us do this without modifying vi_cmd_data.
                                vi_cmd_data['restore_original_carets'] = True
                                # FIXME: This is redundant: we call the same method in 'finally' clause.
                                self.restore_original_carets_if_needed(vi_cmd_data)
                                utils.blink()
                                state.cancel_macro = True
                                return

                self.reorient_begin_to_end(vi_cmd_data)
                self.do_action(vi_cmd_data)
            else:
                self.do_whole_motion(vi_cmd_data)
                if (vi_cmd_data['mode'] == MODE_NORMAL and
                    any([(old == new) for (old, new) in zip(sels_before_motion, list(self.view.sel()))])):
                        state.cancel_macro = True
                        utils.blink()

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

            # TODO: Extract method.
            if vi_cmd_data['must_update_xpos']:
                state = VintageState(self.view)
                state.update_xpos()

            self.do_modify_selections(vi_cmd_data)
            self.restore_original_carets_if_needed(vi_cmd_data)

            # TODO: Extract method.
            if vi_cmd_data['scroll_into_view']:
                if vi_cmd_data['scroll_command']:
                    self.view.run_command(*vi_cmd_data['scroll_command'])
                else:
                    # TODO: If moving by lines, scroll the minimum amount to display the new sels.
                    self.view.show(self.view.sel()[0])

            # We cannot run (maybe_)mark_undo_groups_for_gluing/glue_marked_undo_groups commands
            # within a command meant to be subsumed in the group to be glued. It won't work. So
            # let's save the data we need to transtion to the next mode, which will be taken care
            # of later by VintageState.reset().
            # XXX: This code can probably be moved to VintageState.run().
            # TODO: Extract method.
            state = VintageState(self.view)
            state.next_mode = vi_cmd_data['next_mode']
            state.next_mode_command = vi_cmd_data['follow_up_mode']
コード例 #23
0
        def f(view, s):
            if mode == MODE_NORMAL:
                current_row = view.rowcol(s.b)[0]
                target_row = min(current_row + count, view.rowcol(view.size())[0])
                target_pt = view.text_point(target_row, 0)

                if current_row == view.rowcol(view.size())[0]:
                    utils.blink()

                if view.line(target_pt).empty():
                    return sublime.Region(target_pt, target_pt)

                target_pt = min(target_pt + xpos, view.line(target_pt).b - 1)
                return sublime.Region(target_pt, target_pt)

            if mode == _MODE_INTERNAL_NORMAL:
                current_row = view.rowcol(s.b)[0]
                target_row = min(current_row + count, view.rowcol(view.size())[0])
                target_pt = view.text_point(target_row, 0)
                return sublime.Region(view.line(s.a).a, view.full_line(target_pt).b)

            if mode == MODE_VISUAL:
                exact_position = s.b - 1 if (s.a < s.b) else s.b
                current_row = view.rowcol(exact_position)[0]
                target_row = min(current_row + count, view.rowcol(view.size())[0])
                target_pt = view.text_point(target_row, 0)
                is_long_enough = view.full_line(target_pt).size() > xpos

                # We're crossing over to the other side of .a; we need to modify .a.
                crosses_a = False
                if (s.a > s.b) and (view.rowcol(s.a)[0] < target_row):
                    crosses_a = True

                if view.line(s.begin()) == view.line(s.end() - 1):
                    if s.a > s.b:
                        if is_long_enough:
                            return sublime.Region(s.a - 1, view.text_point(target_row, xpos) + 1)
                        else:
                            return sublime.Region(s.a - 1, view.full_line(target_pt).b)

                # Returning to the same line...
                if not crosses_a and abs(view.rowcol(s.begin())[0] - view.rowcol(s.end())[0]) == 1:
                    if s.a > s.b:
                        if is_long_enough:
                            if view.rowcol(s.a - 1)[1] <= view.rowcol(s.b)[1]:
                                return sublime.Region(s.a - 1, view.text_point(target_row, xpos) + 1)

                if is_long_enough:
                    if s.a < s.b:
                        return sublime.Region(s.a, view.text_point(target_row, xpos) + 1)
                    elif s.a > s.b:
                        start = s.a if not crosses_a else s.a - 1
                        end = view.text_point(target_row, xpos)
                        if crosses_a and xpos == 0:
                            end += 1
                        return sublime.Region(start, end)
                else:
                    if s.a < s.b:
                        return sublime.Region(s.a, view.full_line(target_pt).b)
                    elif s.a > s.b:
                        end = view.full_line(target_pt).b
                        end = end - 1 if not crosses_a else end
                        return sublime.Region(s.a, end)

            if mode == MODE_VISUAL_LINE:
                if s.a < s.b:
                    current_row = view.rowcol(s.b - 1)[0]
                    target_row = min(current_row + count, view.rowcol(view.size())[0])

                    target_pt = view.text_point(target_row, 0)
                    return sublime.Region(s.a, view.full_line(target_pt).b)

                elif s.a > s.b:
                    current_row = view.rowcol(s.b)[0]
                    target_row = min(current_row + count, view.rowcol(view.size())[0])
                    target_pt = view.text_point(target_row, 0)

                    if target_row > view.rowcol(s.a - 1)[0]:
                        return sublime.Region(view.line(s.a - 1).a, view.full_line(target_pt).b)

                    return sublime.Region(s.a, view.full_line(target_pt).a)

            return s
コード例 #24
0
ファイル: ex_commands.py プロジェクト: klorenz/Vintageous
    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 = VintageState(self.window.active_view())
        if state.mode != MODE_NORMAL:
            state.enter_normal_mode()
            self.window.run_command('vi_enter_normal_mode')
コード例 #25
0
    def run(self, edit, **vi_cmd_data):
        self.debug("Data in ViRunCommand:", vi_cmd_data)

        state = VintageState(self.view)

        try:
            # Always save carets just in case.
            self.save_caret_pos()

            # If we're about to jump, we need to remember the current position so we can jump back
            # here. XXX creates_jump_at_current_position might be redundant.
            # TODO: Extract method.
            if vi_cmd_data['creates_jump_at_current_position'] or vi_cmd_data[
                    'is_jump']:
                self.add_to_jump_list(vi_cmd_data)

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

            # 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.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 .restore_original_carets_if_needed() in this event?
                    if (vi_cmd_data['mode']
                            in (_MODE_INTERNAL_NORMAL, MODE_VISUAL)
                            and any([(old == new) for (old, new) in zip(
                                sels_before_motion, list(self.view.sel()))])
                            and vi_cmd_data['cancel_action_if_motion_fails']):
                        # TODO: There should be a method that lets us do this without modifying vi_cmd_data.
                        vi_cmd_data['restore_original_carets'] = True
                        # FIXME: This is redundant: we call the same method in 'finally' clause.
                        self.restore_original_carets_if_needed(vi_cmd_data)
                        utils.blink()
                        state.cancel_macro = True
                        return

                self.do_action(vi_cmd_data)
            else:
                self.do_whole_motion(vi_cmd_data)
                if (vi_cmd_data['mode'] == MODE_NORMAL
                        and any([(old == new) for (old, new) in zip(
                            sels_before_motion, list(self.view.sel()))])):
                    state.cancel_macro = True
                    utils.blink()

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

            # TODO: Extract method.
            if vi_cmd_data['must_update_xpos']:
                state = VintageState(self.view)
                state.update_xpos()

            self.do_modify_selections(vi_cmd_data)
            self.restore_original_carets_if_needed(vi_cmd_data)

            # TODO: Extract method.
            if vi_cmd_data['scroll_into_view']:
                if vi_cmd_data['scroll_command']:
                    self.view.run_command(*vi_cmd_data['scroll_command'])
                else:
                    # TODO: If moving by lines, scroll the minimum amount to display the new sels.
                    self.view.show(self.view.sel()[0])

            # We cannot run (maybe_)mark_undo_groups_for_gluing/glue_marked_undo_groups commands
            # within a command meant to be subsumed in the group to be glued. It won't work. So
            # let's save the data we need to transtion to the next mode, which will be taken care
            # of later by VintageState.reset().
            # XXX: This code can probably be moved to VintageState.run().
            # TODO: Extract method.
            state = VintageState(self.view)
            state.next_mode = vi_cmd_data['next_mode']
            state.next_mode_command = vi_cmd_data['follow_up_mode']
コード例 #26
0
ファイル: state.py プロジェクト: Web5design/Vintageous
    def run(self):
        """Examines the current state and decides whether to actually run the action/motion.
        """

        if self.cancel_action:
            # TODO: add a .parse() method that includes boths steps?
            vi_cmd_data = self.parse_motion()
            vi_cmd_data = self.parse_action(vi_cmd_data)
            if vi_cmd_data['must_blink_on_error']:
                utils.blink()
            self.reset(next_mode=vi_cmd_data['_exit_mode'])
            return

        # Action + motion, like in "3dj".
        if self.action and self.motion:
            vi_cmd_data = self.parse_motion()
            vi_cmd_data = self.parse_action(vi_cmd_data)

            if not vi_cmd_data['is_digraph_start']:
                self.view.run_command('vi_run', vi_cmd_data)
            else:
                # If we have a digraph start, the global data is in an invalid state because we
                # are still missing the complete digraph. Abort and clean up.
                if vi_cmd_data['_exit_mode'] == MODE_INSERT:
                    # We've been requested to change to this mode. For example, we're looking at
                    # CTRL+r,j in INSERTMODE, which is an invalid sequence.
                    # !!! This could be simplified using parameters in .reset(), but then it
                    # wouldn't be obvious what was going on. Don't refactor. !!!
                    utils.blink()
                    self.reset()
                    self.enter_insert_mode()
                elif self.mode != MODE_NORMAL:
                    # Normally we'd go back to normal mode.
                    self.enter_normal_mode()
                    self.reset()

        # Motion only, like in "3j".
        elif self.motion:
            self.view.run_command('vi_run', self.parse_motion())

        # Action only, like in "d" or "esc". Some actions can be executed without a motion.
        elif self.action:
            vi_cmd_data = self.parse_motion()
            vi_cmd_data = self.parse_action(vi_cmd_data)

            if vi_cmd_data['is_digraph_start']:
                if vi_cmd_data['_change_mode_to']:
                    if vi_cmd_data['_change_mode_to'] == MODE_NORMAL:
                        self.enter_normal_mode()
                # We know we are not ready.
                return

            # In cases like gg, we might receive the motion here, so check for that.
            if self.motion and not self.action:
                self.view.run_command('vi_run', self.parse_motion())
                self.update_status()
                return

            if not vi_cmd_data['motion_required']:
                self.view.run_command('vi_run', vi_cmd_data)

        self.update_status()
コード例 #27
0
ファイル: state.py プロジェクト: structAnkit/Vintageous
    def eval(self):
        """Examines the current state and decides whether to actually run the action/motion.
        """

        if self.cancel_action:
            # TODO: add a .parse() method that includes boths steps?
            vi_cmd_data = self.parse_motion()
            vi_cmd_data = self.parse_action(vi_cmd_data)
            if vi_cmd_data["must_blink_on_error"]:
                utils.blink()
            # Modify the data that determines the mode we'll end up in when the command finishes.
            self.next_mode = vi_cmd_data["_exit_mode"]
            # Since we are exiting early, ensure we leave the selections as the commands wants them.
            if vi_cmd_data["_exit_mode_command"]:
                self.view.run_command(vi_cmd_data["_exit_mode_command"])
            self.reset()
            return

        # Action + motion, like in "3dj".
        if self.action and self.motion:
            vi_cmd_data = self.parse_motion()
            vi_cmd_data = self.parse_action(vi_cmd_data)

            if not vi_cmd_data["is_digraph_start"]:
                # We are about to run an action, so let Sublime Text know we want all editing
                # steps folded into a single sequence. "All editing steps" means slightly different
                # things depending on the mode we are in.
                if vi_cmd_data["_mark_groups_for_gluing"]:
                    self.view.run_command("maybe_mark_undo_groups_for_gluing")
                self.view.run_command("vi_run", vi_cmd_data)
                self.reset()
            else:
                # If we have a digraph start, the global data is in an invalid state because we
                # are still missing the complete digraph. Abort and clean up.
                if vi_cmd_data["_exit_mode"] == MODE_INSERT:
                    # We've been requested to change to this mode. For example, we're looking at
                    # CTRL+r,j in INSERTMODE, which is an invalid sequence.
                    # !!! This could be simplified using parameters in .reset(), but then it
                    # wouldn't be obvious what was going on. Don't refactor. !!!
                    utils.blink()
                    self.reset()
                    self.enter_insert_mode()
                elif self.mode != MODE_NORMAL:
                    # Normally we'd go back to normal mode.
                    self.enter_normal_mode()
                    self.reset()

        # Motion only, like in '3j'.
        elif self.motion:
            vi_cmd_data = self.parse_motion()
            self.view.run_command("vi_run", vi_cmd_data)
            self.reset()

        # Action only, like in "d" or "esc". Some actions can be executed without a motion.
        elif self.action:
            vi_cmd_data = self.parse_motion()
            vi_cmd_data = self.parse_action(vi_cmd_data)

            if vi_cmd_data["is_digraph_start"]:
                if vi_cmd_data["_change_mode_to"]:
                    # XXX: When does this happen? Why are we only interested in MODE_NORMAL?
                    # XXX In response to the above, this must be due to Ctrl+r.
                    if vi_cmd_data["_change_mode_to"] == MODE_NORMAL:
                        self.enter_normal_mode()
                # We know we are not ready.
                return

            # In cases like gg, we might receive the motion here, so check for that.
            # XXX: The above doesn't seem to be true. When is this path reached?
            if self.motion and not self.action:
                self.view.run_command("vi_run", self.parse_motion())
                self.update_status()
                self.reset()
                return

            if not vi_cmd_data["motion_required"]:
                # We are about to run an action, so let Sublime Text know we want all editing
                # steps folded into a single sequence. "All editing steps" means slightly different
                # things depending on the mode we are in.
                if vi_cmd_data["_mark_groups_for_gluing"]:
                    self.view.run_command("maybe_mark_undo_groups_for_gluing")
                self.view.run_command("vi_run", vi_cmd_data)
                self.reset()

        self.update_status()