We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
:edit-command accepts invalid commands
When using `:edit-command` and changing the command to `foo` (without an initial `:`):

```
10:33:50 DEBUG    procs      guiprocess:on_finished:98 Process finished with code 0, status 0.
10:33:50 DEBUG    procs      editor:on_proc_closed:73 Editor closed
10:33:50 DEBUG    procs      editor:on_proc_closed:90 Read back: foo

10:33:50 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py", line 179, in callback
    self.set_cmd_text(text)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py", line 86, in set_cmd_text
    self.setText(text)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py", line 212, in setText
    "'{}'!".format(text))
AssertionError: setText got called with invalid text 'foo
'!
```

When changing it to an empty file and pressing enter:

```
10:34:38 DEBUG    commands   command:run:484 command called: command-accept
[...]
10:34:38 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/app.py", line 935, in eventFilter
    return handler(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/app.py", line 895, in _handle_key_event
    return man.eventFilter(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeman.py", line 326, in eventFilter
    return self._eventFilter_keypress(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeman.py", line 162, in _eventFilter_keypress
    handled = parser.handle(event)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/basekeyparser.py", line 266, in handle
    handled = self._handle_special_key(e)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/basekeyparser.py", line 139, in _handle_special_key
    self.execute(cmdstr, self.Type.special, count)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/keyparser.py", line 44, in execute
    self._commandrunner.run(cmdstr, count)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/commands/runners.py", line 301, in run
    result.cmd.run(self._win_id, args, count=count)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/commands/command.py", line 500, in run
    self.handler(*posargs, **kwargs)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py", line 167, in command_accept
    self.got_cmd[str].emit(prefixes[text[0]] + text[1:])
IndexError: string index out of range
```

Report: https://crashes.qutebrowser.org/view/97044b65

cc @rcorre


