Пример #1
0
    def collect_input(self):
        try:
            command = None
            if self.state.motion and self.state.action:
                if self.state.motion.accept_input:
                    command = self.state.motion
                else:
                    command = self.state.action
            else:
                command = self.state.action or self.state.motion

            parser_def = command.input_parser
            if parser_def.interactive_command:

                self.window.run_command(parser_def.interactive_command,
                                        {parser_def.input_param: command._inp})
        except IndexError:
            _log.debug('could not find a command to collect more user input')
            ui_blink()
        finally:
            self.state.non_interactive = False
Пример #2
0
def _do_C(view, edit, mode, count=1, motion=None):
    def f(view, s):
        return Region(s.begin())

    if motion:
        view.run_command(motion['motion'], motion['motion_args'])
    elif mode not in (VISUAL, VISUAL_LINE):
        return ui_blink()

    view.run_command('toggle_comment', {'block': True})
    regions_transformer(view, f)
    enter_normal_mode(view, mode)
Пример #3
0
    def _next_history(self, edit, backwards):
        if self.view.size() == 0:
            raise RuntimeError('expected a non-empty command-line')

        firstc = self.view.substr(0)
        if not history_get_type(firstc):
            raise RuntimeError('expected a valid command-line')

        if _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX is None:
            _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX = -1 if backwards else 0
        else:
            _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX += -1 if backwards else 1

        count = history_len(firstc)
        if count == 0:
            _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX = None

            return ui_blink()

        if abs(_nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX) > count:
            _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX = -count

            return ui_blink()

        if _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX >= 0:
            _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX = 0

            if self.view.size() > 1:
                return self.view.erase(edit, Region(1, self.view.size()))
            else:
                return ui_blink()

        if self.view.size() > 1:
            self.view.erase(edit, Region(1, self.view.size()))

        item = history_get(firstc,
                           _nv_cmdline_feed_key.LAST_HISTORY_ITEM_INDEX)
        if item:
            self.view.insert(edit, 1, item)
Пример #4
0
def _do_c(view, edit, mode, count=1, motion=None):
    def f(view, s):
        return Region(s.begin())

    if motion:
        view.run_command(motion['motion'], motion['motion_args'])
    elif mode not in (VISUAL, VISUAL_LINE):
        return ui_blink()

    view.run_command('toggle_comment', {'block': False})

    regions_transformer(view, f)

    line = view.line(view.sel()[0].begin())
    pt = line.begin()

    if line.size() > 0:
        line = view.find('^\\s*', line.begin())
        pt = line.end()

    view.sel().clear()
    view.sel().add(pt)
    enter_normal_mode(view, mode)
