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
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)
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)
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)
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()
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()
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()