We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Auto-use the first match in the completion
Requested by @Earnestly in IRC:

Typing, e.g. `:do`<kbd>Enter</kbd> should invoke `:download` automatically as that's the first-best match instead of showing an invalid command error.

(of course configurable)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `qutebrowser/commands/runners.py`
Content:
```
1 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
2 
3 # Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
4 #
5 # This file is part of qutebrowser.
6 #
7 # qutebrowser is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # qutebrowser is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.
19 
20 """Module containing command managers (SearchRunner and CommandRunner)."""
21 
22 import traceback
23 import re
24 
25 import attr
26 from PyQt5.QtCore import pyqtSlot, QUrl, QObject
27 
28 from qutebrowser.config import config
29 from qutebrowser.commands import cmdexc, cmdutils
30 from qutebrowser.utils import message, objreg, qtutils, usertypes, utils
31 from qutebrowser.misc import split
32 
33 
34 last_command = {}
35 
36 
37 @attr.s
38 class ParseResult:
39 
40     """The result of parsing a commandline."""
41 
42     cmd = attr.ib()
43     args = attr.ib()
44     cmdline = attr.ib()
45 
46 
47 def _current_url(tabbed_browser):
48     """Convenience method to get the current url."""
49     try:
50         return tabbed_browser.current_url()
51     except qtutils.QtValueError as e:
52         msg = "Current URL is invalid"
53         if e.reason:
54             msg += " ({})".format(e.reason)
55         msg += "!"
56         raise cmdexc.CommandError(msg)
57 
58 
59 def replace_variables(win_id, arglist):
60     """Utility function to replace variables like {url} in a list of args."""
61     variables = {
62         'url': lambda: _current_url(tabbed_browser).toString(
63             QUrl.FullyEncoded | QUrl.RemovePassword),
64         'url:pretty': lambda: _current_url(tabbed_browser).toString(
65             QUrl.DecodeReserved | QUrl.RemovePassword),
66         'clipboard': utils.get_clipboard,
67         'primary': lambda: utils.get_clipboard(selection=True),
68     }
69     values = {}
70     args = []
71     tabbed_browser = objreg.get('tabbed-browser', scope='window',
72                                 window=win_id)
73 
74     def repl_cb(matchobj):
75         """Return replacement for given match."""
76         var = matchobj.group("var")
77         if var not in values:
78             values[var] = variables[var]()
79         return values[var]
80     repl_pattern = re.compile("{(?P<var>" + "|".join(variables.keys()) + ")}")
81 
82     try:
83         for arg in arglist:
84             # using re.sub with callback function replaces all variables in a
85             # single pass and avoids expansion of nested variables (e.g.
86             # "{url}" from clipboard is not expanded)
87             args.append(repl_pattern.sub(repl_cb, arg))
88     except utils.ClipboardError as e:
89         raise cmdexc.CommandError(e)
90     return args
91 
92 
93 class CommandParser:
94 
95     """Parse qutebrowser commandline commands.
96 
97     Attributes:
98 
99         _partial_match: Whether to allow partial command matches.
100     """
101 
102     def __init__(self, partial_match=False):
103         self._partial_match = partial_match
104 
105     def _get_alias(self, text, default=None):
106         """Get an alias from the config.
107 
108         Args:
109             text: The text to parse.
110             default : Default value to return when alias was not found.
111 
112         Return:
113             The new command string if an alias was found. Default value
114             otherwise.
115         """
116         parts = text.strip().split(maxsplit=1)
117         try:
118             alias = config.val.aliases[parts[0]]
119         except KeyError:
120             return default
121 
122         try:
123             new_cmd = '{} {}'.format(alias, parts[1])
124         except IndexError:
125             new_cmd = alias
126         if text.endswith(' '):
127             new_cmd += ' '
128         return new_cmd
129 
130     def _parse_all_gen(self, text, aliases=True, *args, **kwargs):
131         """Split a command on ;; and parse all parts.
132 
133         If the first command in the commandline is a non-split one, it only
134         returns that.
135 
136         Args:
137             text: Text to parse.
138             aliases: Whether to handle aliases.
139             *args/**kwargs: Passed to parse().
140 
141         Yields:
142             ParseResult tuples.
143         """
144         text = text.strip().lstrip(':').strip()
145         if not text:
146             raise cmdexc.NoSuchCommandError("No command given")
147 
148         if aliases:
149             text = self._get_alias(text, text)
150 
151         if ';;' in text:
152             # Get the first command and check if it doesn't want to have ;;
153             # split.
154             first = text.split(';;')[0]
155             result = self.parse(first, *args, **kwargs)
156             if result.cmd.no_cmd_split:
157                 sub_texts = [text]
158             else:
159                 sub_texts = [e.strip() for e in text.split(';;')]
160         else:
161             sub_texts = [text]
162         for sub in sub_texts:
163             yield self.parse(sub, *args, **kwargs)
164 
165     def parse_all(self, *args, **kwargs):
166         """Wrapper over parse_all."""
167         return list(self._parse_all_gen(*args, **kwargs))
168 
169     def parse(self, text, *, fallback=False, keep=False):
170         """Split the commandline text into command and arguments.
171 
172         Args:
173             text: Text to parse.
174             fallback: Whether to do a fallback splitting when the command was
175                       unknown.
176             keep: Whether to keep special chars and whitespace
177 
178         Return:
179             A ParseResult tuple.
180         """
181         cmdstr, sep, argstr = text.partition(' ')
182 
183         if not cmdstr and not fallback:
184             raise cmdexc.NoSuchCommandError("No command given")
185 
186         if self._partial_match:
187             cmdstr = self._completion_match(cmdstr)
188 
189         try:
190             cmd = cmdutils.cmd_dict[cmdstr]
191         except KeyError:
192             if not fallback:
193                 raise cmdexc.NoSuchCommandError(
194                     '{}: no such command'.format(cmdstr))
195             cmdline = split.split(text, keep=keep)
196             return ParseResult(cmd=None, args=None, cmdline=cmdline)
197 
198         args = self._split_args(cmd, argstr, keep)
199         if keep and args:
200             cmdline = [cmdstr, sep + args[0]] + args[1:]
201         elif keep:
202             cmdline = [cmdstr, sep]
203         else:
204             cmdline = [cmdstr] + args[:]
205 
206         return ParseResult(cmd=cmd, args=args, cmdline=cmdline)
207 
208     def _completion_match(self, cmdstr):
209         """Replace cmdstr with a matching completion if there's only one match.
210 
211         Args:
212             cmdstr: The string representing the entered command so far
213 
214         Return:
215             cmdstr modified to the matching completion or unmodified
216         """
217         matches = []
218         for valid_command in cmdutils.cmd_dict:
219             if valid_command.find(cmdstr) == 0:
220                 matches.append(valid_command)
221         if len(matches) == 1:
222             cmdstr = matches[0]
223         return cmdstr
224 
225     def _split_args(self, cmd, argstr, keep):
226         """Split the arguments from an arg string.
227 
228         Args:
229             cmd: The command we're currently handling.
230             argstr: An argument string.
231             keep: Whether to keep special chars and whitespace
232 
233         Return:
234             A list containing the split strings.
235         """
236         if not argstr:
237             return []
238         elif cmd.maxsplit is None:
239             return split.split(argstr, keep=keep)
240         else:
241             # If split=False, we still want to split the flags, but not
242             # everything after that.
243             # We first split the arg string and check the index of the first
244             # non-flag args, then we re-split again properly.
245             # example:
246             #
247             # input: "--foo -v bar baz"
248             # first split: ['--foo', '-v', 'bar', 'baz']
249             #                0        1     2      3
250             # second split: ['--foo', '-v', 'bar baz']
251             # (maxsplit=2)
252             split_args = split.simple_split(argstr, keep=keep)
253             flag_arg_count = 0
254             for i, arg in enumerate(split_args):
255                 arg = arg.strip()
256                 if arg.startswith('-'):
257                     if arg in cmd.flags_with_args:
258                         flag_arg_count += 1
259                 else:
260                     maxsplit = i + cmd.maxsplit + flag_arg_count
261                     return split.simple_split(argstr, keep=keep,
262                                               maxsplit=maxsplit)
263 
264             # If there are only flags, we got it right on the first try
265             # already.
266             return split_args
267 
268 
269 class CommandRunner(QObject):
270 
271     """Parse and run qutebrowser commandline commands.
272 
273     Attributes:
274         _win_id: The window this CommandRunner is associated with.
275     """
276 
277     def __init__(self, win_id, partial_match=False, parent=None):
278         super().__init__(parent)
279         self._parser = CommandParser(partial_match=partial_match)
280         self._win_id = win_id
281 
282     def run(self, text, count=None):
283         """Parse a command from a line of text and run it.
284 
285         Args:
286             text: The text to parse.
287             count: The count to pass to the command.
288         """
289         record_last_command = True
290         record_macro = True
291 
292         mode_manager = objreg.get('mode-manager', scope='window',
293                                   window=self._win_id)
294         cur_mode = mode_manager.mode
295 
296         for result in self._parser.parse_all(text):
297             if result.cmd.no_replace_variables:
298                 args = result.args
299             else:
300                 args = replace_variables(self._win_id, result.args)
301             result.cmd.run(self._win_id, args, count=count)
302 
303             if result.cmdline[0] == 'repeat-command':
304                 record_last_command = False
305 
306             if result.cmdline[0] in ['record-macro', 'run-macro',
307                                      'set-cmd-text']:
308                 record_macro = False
309 
310         if record_last_command:
311             last_command[cur_mode] = (text, count)
312 
313         if record_macro and cur_mode == usertypes.KeyMode.normal:
314             macro_recorder = objreg.get('macro-recorder')
315             macro_recorder.record_command(text, count)
316 
317     @pyqtSlot(str, int)
318     @pyqtSlot(str)
319     def run_safely(self, text, count=None):
320         """Run a command and display exceptions in the statusbar."""
321         try:
322             self.run(text, count)
323         except cmdexc.Error as e:
324             message.error(str(e), stack=traceback.format_exc())
325
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py
--- a/qutebrowser/commands/runners.py
+++ b/qutebrowser/commands/runners.py
@@ -220,6 +220,8 @@
                 matches.append(valid_command)
         if len(matches) == 1:
             cmdstr = matches[0]
+        elif len(matches) > 1 and config.val.completion.use_best_match:
+            cmdstr = matches[0]
         return cmdstr
 
     def _split_args(self, cmd, argstr, keep):

{"golden_diff": "diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py\n--- a/qutebrowser/commands/runners.py\n+++ b/qutebrowser/commands/runners.py\n@@ -220,6 +220,8 @@\n                 matches.append(valid_command)\n         if len(matches) == 1:\n             cmdstr = matches[0]\n+        elif len(matches) > 1 and config.val.completion.use_best_match:\n+            cmdstr = matches[0]\n         return cmdstr\n \n     def _split_args(self, cmd, argstr, keep):\n", "issue": "Auto-use the first match in the completion\nRequested by @Earnestly in IRC:\n\nTyping, e.g. `:do`<kbd>Enter</kbd> should invoke `:download` automatically as that's the first-best match instead of showing an invalid command error.\n\n(of course configurable)\n\n", "before_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>\n#\n# This file is part of qutebrowser.\n#\n# qutebrowser is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# qutebrowser is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"Module containing command managers (SearchRunner and CommandRunner).\"\"\"\n\nimport traceback\nimport re\n\nimport attr\nfrom PyQt5.QtCore import pyqtSlot, QUrl, QObject\n\nfrom qutebrowser.config import config\nfrom qutebrowser.commands import cmdexc, cmdutils\nfrom qutebrowser.utils import message, objreg, qtutils, usertypes, utils\nfrom qutebrowser.misc import split\n\n\nlast_command = {}\n\n\n@attr.s\nclass ParseResult:\n\n    \"\"\"The result of parsing a commandline.\"\"\"\n\n    cmd = attr.ib()\n    args = attr.ib()\n    cmdline = attr.ib()\n\n\ndef _current_url(tabbed_browser):\n    \"\"\"Convenience method to get the current url.\"\"\"\n    try:\n        return tabbed_browser.current_url()\n    except qtutils.QtValueError as e:\n        msg = \"Current URL is invalid\"\n        if e.reason:\n            msg += \" ({})\".format(e.reason)\n        msg += \"!\"\n        raise cmdexc.CommandError(msg)\n\n\ndef replace_variables(win_id, arglist):\n    \"\"\"Utility function to replace variables like {url} in a list of args.\"\"\"\n    variables = {\n        'url': lambda: _current_url(tabbed_browser).toString(\n            QUrl.FullyEncoded | QUrl.RemovePassword),\n        'url:pretty': lambda: _current_url(tabbed_browser).toString(\n            QUrl.DecodeReserved | QUrl.RemovePassword),\n        'clipboard': utils.get_clipboard,\n        'primary': lambda: utils.get_clipboard(selection=True),\n    }\n    values = {}\n    args = []\n    tabbed_browser = objreg.get('tabbed-browser', scope='window',\n                                window=win_id)\n\n    def repl_cb(matchobj):\n        \"\"\"Return replacement for given match.\"\"\"\n        var = matchobj.group(\"var\")\n        if var not in values:\n            values[var] = variables[var]()\n        return values[var]\n    repl_pattern = re.compile(\"{(?P<var>\" + \"|\".join(variables.keys()) + \")}\")\n\n    try:\n        for arg in arglist:\n            # using re.sub with callback function replaces all variables in a\n            # single pass and avoids expansion of nested variables (e.g.\n            # \"{url}\" from clipboard is not expanded)\n            args.append(repl_pattern.sub(repl_cb, arg))\n    except utils.ClipboardError as e:\n        raise cmdexc.CommandError(e)\n    return args\n\n\nclass CommandParser:\n\n    \"\"\"Parse qutebrowser commandline commands.\n\n    Attributes:\n\n        _partial_match: Whether to allow partial command matches.\n    \"\"\"\n\n    def __init__(self, partial_match=False):\n        self._partial_match = partial_match\n\n    def _get_alias(self, text, default=None):\n        \"\"\"Get an alias from the config.\n\n        Args:\n            text: The text to parse.\n            default : Default value to return when alias was not found.\n\n        Return:\n            The new command string if an alias was found. Default value\n            otherwise.\n        \"\"\"\n        parts = text.strip().split(maxsplit=1)\n        try:\n            alias = config.val.aliases[parts[0]]\n        except KeyError:\n            return default\n\n        try:\n            new_cmd = '{} {}'.format(alias, parts[1])\n        except IndexError:\n            new_cmd = alias\n        if text.endswith(' '):\n            new_cmd += ' '\n        return new_cmd\n\n    def _parse_all_gen(self, text, aliases=True, *args, **kwargs):\n        \"\"\"Split a command on ;; and parse all parts.\n\n        If the first command in the commandline is a non-split one, it only\n        returns that.\n\n        Args:\n            text: Text to parse.\n            aliases: Whether to handle aliases.\n            *args/**kwargs: Passed to parse().\n\n        Yields:\n            ParseResult tuples.\n        \"\"\"\n        text = text.strip().lstrip(':').strip()\n        if not text:\n            raise cmdexc.NoSuchCommandError(\"No command given\")\n\n        if aliases:\n            text = self._get_alias(text, text)\n\n        if ';;' in text:\n            # Get the first command and check if it doesn't want to have ;;\n            # split.\n            first = text.split(';;')[0]\n            result = self.parse(first, *args, **kwargs)\n            if result.cmd.no_cmd_split:\n                sub_texts = [text]\n            else:\n                sub_texts = [e.strip() for e in text.split(';;')]\n        else:\n            sub_texts = [text]\n        for sub in sub_texts:\n            yield self.parse(sub, *args, **kwargs)\n\n    def parse_all(self, *args, **kwargs):\n        \"\"\"Wrapper over parse_all.\"\"\"\n        return list(self._parse_all_gen(*args, **kwargs))\n\n    def parse(self, text, *, fallback=False, keep=False):\n        \"\"\"Split the commandline text into command and arguments.\n\n        Args:\n            text: Text to parse.\n            fallback: Whether to do a fallback splitting when the command was\n                      unknown.\n            keep: Whether to keep special chars and whitespace\n\n        Return:\n            A ParseResult tuple.\n        \"\"\"\n        cmdstr, sep, argstr = text.partition(' ')\n\n        if not cmdstr and not fallback:\n            raise cmdexc.NoSuchCommandError(\"No command given\")\n\n        if self._partial_match:\n            cmdstr = self._completion_match(cmdstr)\n\n        try:\n            cmd = cmdutils.cmd_dict[cmdstr]\n        except KeyError:\n            if not fallback:\n                raise cmdexc.NoSuchCommandError(\n                    '{}: no such command'.format(cmdstr))\n            cmdline = split.split(text, keep=keep)\n            return ParseResult(cmd=None, args=None, cmdline=cmdline)\n\n        args = self._split_args(cmd, argstr, keep)\n        if keep and args:\n            cmdline = [cmdstr, sep + args[0]] + args[1:]\n        elif keep:\n            cmdline = [cmdstr, sep]\n        else:\n            cmdline = [cmdstr] + args[:]\n\n        return ParseResult(cmd=cmd, args=args, cmdline=cmdline)\n\n    def _completion_match(self, cmdstr):\n        \"\"\"Replace cmdstr with a matching completion if there's only one match.\n\n        Args:\n            cmdstr: The string representing the entered command so far\n\n        Return:\n            cmdstr modified to the matching completion or unmodified\n        \"\"\"\n        matches = []\n        for valid_command in cmdutils.cmd_dict:\n            if valid_command.find(cmdstr) == 0:\n                matches.append(valid_command)\n        if len(matches) == 1:\n            cmdstr = matches[0]\n        return cmdstr\n\n    def _split_args(self, cmd, argstr, keep):\n        \"\"\"Split the arguments from an arg string.\n\n        Args:\n            cmd: The command we're currently handling.\n            argstr: An argument string.\n            keep: Whether to keep special chars and whitespace\n\n        Return:\n            A list containing the split strings.\n        \"\"\"\n        if not argstr:\n            return []\n        elif cmd.maxsplit is None:\n            return split.split(argstr, keep=keep)\n        else:\n            # If split=False, we still want to split the flags, but not\n            # everything after that.\n            # We first split the arg string and check the index of the first\n            # non-flag args, then we re-split again properly.\n            # example:\n            #\n            # input: \"--foo -v bar baz\"\n            # first split: ['--foo', '-v', 'bar', 'baz']\n            #                0        1     2      3\n            # second split: ['--foo', '-v', 'bar baz']\n            # (maxsplit=2)\n            split_args = split.simple_split(argstr, keep=keep)\n            flag_arg_count = 0\n            for i, arg in enumerate(split_args):\n                arg = arg.strip()\n                if arg.startswith('-'):\n                    if arg in cmd.flags_with_args:\n                        flag_arg_count += 1\n                else:\n                    maxsplit = i + cmd.maxsplit + flag_arg_count\n                    return split.simple_split(argstr, keep=keep,\n                                              maxsplit=maxsplit)\n\n            # If there are only flags, we got it right on the first try\n            # already.\n            return split_args\n\n\nclass CommandRunner(QObject):\n\n    \"\"\"Parse and run qutebrowser commandline commands.\n\n    Attributes:\n        _win_id: The window this CommandRunner is associated with.\n    \"\"\"\n\n    def __init__(self, win_id, partial_match=False, parent=None):\n        super().__init__(parent)\n        self._parser = CommandParser(partial_match=partial_match)\n        self._win_id = win_id\n\n    def run(self, text, count=None):\n        \"\"\"Parse a command from a line of text and run it.\n\n        Args:\n            text: The text to parse.\n            count: The count to pass to the command.\n        \"\"\"\n        record_last_command = True\n        record_macro = True\n\n        mode_manager = objreg.get('mode-manager', scope='window',\n                                  window=self._win_id)\n        cur_mode = mode_manager.mode\n\n        for result in self._parser.parse_all(text):\n            if result.cmd.no_replace_variables:\n                args = result.args\n            else:\n                args = replace_variables(self._win_id, result.args)\n            result.cmd.run(self._win_id, args, count=count)\n\n            if result.cmdline[0] == 'repeat-command':\n                record_last_command = False\n\n            if result.cmdline[0] in ['record-macro', 'run-macro',\n                                     'set-cmd-text']:\n                record_macro = False\n\n        if record_last_command:\n            last_command[cur_mode] = (text, count)\n\n        if record_macro and cur_mode == usertypes.KeyMode.normal:\n            macro_recorder = objreg.get('macro-recorder')\n            macro_recorder.record_command(text, count)\n\n    @pyqtSlot(str, int)\n    @pyqtSlot(str)\n    def run_safely(self, text, count=None):\n        \"\"\"Run a command and display exceptions in the statusbar.\"\"\"\n        try:\n            self.run(text, count)\n        except cmdexc.Error as e:\n            message.error(str(e), stack=traceback.format_exc())\n", "path": "qutebrowser/commands/runners.py"}], "after_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>\n#\n# This file is part of qutebrowser.\n#\n# qutebrowser is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# qutebrowser is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with qutebrowser.  If not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"Module containing command managers (SearchRunner and CommandRunner).\"\"\"\n\nimport traceback\nimport re\n\nimport attr\nfrom PyQt5.QtCore import pyqtSlot, QUrl, QObject\n\nfrom qutebrowser.config import config\nfrom qutebrowser.commands import cmdexc, cmdutils\nfrom qutebrowser.utils import message, objreg, qtutils, usertypes, utils\nfrom qutebrowser.misc import split\n\n\nlast_command = {}\n\n\n@attr.s\nclass ParseResult:\n\n    \"\"\"The result of parsing a commandline.\"\"\"\n\n    cmd = attr.ib()\n    args = attr.ib()\n    cmdline = attr.ib()\n\n\ndef _current_url(tabbed_browser):\n    \"\"\"Convenience method to get the current url.\"\"\"\n    try:\n        return tabbed_browser.current_url()\n    except qtutils.QtValueError as e:\n        msg = \"Current URL is invalid\"\n        if e.reason:\n            msg += \" ({})\".format(e.reason)\n        msg += \"!\"\n        raise cmdexc.CommandError(msg)\n\n\ndef replace_variables(win_id, arglist):\n    \"\"\"Utility function to replace variables like {url} in a list of args.\"\"\"\n    variables = {\n        'url': lambda: _current_url(tabbed_browser).toString(\n            QUrl.FullyEncoded | QUrl.RemovePassword),\n        'url:pretty': lambda: _current_url(tabbed_browser).toString(\n            QUrl.DecodeReserved | QUrl.RemovePassword),\n        'clipboard': utils.get_clipboard,\n        'primary': lambda: utils.get_clipboard(selection=True),\n    }\n    values = {}\n    args = []\n    tabbed_browser = objreg.get('tabbed-browser', scope='window',\n                                window=win_id)\n\n    def repl_cb(matchobj):\n        \"\"\"Return replacement for given match.\"\"\"\n        var = matchobj.group(\"var\")\n        if var not in values:\n            values[var] = variables[var]()\n        return values[var]\n    repl_pattern = re.compile(\"{(?P<var>\" + \"|\".join(variables.keys()) + \")}\")\n\n    try:\n        for arg in arglist:\n            # using re.sub with callback function replaces all variables in a\n            # single pass and avoids expansion of nested variables (e.g.\n            # \"{url}\" from clipboard is not expanded)\n            args.append(repl_pattern.sub(repl_cb, arg))\n    except utils.ClipboardError as e:\n        raise cmdexc.CommandError(e)\n    return args\n\n\nclass CommandParser:\n\n    \"\"\"Parse qutebrowser commandline commands.\n\n    Attributes:\n\n        _partial_match: Whether to allow partial command matches.\n    \"\"\"\n\n    def __init__(self, partial_match=False):\n        self._partial_match = partial_match\n\n    def _get_alias(self, text, default=None):\n        \"\"\"Get an alias from the config.\n\n        Args:\n            text: The text to parse.\n            default : Default value to return when alias was not found.\n\n        Return:\n            The new command string if an alias was found. Default value\n            otherwise.\n        \"\"\"\n        parts = text.strip().split(maxsplit=1)\n        try:\n            alias = config.val.aliases[parts[0]]\n        except KeyError:\n            return default\n\n        try:\n            new_cmd = '{} {}'.format(alias, parts[1])\n        except IndexError:\n            new_cmd = alias\n        if text.endswith(' '):\n            new_cmd += ' '\n        return new_cmd\n\n    def _parse_all_gen(self, text, aliases=True, *args, **kwargs):\n        \"\"\"Split a command on ;; and parse all parts.\n\n        If the first command in the commandline is a non-split one, it only\n        returns that.\n\n        Args:\n            text: Text to parse.\n            aliases: Whether to handle aliases.\n            *args/**kwargs: Passed to parse().\n\n        Yields:\n            ParseResult tuples.\n        \"\"\"\n        text = text.strip().lstrip(':').strip()\n        if not text:\n            raise cmdexc.NoSuchCommandError(\"No command given\")\n\n        if aliases:\n            text = self._get_alias(text, text)\n\n        if ';;' in text:\n            # Get the first command and check if it doesn't want to have ;;\n            # split.\n            first = text.split(';;')[0]\n            result = self.parse(first, *args, **kwargs)\n            if result.cmd.no_cmd_split:\n                sub_texts = [text]\n            else:\n                sub_texts = [e.strip() for e in text.split(';;')]\n        else:\n            sub_texts = [text]\n        for sub in sub_texts:\n            yield self.parse(sub, *args, **kwargs)\n\n    def parse_all(self, *args, **kwargs):\n        \"\"\"Wrapper over parse_all.\"\"\"\n        return list(self._parse_all_gen(*args, **kwargs))\n\n    def parse(self, text, *, fallback=False, keep=False):\n        \"\"\"Split the commandline text into command and arguments.\n\n        Args:\n            text: Text to parse.\n            fallback: Whether to do a fallback splitting when the command was\n                      unknown.\n            keep: Whether to keep special chars and whitespace\n\n        Return:\n            A ParseResult tuple.\n        \"\"\"\n        cmdstr, sep, argstr = text.partition(' ')\n\n        if not cmdstr and not fallback:\n            raise cmdexc.NoSuchCommandError(\"No command given\")\n\n        if self._partial_match:\n            cmdstr = self._completion_match(cmdstr)\n\n        try:\n            cmd = cmdutils.cmd_dict[cmdstr]\n        except KeyError:\n            if not fallback:\n                raise cmdexc.NoSuchCommandError(\n                    '{}: no such command'.format(cmdstr))\n            cmdline = split.split(text, keep=keep)\n            return ParseResult(cmd=None, args=None, cmdline=cmdline)\n\n        args = self._split_args(cmd, argstr, keep)\n        if keep and args:\n            cmdline = [cmdstr, sep + args[0]] + args[1:]\n        elif keep:\n            cmdline = [cmdstr, sep]\n        else:\n            cmdline = [cmdstr] + args[:]\n\n        return ParseResult(cmd=cmd, args=args, cmdline=cmdline)\n\n    def _completion_match(self, cmdstr):\n        \"\"\"Replace cmdstr with a matching completion if there's only one match.\n\n        Args:\n            cmdstr: The string representing the entered command so far\n\n        Return:\n            cmdstr modified to the matching completion or unmodified\n        \"\"\"\n        matches = []\n        for valid_command in cmdutils.cmd_dict:\n            if valid_command.find(cmdstr) == 0:\n                matches.append(valid_command)\n        if len(matches) == 1:\n            cmdstr = matches[0]\n        elif len(matches) > 1 and config.val.completion.use_best_match:\n            cmdstr = matches[0]\n        return cmdstr\n\n    def _split_args(self, cmd, argstr, keep):\n        \"\"\"Split the arguments from an arg string.\n\n        Args:\n            cmd: The command we're currently handling.\n            argstr: An argument string.\n            keep: Whether to keep special chars and whitespace\n\n        Return:\n            A list containing the split strings.\n        \"\"\"\n        if not argstr:\n            return []\n        elif cmd.maxsplit is None:\n            return split.split(argstr, keep=keep)\n        else:\n            # If split=False, we still want to split the flags, but not\n            # everything after that.\n            # We first split the arg string and check the index of the first\n            # non-flag args, then we re-split again properly.\n            # example:\n            #\n            # input: \"--foo -v bar baz\"\n            # first split: ['--foo', '-v', 'bar', 'baz']\n            #                0        1     2      3\n            # second split: ['--foo', '-v', 'bar baz']\n            # (maxsplit=2)\n            split_args = split.simple_split(argstr, keep=keep)\n            flag_arg_count = 0\n            for i, arg in enumerate(split_args):\n                arg = arg.strip()\n                if arg.startswith('-'):\n                    if arg in cmd.flags_with_args:\n                        flag_arg_count += 1\n                else:\n                    maxsplit = i + cmd.maxsplit + flag_arg_count\n                    return split.simple_split(argstr, keep=keep,\n                                              maxsplit=maxsplit)\n\n            # If there are only flags, we got it right on the first try\n            # already.\n            return split_args\n\n\nclass CommandRunner(QObject):\n\n    \"\"\"Parse and run qutebrowser commandline commands.\n\n    Attributes:\n        _win_id: The window this CommandRunner is associated with.\n    \"\"\"\n\n    def __init__(self, win_id, partial_match=False, parent=None):\n        super().__init__(parent)\n        self._parser = CommandParser(partial_match=partial_match)\n        self._win_id = win_id\n\n    def run(self, text, count=None):\n        \"\"\"Parse a command from a line of text and run it.\n\n        Args:\n            text: The text to parse.\n            count: The count to pass to the command.\n        \"\"\"\n        record_last_command = True\n        record_macro = True\n\n        mode_manager = objreg.get('mode-manager', scope='window',\n                                  window=self._win_id)\n        cur_mode = mode_manager.mode\n\n        for result in self._parser.parse_all(text):\n            if result.cmd.no_replace_variables:\n                args = result.args\n            else:\n                args = replace_variables(self._win_id, result.args)\n            result.cmd.run(self._win_id, args, count=count)\n\n            if result.cmdline[0] == 'repeat-command':\n                record_last_command = False\n\n            if result.cmdline[0] in ['record-macro', 'run-macro',\n                                     'set-cmd-text']:\n                record_macro = False\n\n        if record_last_command:\n            last_command[cur_mode] = (text, count)\n\n        if record_macro and cur_mode == usertypes.KeyMode.normal:\n            macro_recorder = objreg.get('macro-recorder')\n            macro_recorder.record_command(text, count)\n\n    @pyqtSlot(str, int)\n    @pyqtSlot(str)\n    def run_safely(self, text, count=None):\n        \"\"\"Run a command and display exceptions in the statusbar.\"\"\"\n        try:\n            self.run(text, count)\n        except cmdexc.Error as e:\n            message.error(str(e), stack=traceback.format_exc())\n\n    @pyqtSlot(str, int)\n    def run_safely_init(self, text, count=None):\n        \"\"\"Run a command and display exceptions in the statusbar.\n\n        Contrary to run_safely, error messages are queued so this is more\n        suitable to use while initializing.\n        \"\"\"\n        try:\n            self.run(text, count)\n        except cmdexc.Error as e:\n            message.error(str(e), stack=traceback.format_exc())\n", "path": "qutebrowser/commands/runners.py"}]}