Пример #5
0
    def run(self, keys, repeat_count=None, check_user_mappings=True):
        state = self.state
        _log.debug('process notation keys \'%s\', mode \'%s\'', keys,
                   state.mode)
        initial_mode = state.mode
        # Disable interactive prompts. For example, to supress interactive
        # input collection in /foo<CR>.
        state.non_interactive = True

        # First, run any motions coming before the first action. We don't keep
        # these in the undo stack, but they will still be repeated via '.'.
        # This ensures that undoing will leave the caret where the  first
        # editing action started. For example, 'lldl' would skip 'll' in the
        # undo history, but store the full sequence for '.' to use.
        leading_motions = ''
        for key in KeySequenceTokenizer(keys).iter_tokenize():
            self.window.run_command(
                'press_key', {
                    'key': key,
                    'do_eval': False,
                    'repeat_count': repeat_count,
                    'check_user_mappings': check_user_mappings
                })
            if state.action:
                # The last key press has caused an action to be primed. That
                # means there are no more leading motions. Break out of here.
                _log.debug('[process_notation] first action found in \'%s\'',
                           state.sequence)
                state.reset_command_data()
                if state.mode == OPERATOR_PENDING:
                    state.mode = NORMAL

                break

            elif state.runnable():
                # Run any primed motion.
                leading_motions += state.sequence
                state.eval()
                state.reset_command_data()

            else:
                # XXX: When do we reach here?
                state.eval()

        if state.must_collect_input:
            # State is requesting more input, so this is the last command in
            # the sequence and it needs more input.
            self.collect_input()
            return

        # Strip the already run commands
        if leading_motions:
            if ((len(leading_motions) == len(keys))
                    and (not state.must_collect_input)):
                state.non_interactive = False
                return

            _log.debug(
                '[process_notation] original seq/leading motions: %s/%s', keys,
                leading_motions)
            keys = keys[len(leading_motions):]
            _log.debug('[process_notation] seq stripped to \'%s\'', keys)

        if not (state.motion and not state.action):
            with gluing_undo_groups(self.window.active_view(), state):
                try:
                    for key in KeySequenceTokenizer(keys).iter_tokenize():
                        if key.lower() == key_names.ESC:
                            # XXX: We should pass a mode here?
                            self.window.run_command('_enter_normal_mode')
                            continue

                        elif state.mode not in (INSERT, REPLACE):
                            self.window.run_command(
                                'press_key', {
                                    'key': key,
                                    'repeat_count': repeat_count,
                                    'check_user_mappings': check_user_mappings
                                })
                        else:
                            self.window.run_command(
                                'insert', {'characters': translate_char(key)})

                    if not state.must_collect_input:
                        return

                finally:
                    state.non_interactive = False
                    # Ensure we set the full command for '.' to use, but don't
                    # store '.' alone.
                    if (leading_motions + keys) not in ('.', 'u', '<C-r>'):
                        state.repeat_data = ('vi', (leading_motions + keys),
                                             initial_mode, None)

        # We'll reach this point if we have a command that requests input
        # whose input parser isn't satistied. For example, `/foo`. Note that
        # `/foo<CR>`, on the contrary, would have satisfied the parser.
        _log.debug(
            '[process_notation] unsatisfied parser action=\'%s\', motion=\'%s\'',
            state.action, state.motion)
        if (state.action and state.motion):
            # We have a parser an a motion that can collect data. Collect data
            # interactively.
            motion_data = state.motion.translate(state) or None

            if motion_data is None:
                state.reset_command_data()

                return ui_blink()

            motion_data['motion_args']['default'] = state.motion._inp

            self.window.run_command(motion_data['motion'],
                                    motion_data['motion_args'])

            return

        self.collect_input()
