def _bind_current_default(key, info): """Get current/default data for the given key.""" data = [] try: seq = keyutils.KeySequence.parse(key) except keyutils.KeyParseError as e: data.append(('', str(e), key)) return data cmd_text = info.keyconf.get_command(seq, 'normal') if cmd_text: parser = runners.CommandParser() try: cmd = parser.parse(cmd_text).cmd except cmdexc.NoSuchCommandError: data.append((cmd_text, '(Current) Invalid command!', key)) else: data.append((cmd_text, '(Current) {}'.format(cmd.desc), key)) cmd_text = info.keyconf.get_command(seq, 'normal', default=True) if cmd_text: parser = runners.CommandParser() cmd = parser.parse(cmd_text).cmd data.append((cmd_text, '(Default) {}'.format(cmd.desc), key)) return data
def bind(key, *, info): """A CompletionModel filled with all bindable commands and descriptions. Args: key: the key being bound. """ model = completionmodel.CompletionModel(column_widths=(20, 60, 20)) data = [] cmd_text = info.keyconf.get_command(key, 'normal') if cmd_text: parser = runners.CommandParser() try: cmd = parser.parse(cmd_text).cmd except cmdexc.NoSuchCommandError: data.append((cmd_text, '(Current) Invalid command!', key)) else: data.append((cmd_text, '(Current) {}'.format(cmd.desc), key)) cmd_text = info.keyconf.get_command(key, 'normal', default=True) if cmd_text: parser = runners.CommandParser() cmd = parser.parse(cmd_text).cmd data.append((cmd_text, '(Default) {}'.format(cmd.desc), key)) if data: model.add_category(listcategory.ListCategory("Current/Default", data)) cmdlist = util.get_cmd_completions(info, include_hidden=True, include_aliases=True) model.add_category(listcategory.ListCategory("Commands", cmdlist)) return model
def _partition(self): """Divide the commandline text into chunks around the cursor position. Return: ([parts_before_cursor], 'part_under_cursor', [parts_after_cursor]) """ text = self._cmd.text()[len(self._cmd.prefix()):] if not text or not text.strip(): # Only ":", empty part under the cursor with nothing before/after return [], '', [] parser = runners.CommandParser() result = parser.parse(text, fallback=True, keep=True) parts = [x for x in result.cmdline if x] pos = self._cmd.cursorPosition() - len(self._cmd.prefix()) pos = min(pos, len(text)) # Qt treats 2-byte UTF-16 chars as 2 chars log.completion.debug('partitioning {} around position {}'.format(parts, pos)) for i, part in enumerate(parts): pos -= len(part) if pos <= 0: if part[pos-1:pos+1].isspace(): # cursor is in a space between two existing words parts.insert(i, '') prefix = [x.strip() for x in parts[:i]] center = parts[i].strip() # strip trailing whitespace included as a separate token postfix = [x.strip() for x in parts[i+1:] if not x.isspace()] log.completion.debug( "partitioned: {} '{}' {}".format(prefix, center, postfix)) return prefix, center, postfix raise utils.Unreachable("Not all parts consumed: {}".format(parts))
def bind(self, key, command, *, mode, force=False, save_yaml=False): """Add a new binding from key to command.""" key = self._prepare(key, mode) parser = runners.CommandParser() try: results = parser.parse_all(command) except cmdexc.Error as e: raise configexc.KeybindingError("Invalid command: {}".format(e)) for result in results: # pragma: no branch try: result.cmd.validate_mode(usertypes.KeyMode[mode]) except cmdexc.PrerequisitesError as e: raise configexc.KeybindingError(str(e)) log.keyboard.vdebug("Adding binding {} -> {} in mode {}.".format( key, command, mode)) if key in self.get_bindings_for(mode) and not force: raise configexc.DuplicateKeyError(key) bindings = self._config.get_obj('bindings.commands') if mode not in bindings: bindings[mode] = {} bindings[mode][key] = command self._config.update_mutables(save_yaml=save_yaml)
def test_partial_parsing(self, config_stub): """Test partial parsing with a runner where it's enabled. The same with it being disabled is tested by test_parse_all. """ parser = runners.CommandParser(partial_match=True) result = parser.parse('on') assert result.cmd.name == 'one'
def test_parse_empty_with_alias(self, command): """An empty command should not crash. See https://github.com/qutebrowser/qutebrowser/issues/1690 and https://github.com/qutebrowser/qutebrowser/issues/1773 """ parser = runners.CommandParser() with pytest.raises(cmdexc.NoSuchCommandError): parser.parse_all(command)
def test_dont_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to false. Should raise NoSuchCommandError """ config_stub.val.completion.use_best_match = False parser = runners.CommandParser(partial_match=True) with pytest.raises(cmdexc.NoSuchCommandError): parser.parse('tw')
def test_use_best_match(self, config_stub): """Test multiple completion options with use_best_match set to true. The resulting command should be the best match """ config_stub.val.completion.use_best_match = True parser = runners.CommandParser(partial_match=True) result = parser.parse('tw') assert result.cmd.name == 'two'
def test_parse_all_with_alias(self, cmdline_test, monkeypatch, config_stub): if not cmdline_test.cmd: pytest.skip("Empty command") config_stub.val.aliases = {'alias_name': cmdline_test.cmd} parser = runners.CommandParser() if cmdline_test.valid: assert len(parser.parse_all("alias_name")) > 0 else: with pytest.raises(cmdexc.NoSuchCommandError): parser.parse_all("alias_name")
def test_parse_all(self, cmdline_test): """Test parsing of commands. See https://github.com/qutebrowser/qutebrowser/issues/615 Args: cmdline_test: A pytest fixture which provides testcases. """ parser = runners.CommandParser() if cmdline_test.valid: parser.parse_all(cmdline_test.cmd, aliases=False) else: with pytest.raises(cmdexc.NoSuchCommandError): parser.parse_all(cmdline_test.cmd, aliases=False)
def bind(key, *, info): """A CompletionModel filled with all bindable commands and descriptions. Args: key: the key being bound. """ model = completionmodel.CompletionModel(column_widths=(20, 60, 20)) cmd_text = info.keyconf.get_command(key, 'normal') if cmd_text: parser = runners.CommandParser() cmd = parser.parse(cmd_text).cmd data = [(cmd_text, cmd.desc, key)] model.add_category(listcategory.ListCategory("Current", data)) cmdlist = util.get_cmd_completions(info, include_hidden=True, include_aliases=True) model.add_category(listcategory.ListCategory("Commands", cmdlist)) return model
def to_py(self, value): self._basic_py_validation(value, str) if not value: return None # This requires some trickery, as runners.CommandParser uses # conf.val.aliases, which in turn map to a command again, # leading to an endless recursion. # To fix that, we turn off validating other commands (alias values) # while validating a command. if not Command.unvalidated: Command.unvalidated = True try: parser = runners.CommandParser() try: parser.parse_all(value) except cmdexc.Error as e: raise configexc.ValidationError(value, str(e)) finally: Command.unvalidated = False return value