def one_char(in_): # Any input (character) satisfies this parser. # # Args: # in_ (str): # # Returns # bool: True if in_ is one character in length, False otherwise. return len(translate_char(in_)) == 1
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 accept(self, key): self.inp += translate_char(key) return True