Пример #6
0
    def run(self,
            key,
            repeat_count=None,
            do_eval=True,
            check_user_mappings=True):
        _log.info(
            'key evt: %s repeat_count=%s do_eval=%s check_user_mappings=%s',
            key, repeat_count, do_eval, check_user_mappings)  # noqa: E501
        state = self.state

        # If the user has made selections with the mouse, we may be in an
        # inconsistent state. Try to remedy that.
        if (state.view.has_non_empty_selection_region() and state.mode
                not in (VISUAL, VISUAL_LINE, VISUAL_BLOCK, SELECT)):
            init_state(state.view)

        if key.lower() == '<esc>':
            self.window.run_command('_enter_normal_mode', {'mode': state.mode})
            state.reset_command_data()

            return

        state.sequence += key
        state.display_status()

        if state.must_capture_register_name:
            _log.debug('capturing register name...')
            state.register = key
            state.partial_sequence = ''

            return

        if state.must_collect_input:
            _log.debug('collecting input...')
            state.process_input(key)
            if state.runnable():
                _log.debug('state is runnable')
                if do_eval:
                    _log.debug('evaluating state...')
                    state.eval()
                    state.reset_command_data()

            return

        if repeat_count:
            state.action_count = str(repeat_count)

        if self._handle_count(state, key, repeat_count):
            _log.debug('handled count')

            return

        state.partial_sequence += key

        if check_user_mappings and mappings_is_incomplete(
                state.mode, state.partial_sequence):
            _log.debug('found incomplete mapping')

            return

        command = mappings_resolve(state,
                                   check_user_mappings=check_user_mappings)

        if isinstance(command, ViOpenRegister):
            _log.debug('opening register...')
            state.must_capture_register_name = True

            return

        # XXX: This doesn't seem to be correct. If we are in OPERATOR_PENDING mode, we should
        # most probably not have to wipe the state.
        if isinstance(command, Mapping):
            _log.debug('found user mapping...')

            if do_eval:
                _log.debug('evaluating user mapping...')

                new_keys = command.mapping
                if state.mode == OPERATOR_PENDING:
                    new_keys = state.sequence[:-len(state.partial_sequence
                                                    )] + command.mapping
                reg = state.register
                acount = state.action_count
                mcount = state.motion_count
                state.reset_command_data()
                state.register = reg
                state.motion_count = mcount
                state.action_count = acount

                _log.info('user mapping %s -> %s', key, new_keys)

                # Support for basic Command-line mode mappings:
                #
                # `:Command<CR>` maps to Sublime Text command (starts with uppercase letter).
                # `:command<CR>` maps to Command-line mode command.

                if ':' in new_keys:
                    match = re.match(
                        '^\\:(?P<cmd_line_command>[a-zA-Z][a-zA-Z_]*)\\<CR\\>',
                        new_keys)
                    if match:
                        cmd_line_command = match.group('cmd_line_command')
                        if cmd_line_command[0].isupper():
                            # run regular sublime text command
                            def _coerce_to_snakecase(string):
                                string = re.sub(r"([A-Z]+)([A-Z][a-z])",
                                                r'\1_\2', string)
                                string = re.sub(r"([a-z\d])([A-Z])", r'\1_\2',
                                                string)
                                string = string.replace("-", "_")

                                return string.lower()

                            command = _coerce_to_snakecase(cmd_line_command)
                            command_args = {}
                        else:
                            command = 'vi_colon_input'
                            command_args = {'cmd_line': ':' + cmd_line_command}

                        _log.info('run command -> %s %s', command,
                                  command_args)

                        return self.window.run_command(command, command_args)

                    if ':' == new_keys:
                        return self.window.run_command('vi_colon_input')

                    return console_message(
                        'invalid command line mapping %s -> %s (only `:[a-zA-Z][a-zA-Z_]*<CR>` is supported)'
                        % (command.head, command.mapping))  # noqa: E501

                self.window.run_command('process_notation', {
                    'keys': new_keys,
                    'check_user_mappings': False
                })

            return

        if isinstance(command, ViOpenNameSpace):
            # Keep collecting input to complete the sequence. For example, we
            # may have typed 'g'
            _log.info('opening namespace')

            return

        elif isinstance(command, ViMissingCommandDef):
            _log.info('found missing command...')

            bare_seq = to_bare_command_name(state.sequence)
            if state.mode == OPERATOR_PENDING:
                # We might be looking at a command like 'dd'. The first 'd' is
                # mapped for normal mode, but the second is missing in
                # operator pending mode, so we get a missing command. Try to
                # build the full command now.
                #
                # Exclude user mappings, since they've already been given a
                # chance to evaluate.
                command = mappings_resolve(state,
                                           sequence=bare_seq,
                                           mode=NORMAL,
                                           check_user_mappings=False)
            else:
                command = mappings_resolve(state, sequence=bare_seq)

            if isinstance(command, ViMissingCommandDef):
                _log.debug('unmapped sequence %s', state.sequence)
                state.mode = NORMAL
                state.reset_command_data()

                return ui_blink()

        if (state.mode == OPERATOR_PENDING
                and isinstance(command, ViOperatorDef)):
            _log.info('found operator pending...')
            # TODO: This may be unreachable code by now. ???
            # we're expecting a motion, but we could still get an action.
            # For example, dd, g~g~ or g~~
            # remove counts
            action_seq = to_bare_command_name(state.sequence)
            _log.debug('action sequence %s', action_seq)
            command = mappings_resolve(state, sequence=action_seq, mode=NORMAL)
            # TODO: Make _missing a command.
            if isinstance(command, ViMissingCommandDef):
                _log.debug('unmapped sequence %s', state.sequence)
                state.reset_command_data()
                return

            if not command['motion_required']:
                state.mode = NORMAL

        state.set_command(command)

        if state.mode == OPERATOR_PENDING:
            state.reset_partial_sequence()

        if do_eval:
            _log.info('evaluating state...')
            state.eval()
