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
Beispiel #2
0
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
Beispiel #3
0
    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))
Beispiel #4
0
    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)
Beispiel #5
0
    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'
Beispiel #6
0
    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)
Beispiel #7
0
    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')
Beispiel #8
0
    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'
Beispiel #9
0
    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")
Beispiel #10
0
    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)
Beispiel #11
0
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
Beispiel #12
0
    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