--- 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/mainwindow/statusbar/command.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 """The commandline in the statusbar."""
21 
22 from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize
23 from PyQt5.QtWidgets import QSizePolicy
24 
25 from qutebrowser.keyinput import modeman, modeparsers
26 from qutebrowser.commands import cmdexc, cmdutils
27 from qutebrowser.misc import cmdhistory, editor
28 from qutebrowser.misc import miscwidgets as misc
29 from qutebrowser.utils import usertypes, log, objreg
30 
31 
32 class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
33 
34     """The commandline part of the statusbar.
35 
36     Attributes:
37         _win_id: The window ID this widget is associated with.
38 
39     Signals:
40         got_cmd: Emitted when a command is triggered by the user.
41                  arg: The command string and also potentially the count.
42         clear_completion_selection: Emitted before the completion widget is
43                                     hidden.
44         hide_completion: Emitted when the completion widget should be hidden.
45         update_completion: Emitted when the completion should be shown/updated.
46         show_cmd: Emitted when command input should be shown.
47         hide_cmd: Emitted when command input can be hidden.
48     """
49 
50     got_cmd = pyqtSignal([str], [str, int])
51     clear_completion_selection = pyqtSignal()
52     hide_completion = pyqtSignal()
53     update_completion = pyqtSignal()
54     show_cmd = pyqtSignal()
55     hide_cmd = pyqtSignal()
56 
57     def __init__(self, *, win_id, private, parent=None):
58         misc.CommandLineEdit.__init__(self, parent=parent)
59         misc.MinimalLineEditMixin.__init__(self)
60         self._win_id = win_id
61         if not private:
62             command_history = objreg.get('command-history')
63             self.history.history = command_history.data
64             self.history.changed.connect(command_history.changed)
65         self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
66         self.cursorPositionChanged.connect(self.update_completion)
67         self.textChanged.connect(self.update_completion)
68         self.textChanged.connect(self.updateGeometry)
69 
70     def prefix(self):
71         """Get the currently entered command prefix."""
72         text = self.text()
73         if not text:
74             return ''
75         elif text[0] in modeparsers.STARTCHARS:
76             return text[0]
77         else:
78             return ''
79 
80     def set_cmd_text(self, text):
81         """Preset the statusbar to some text.
82 
83         Args:
84             text: The text to set as string.
85         """
86         self.setText(text)
87         log.modes.debug("Setting command text, focusing {!r}".format(self))
88         modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus')
89         self.setFocus()
90         self.show_cmd.emit()
91 
92     @cmdutils.register(instance='status-command', name='set-cmd-text',
93                        scope='window', maxsplit=0)
94     @cmdutils.argument('count', count=True)
95     def set_cmd_text_command(self, text, count=None, space=False, append=False,
96                              run_on_count=False):
97         """Preset the statusbar to some text.
98 
99         //
100 
101         Wrapper for set_cmd_text to check the arguments and allow multiple
102         strings which will get joined.
103 
104         Args:
105             text: The commandline to set.
106             count: The count if given.
107             space: If given, a space is added to the end.
108             append: If given, the text is appended to the current text.
109             run_on_count: If given with a count, the command is run with the
110                           given count rather than setting the command text.
111         """
112         if space:
113             text += ' '
114         if append:
115             if not self.text():
116                 raise cmdexc.CommandError("No current text!")
117             text = self.text() + text
118 
119         if not text or text[0] not in modeparsers.STARTCHARS:
120             raise cmdexc.CommandError(
121                 "Invalid command text '{}'.".format(text))
122         if run_on_count and count is not None:
123             self.got_cmd[str, int].emit(text, count)
124         else:
125             self.set_cmd_text(text)
126 
127     @cmdutils.register(instance='status-command',
128                        modes=[usertypes.KeyMode.command], scope='window')
129     def command_history_prev(self):
130         """Go back in the commandline history."""
131         try:
132             if not self.history.is_browsing():
133                 item = self.history.start(self.text().strip())
134             else:
135                 item = self.history.previtem()
136         except (cmdhistory.HistoryEmptyError,
137                 cmdhistory.HistoryEndReachedError):
138             return
139         if item:
140             self.set_cmd_text(item)
141 
142     @cmdutils.register(instance='status-command',
143                        modes=[usertypes.KeyMode.command], scope='window')
144     def command_history_next(self):
145         """Go forward in the commandline history."""
146         if not self.history.is_browsing():
147             return
148         try:
149             item = self.history.nextitem()
150         except cmdhistory.HistoryEndReachedError:
151             return
152         if item:
153             self.set_cmd_text(item)
154 
155     @cmdutils.register(instance='status-command',
156                        modes=[usertypes.KeyMode.command], scope='window')
157     def command_accept(self):
158         """Execute the command currently in the commandline."""
159         prefixes = {
160             ':': '',
161             '/': 'search -- ',
162             '?': 'search -r -- ',
163         }
164         text = self.text()
165         self.history.append(text)
166         modeman.leave(self._win_id, usertypes.KeyMode.command, 'cmd accept')
167         self.got_cmd[str].emit(prefixes[text[0]] + text[1:])
168 
169     @cmdutils.register(instance='status-command', scope='window')
170     def edit_command(self, run=False):
171         """Open an editor to modify the current command.
172 
173         Args:
174             run: Run the command if the editor exits successfully.
175         """
176         ed = editor.ExternalEditor(parent=self)
177 
178         def callback(text):
179             self.set_cmd_text(text)
180             if run:
181                 self.command_accept()
182 
183         ed.editing_finished.connect(callback)
184         ed.edit(self.text())
185 
186     @pyqtSlot(usertypes.KeyMode)
187     def on_mode_left(self, mode):
188         """Clear up when command mode was left.
189 
190         - Clear the statusbar text if it's explicitly unfocused.
191         - Clear completion selection
192         - Hide completion
193 
194         Args:
195             mode: The mode which was left.
196         """
197         if mode == usertypes.KeyMode.command:
198             self.setText('')
199             self.history.stop()
200             self.hide_cmd.emit()
201             self.clear_completion_selection.emit()
202             self.hide_completion.emit()
203 
204     def setText(self, text):
205         """Extend setText to set prefix and make sure the prompt is ok."""
206         if not text:
207             pass
208         elif text[0] in modeparsers.STARTCHARS:
209             super().set_prompt(text[0])
210         else:
211             raise AssertionError("setText got called with invalid text "
212                                  "'{}'!".format(text))
213         super().setText(text)
214 
215     def keyPressEvent(self, e):
216         """Override keyPressEvent to ignore Return key presses.
217 
218         If this widget is focused, we are in passthrough key mode, and
219         Enter/Shift+Enter/etc. will cause QLineEdit to think it's finished
220         without command_accept to be called.
221         """
222         if e.key() == Qt.Key_Return:
223             e.ignore()
224             return
225         else:
226             super().keyPressEvent(e)
227 
228     def sizeHint(self):
229         """Dynamically calculate the needed size."""
230         height = super().sizeHint().height()
231         text = self.text()
232         if not text:
233             text = 'x'
234         width = self.fontMetrics().width(text)
235         return QSize(width, height)
236
```
--- 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/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py
--- a/qutebrowser/mainwindow/statusbar/command.py
+++ b/qutebrowser/mainwindow/statusbar/command.py
@@ -26,7 +26,7 @@
 from qutebrowser.commands import cmdexc, cmdutils
 from qutebrowser.misc import cmdhistory, editor
 from qutebrowser.misc import miscwidgets as misc
-from qutebrowser.utils import usertypes, log, objreg
+from qutebrowser.utils import usertypes, log, objreg, message
 
 
 class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
@@ -176,6 +176,10 @@
         ed = editor.ExternalEditor(parent=self)
 
         def callback(text):
+            if not text or text[0] not in modeparsers.STARTCHARS:
+                message.error('command must start with one of {}'
+                              .format(modeparsers.STARTCHARS))
+                return
             self.set_cmd_text(text)
             if run:
                 self.command_accept()

{"golden_diff": "diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py\n--- a/qutebrowser/mainwindow/statusbar/command.py\n+++ b/qutebrowser/mainwindow/statusbar/command.py\n@@ -26,7 +26,7 @@\n from qutebrowser.commands import cmdexc, cmdutils\n from qutebrowser.misc import cmdhistory, editor\n from qutebrowser.misc import miscwidgets as misc\n-from qutebrowser.utils import usertypes, log, objreg\n+from qutebrowser.utils import usertypes, log, objreg, message\n \n \n class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):\n@@ -176,6 +176,10 @@\n         ed = editor.ExternalEditor(parent=self)\n \n         def callback(text):\n+            if not text or text[0] not in modeparsers.STARTCHARS:\n+                message.error('command must start with one of {}'\n+                              .format(modeparsers.STARTCHARS))\n+                return\n             self.set_cmd_text(text)\n             if run:\n                 self.command_accept()\n", "issue": ":edit-command accepts invalid commands\nWhen using `:edit-command` and changing the command to `foo` (without an initial `:`):\r\n\r\n```\r\n10:33:50 DEBUG    procs      guiprocess:on_finished:98 Process finished with code 0, status 0.\r\n10:33:50 DEBUG    procs      editor:on_proc_closed:73 Editor closed\r\n10:33:50 DEBUG    procs      editor:on_proc_closed:90 Read back: foo\r\n\r\n10:33:50 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception\r\nTraceback (most recent call last):\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py\", line 179, in callback\r\n    self.set_cmd_text(text)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py\", line 86, in set_cmd_text\r\n    self.setText(text)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py\", line 212, in setText\r\n    \"'{}'!\".format(text))\r\nAssertionError: setText got called with invalid text 'foo\r\n'!\r\n```\r\n\r\nWhen changing it to an empty file and pressing enter:\r\n\r\n```\r\n10:34:38 DEBUG    commands   command:run:484 command called: command-accept\r\n[...]\r\n10:34:38 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception\r\nTraceback (most recent call last):\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/app.py\", line 935, in eventFilter\r\n    return handler(event)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/app.py\", line 895, in _handle_key_event\r\n    return man.eventFilter(event)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeman.py\", line 326, in eventFilter\r\n    return self._eventFilter_keypress(event)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/modeman.py\", line 162, in _eventFilter_keypress\r\n    handled = parser.handle(event)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/basekeyparser.py\", line 266, in handle\r\n    handled = self._handle_special_key(e)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/basekeyparser.py\", line 139, in _handle_special_key\r\n    self.execute(cmdstr, self.Type.special, count)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/keyinput/keyparser.py\", line 44, in execute\r\n    self._commandrunner.run(cmdstr, count)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/commands/runners.py\", line 301, in run\r\n    result.cmd.run(self._win_id, args, count=count)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/commands/command.py\", line 500, in run\r\n    self.handler(*posargs, **kwargs)\r\n  File \"/home/florian/proj/qutebrowser/git/qutebrowser/mainwindow/statusbar/command.py\", line 167, in command_accept\r\n    self.got_cmd[str].emit(prefixes[text[0]] + text[1:])\r\nIndexError: string index out of range\r\n```\r\n\r\nReport: https://crashes.qutebrowser.org/view/97044b65\r\n\r\ncc @rcorre\r\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\"\"\"The commandline in the statusbar.\"\"\"\n\nfrom PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize\nfrom PyQt5.QtWidgets import QSizePolicy\n\nfrom qutebrowser.keyinput import modeman, modeparsers\nfrom qutebrowser.commands import cmdexc, cmdutils\nfrom qutebrowser.misc import cmdhistory, editor\nfrom qutebrowser.misc import miscwidgets as misc\nfrom qutebrowser.utils import usertypes, log, objreg\n\n\nclass Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):\n\n    \"\"\"The commandline part of the statusbar.\n\n    Attributes:\n        _win_id: The window ID this widget is associated with.\n\n    Signals:\n        got_cmd: Emitted when a command is triggered by the user.\n                 arg: The command string and also potentially the count.\n        clear_completion_selection: Emitted before the completion widget is\n                                    hidden.\n        hide_completion: Emitted when the completion widget should be hidden.\n        update_completion: Emitted when the completion should be shown/updated.\n        show_cmd: Emitted when command input should be shown.\n        hide_cmd: Emitted when command input can be hidden.\n    \"\"\"\n\n    got_cmd = pyqtSignal([str], [str, int])\n    clear_completion_selection = pyqtSignal()\n    hide_completion = pyqtSignal()\n    update_completion = pyqtSignal()\n    show_cmd = pyqtSignal()\n    hide_cmd = pyqtSignal()\n\n    def __init__(self, *, win_id, private, parent=None):\n        misc.CommandLineEdit.__init__(self, parent=parent)\n        misc.MinimalLineEditMixin.__init__(self)\n        self._win_id = win_id\n        if not private:\n            command_history = objreg.get('command-history')\n            self.history.history = command_history.data\n            self.history.changed.connect(command_history.changed)\n        self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)\n        self.cursorPositionChanged.connect(self.update_completion)\n        self.textChanged.connect(self.update_completion)\n        self.textChanged.connect(self.updateGeometry)\n\n    def prefix(self):\n        \"\"\"Get the currently entered command prefix.\"\"\"\n        text = self.text()\n        if not text:\n            return ''\n        elif text[0] in modeparsers.STARTCHARS:\n            return text[0]\n        else:\n            return ''\n\n    def set_cmd_text(self, text):\n        \"\"\"Preset the statusbar to some text.\n\n        Args:\n            text: The text to set as string.\n        \"\"\"\n        self.setText(text)\n        log.modes.debug(\"Setting command text, focusing {!r}\".format(self))\n        modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus')\n        self.setFocus()\n        self.show_cmd.emit()\n\n    @cmdutils.register(instance='status-command', name='set-cmd-text',\n                       scope='window', maxsplit=0)\n    @cmdutils.argument('count', count=True)\n    def set_cmd_text_command(self, text, count=None, space=False, append=False,\n                             run_on_count=False):\n        \"\"\"Preset the statusbar to some text.\n\n        //\n\n        Wrapper for set_cmd_text to check the arguments and allow multiple\n        strings which will get joined.\n\n        Args:\n            text: The commandline to set.\n            count: The count if given.\n            space: If given, a space is added to the end.\n            append: If given, the text is appended to the current text.\n            run_on_count: If given with a count, the command is run with the\n                          given count rather than setting the command text.\n        \"\"\"\n        if space:\n            text += ' '\n        if append:\n            if not self.text():\n                raise cmdexc.CommandError(\"No current text!\")\n            text = self.text() + text\n\n        if not text or text[0] not in modeparsers.STARTCHARS:\n            raise cmdexc.CommandError(\n                \"Invalid command text '{}'.\".format(text))\n        if run_on_count and count is not None:\n            self.got_cmd[str, int].emit(text, count)\n        else:\n            self.set_cmd_text(text)\n\n    @cmdutils.register(instance='status-command',\n                       modes=[usertypes.KeyMode.command], scope='window')\n    def command_history_prev(self):\n        \"\"\"Go back in the commandline history.\"\"\"\n        try:\n            if not self.history.is_browsing():\n                item = self.history.start(self.text().strip())\n            else:\n                item = self.history.previtem()\n        except (cmdhistory.HistoryEmptyError,\n                cmdhistory.HistoryEndReachedError):\n            return\n        if item:\n            self.set_cmd_text(item)\n\n    @cmdutils.register(instance='status-command',\n                       modes=[usertypes.KeyMode.command], scope='window')\n    def command_history_next(self):\n        \"\"\"Go forward in the commandline history.\"\"\"\n        if not self.history.is_browsing():\n            return\n        try:\n            item = self.history.nextitem()\n        except cmdhistory.HistoryEndReachedError:\n            return\n        if item:\n            self.set_cmd_text(item)\n\n    @cmdutils.register(instance='status-command',\n                       modes=[usertypes.KeyMode.command], scope='window')\n    def command_accept(self):\n        \"\"\"Execute the command currently in the commandline.\"\"\"\n        prefixes = {\n            ':': '',\n            '/': 'search -- ',\n            '?': 'search -r -- ',\n        }\n        text = self.text()\n        self.history.append(text)\n        modeman.leave(self._win_id, usertypes.KeyMode.command, 'cmd accept')\n        self.got_cmd[str].emit(prefixes[text[0]] + text[1:])\n\n    @cmdutils.register(instance='status-command', scope='window')\n    def edit_command(self, run=False):\n        \"\"\"Open an editor to modify the current command.\n\n        Args:\n            run: Run the command if the editor exits successfully.\n        \"\"\"\n        ed = editor.ExternalEditor(parent=self)\n\n        def callback(text):\n            self.set_cmd_text(text)\n            if run:\n                self.command_accept()\n\n        ed.editing_finished.connect(callback)\n        ed.edit(self.text())\n\n    @pyqtSlot(usertypes.KeyMode)\n    def on_mode_left(self, mode):\n        \"\"\"Clear up when command mode was left.\n\n        - Clear the statusbar text if it's explicitly unfocused.\n        - Clear completion selection\n        - Hide completion\n\n        Args:\n            mode: The mode which was left.\n        \"\"\"\n        if mode == usertypes.KeyMode.command:\n            self.setText('')\n            self.history.stop()\n            self.hide_cmd.emit()\n            self.clear_completion_selection.emit()\n            self.hide_completion.emit()\n\n    def setText(self, text):\n        \"\"\"Extend setText to set prefix and make sure the prompt is ok.\"\"\"\n        if not text:\n            pass\n        elif text[0] in modeparsers.STARTCHARS:\n            super().set_prompt(text[0])\n        else:\n            raise AssertionError(\"setText got called with invalid text \"\n                                 \"'{}'!\".format(text))\n        super().setText(text)\n\n    def keyPressEvent(self, e):\n        \"\"\"Override keyPressEvent to ignore Return key presses.\n\n        If this widget is focused, we are in passthrough key mode, and\n        Enter/Shift+Enter/etc. will cause QLineEdit to think it's finished\n        without command_accept to be called.\n        \"\"\"\n        if e.key() == Qt.Key_Return:\n            e.ignore()\n            return\n        else:\n            super().keyPressEvent(e)\n\n    def sizeHint(self):\n        \"\"\"Dynamically calculate the needed size.\"\"\"\n        height = super().sizeHint().height()\n        text = self.text()\n        if not text:\n            text = 'x'\n        width = self.fontMetrics().width(text)\n        return QSize(width, height)\n", "path": "qutebrowser/mainwindow/statusbar/command.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\"\"\"The commandline in the statusbar.\"\"\"\n\nfrom PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QSize\nfrom PyQt5.QtWidgets import QSizePolicy\n\nfrom qutebrowser.keyinput import modeman, modeparsers\nfrom qutebrowser.commands import cmdexc, cmdutils\nfrom qutebrowser.misc import cmdhistory, editor\nfrom qutebrowser.misc import miscwidgets as misc\nfrom qutebrowser.utils import usertypes, log, objreg, message\n\n\nclass Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):\n\n    \"\"\"The commandline part of the statusbar.\n\n    Attributes:\n        _win_id: The window ID this widget is associated with.\n\n    Signals:\n        got_cmd: Emitted when a command is triggered by the user.\n                 arg: The command string and also potentially the count.\n        clear_completion_selection: Emitted before the completion widget is\n                                    hidden.\n        hide_completion: Emitted when the completion widget should be hidden.\n        update_completion: Emitted when the completion should be shown/updated.\n        show_cmd: Emitted when command input should be shown.\n        hide_cmd: Emitted when command input can be hidden.\n    \"\"\"\n\n    got_cmd = pyqtSignal([str], [str, int])\n    clear_completion_selection = pyqtSignal()\n    hide_completion = pyqtSignal()\n    update_completion = pyqtSignal()\n    show_cmd = pyqtSignal()\n    hide_cmd = pyqtSignal()\n\n    def __init__(self, *, win_id, private, parent=None):\n        misc.CommandLineEdit.__init__(self, parent=parent)\n        misc.MinimalLineEditMixin.__init__(self)\n        self._win_id = win_id\n        if not private:\n            command_history = objreg.get('command-history')\n            self.history.history = command_history.data\n            self.history.changed.connect(command_history.changed)\n        self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)\n        self.cursorPositionChanged.connect(self.update_completion)\n        self.textChanged.connect(self.update_completion)\n        self.textChanged.connect(self.updateGeometry)\n\n    def prefix(self):\n        \"\"\"Get the currently entered command prefix.\"\"\"\n        text = self.text()\n        if not text:\n            return ''\n        elif text[0] in modeparsers.STARTCHARS:\n            return text[0]\n        else:\n            return ''\n\n    def set_cmd_text(self, text):\n        \"\"\"Preset the statusbar to some text.\n\n        Args:\n            text: The text to set as string.\n        \"\"\"\n        self.setText(text)\n        log.modes.debug(\"Setting command text, focusing {!r}\".format(self))\n        modeman.enter(self._win_id, usertypes.KeyMode.command, 'cmd focus')\n        self.setFocus()\n        self.show_cmd.emit()\n\n    @cmdutils.register(instance='status-command', name='set-cmd-text',\n                       scope='window', maxsplit=0)\n    @cmdutils.argument('count', count=True)\n    def set_cmd_text_command(self, text, count=None, space=False, append=False,\n                             run_on_count=False):\n        \"\"\"Preset the statusbar to some text.\n\n        //\n\n        Wrapper for set_cmd_text to check the arguments and allow multiple\n        strings which will get joined.\n\n        Args:\n            text: The commandline to set.\n            count: The count if given.\n            space: If given, a space is added to the end.\n            append: If given, the text is appended to the current text.\n            run_on_count: If given with a count, the command is run with the\n                          given count rather than setting the command text.\n        \"\"\"\n        if space:\n            text += ' '\n        if append:\n            if not self.text():\n                raise cmdexc.CommandError(\"No current text!\")\n            text = self.text() + text\n\n        if not text or text[0] not in modeparsers.STARTCHARS:\n            raise cmdexc.CommandError(\n                \"Invalid command text '{}'.\".format(text))\n        if run_on_count and count is not None:\n            self.got_cmd[str, int].emit(text, count)\n        else:\n            self.set_cmd_text(text)\n\n    @cmdutils.register(instance='status-command',\n                       modes=[usertypes.KeyMode.command], scope='window')\n    def command_history_prev(self):\n        \"\"\"Go back in the commandline history.\"\"\"\n        try:\n            if not self.history.is_browsing():\n                item = self.history.start(self.text().strip())\n            else:\n                item = self.history.previtem()\n        except (cmdhistory.HistoryEmptyError,\n                cmdhistory.HistoryEndReachedError):\n            return\n        if item:\n            self.set_cmd_text(item)\n\n    @cmdutils.register(instance='status-command',\n                       modes=[usertypes.KeyMode.command], scope='window')\n    def command_history_next(self):\n        \"\"\"Go forward in the commandline history.\"\"\"\n        if not self.history.is_browsing():\n            return\n        try:\n            item = self.history.nextitem()\n        except cmdhistory.HistoryEndReachedError:\n            return\n        if item:\n            self.set_cmd_text(item)\n\n    @cmdutils.register(instance='status-command',\n                       modes=[usertypes.KeyMode.command], scope='window')\n    def command_accept(self):\n        \"\"\"Execute the command currently in the commandline.\"\"\"\n        prefixes = {\n            ':': '',\n            '/': 'search -- ',\n            '?': 'search -r -- ',\n        }\n        text = self.text()\n        self.history.append(text)\n        modeman.leave(self._win_id, usertypes.KeyMode.command, 'cmd accept')\n        self.got_cmd[str].emit(prefixes[text[0]] + text[1:])\n\n    @cmdutils.register(instance='status-command', scope='window')\n    def edit_command(self, run=False):\n        \"\"\"Open an editor to modify the current command.\n\n        Args:\n            run: Run the command if the editor exits successfully.\n        \"\"\"\n        ed = editor.ExternalEditor(parent=self)\n\n        def callback(text):\n            if not text or text[0] not in modeparsers.STARTCHARS:\n                message.error('command must start with one of {}'\n                              .format(modeparsers.STARTCHARS))\n                return\n            self.set_cmd_text(text)\n            if run:\n                self.command_accept()\n\n        ed.editing_finished.connect(callback)\n        ed.edit(self.text())\n\n    @pyqtSlot(usertypes.KeyMode)\n    def on_mode_left(self, mode):\n        \"\"\"Clear up when command mode was left.\n\n        - Clear the statusbar text if it's explicitly unfocused.\n        - Clear completion selection\n        - Hide completion\n\n        Args:\n            mode: The mode which was left.\n        \"\"\"\n        if mode == usertypes.KeyMode.command:\n            self.setText('')\n            self.history.stop()\n            self.hide_cmd.emit()\n            self.clear_completion_selection.emit()\n            self.hide_completion.emit()\n\n    def setText(self, text):\n        \"\"\"Extend setText to set prefix and make sure the prompt is ok.\"\"\"\n        if not text:\n            pass\n        elif text[0] in modeparsers.STARTCHARS:\n            super().set_prompt(text[0])\n        else:\n            raise AssertionError(\"setText got called with invalid text \"\n                                 \"'{}'!\".format(text))\n        super().setText(text)\n\n    def keyPressEvent(self, e):\n        \"\"\"Override keyPressEvent to ignore Return key presses.\n\n        If this widget is focused, we are in passthrough key mode, and\n        Enter/Shift+Enter/etc. will cause QLineEdit to think it's finished\n        without command_accept to be called.\n        \"\"\"\n        if e.key() == Qt.Key_Return:\n            e.ignore()\n            return\n        else:\n            super().keyPressEvent(e)\n\n    def sizeHint(self):\n        \"\"\"Dynamically calculate the needed size.\"\"\"\n        height = super().sizeHint().height()\n        text = self.text()\n        if not text:\n            text = 'x'\n        width = self.fontMetrics().width(text)\n        return QSize(width, height)\n", "path": "qutebrowser/mainwindow/statusbar/command.py"}]}