Пример #7
0
    def _feed_key(self,
                  key,
                  repeat_count=None,
                  do_eval=True,
                  check_user_mappings=True):
        # Args:
        #   key (str): Key pressed.
        #   repeat_count (int): Count to be used when repeating through the '.' command.
        #   do_eval (bool): Whether to evaluate the global state when it's in a
        #       runnable state. Most of the time, the default value of `True` should
        #       be used. Set to `False` when you want to manually control the global
        #       state's evaluation. For example, this is what the _nv_feed_key
        #       command does.
        #   check_user_mappings (bool):
        state = self.state

        mode = state.mode

        _log.debug('mode: %s', mode)

        # If the user has made selections with the mouse, we may be in an
        # inconsistent state. Try to remedy that.
        if (state.view.has_non_empty_selection_region()
                and mode not in (VISUAL, VISUAL_LINE, VISUAL_BLOCK, SELECT)):
            init_state(state.view)

        if key.lower() == '<esc>':
            self.window.run_command('_enter_normal_mode', {'mode': mode})
            state.reset_command_data()

            return

        state.sequence += key
        state.display_status()

        if state.must_capture_register_name:
            _log.debug('capturing register name...')
            state.register = key
            state.partial_sequence = ''

            return

        if state.must_collect_input:
            _log.debug('collecting input...')
            state.process_input(key)
            if state.runnable():
                _log.debug('state is runnable')
                if do_eval:
                    _log.debug('evaluating state...')
                    state.eval()
                    state.reset_command_data()

            return

        if repeat_count:
            state.action_count = str(repeat_count)

        if self._handle_count(state, key, repeat_count):
            _log.debug('handled count')

            return

        state.partial_sequence += key

        if check_user_mappings and mappings_is_incomplete(
                state.mode, state.partial_sequence):
            _log.debug('found incomplete mapping')

            return

        command = mappings_resolve(state,
                                   check_user_mappings=check_user_mappings)
        _log.debug('command %s %s', command, command.__class__.__mro__)

        if isinstance(command, ViOpenRegister):
            _log.debug('opening register...')
            state.must_capture_register_name = True

            return

        # XXX: This doesn't seem to be correct. If we are in OPERATOR_PENDING mode, we should
        # most probably not have to wipe the state.
        if isinstance(command, Mapping):
            _log.debug('found user mapping...')

            if do_eval:
                _log.debug('evaluating user mapping (mode=%s)...', state.mode)

                new_keys = command.mapping
                if state.mode == OPERATOR_PENDING:
                    new_keys = state.sequence[:-len(state.partial_sequence
                                                    )] + command.mapping
                reg = state.register
                acount = state.action_count
                mcount = state.motion_count
                state.reset_command_data()
                state.register = reg
                state.motion_count = mcount
                state.action_count = acount

                _log.info('user mapping %s -> %s', command.sequence, new_keys)

                if ':' in new_keys:
                    do_ex_user_cmdline(self.window, new_keys)

                    return

                self.window.run_command('_nv_process_notation', {
                    'keys': new_keys,
                    'check_user_mappings': False
                })

            return

        if isinstance(command, ViOpenNameSpace):
            # Keep collecting input to complete the sequence. For example, we
            # may have typed 'g'
            _log.info('opening namespace')

            return

        elif isinstance(command, ViMissingCommandDef):
            _log.info('found missing command...')

            bare_seq = to_bare_command_name(state.sequence)
            if state.mode == OPERATOR_PENDING:
                # We might be looking at a command like 'dd'. The first 'd' is
                # mapped for normal mode, but the second is missing in
                # operator pending mode, so we get a missing command. Try to
                # build the full command now.
                #
                # Exclude user mappings, since they've already been given a
                # chance to evaluate.
                command = mappings_resolve(state,
                                           sequence=bare_seq,
                                           mode=NORMAL,
                                           check_user_mappings=False)
            else:
                command = mappings_resolve(state, sequence=bare_seq)

            if isinstance(command, ViMissingCommandDef):
                _log.debug('unmapped sequence %s', state.sequence)
                state.mode = NORMAL
                state.reset_command_data()

                return ui_blink()

        if (state.mode == OPERATOR_PENDING
                and isinstance(command, ViOperatorDef)):
            _log.info('found operator pending...')
            # TODO: This may be unreachable code by now. ???
            # we're expecting a motion, but we could still get an action.
            # For example, dd, g~g~ or g~~
            # remove counts
            action_seq = to_bare_command_name(state.sequence)
            _log.debug('action sequence %s', action_seq)
            command = mappings_resolve(state, sequence=action_seq, mode=NORMAL)
            if isinstance(command, ViMissingCommandDef):
                _log.debug('unmapped sequence %s', state.sequence)
                state.reset_command_data()

                return

            if not command['motion_required']:
                state.mode = NORMAL

        state.set_command(command)

        if state.mode == OPERATOR_PENDING:
            state.reset_partial_sequence()

        if do_eval:
            _log.info('evaluating state...')
            state.eval()