We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Crash in schedule_completion_update because self._last_cursor_pos was None
From https://crashes.qutebrowser.org/view/2e422bf5

```
10:10:35 DEBUG    commands   command:run:485 command called: set-cmd-text ['-s', ':open -t']
10:10:35 DEBUG    commands   command:run:500 Calling qutebrowser.mainwindow.statusbar.command.Command.set_cmd_text_command(<qutebrowser.mainwindow.statusbar.command.Command>, ':open -t', None, True, False, False)
10:10:35 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/qutebrowser/completion/completer.py", line 206, in schedule_completion_update
    self._cmd.cursorPosition() > self._last_cursor_pos):
TypeError: '>' not supported between instances of 'int' and 'NoneType'
```

--- 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/completion/completer.py`
Content:
```
1 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
2 
3 # Copyright 2014-2018 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 """Completer attached to a CompletionView."""
21 
22 import attr
23 from PyQt5.QtCore import pyqtSlot, QObject, QTimer
24 
25 from qutebrowser.config import config
26 from qutebrowser.commands import cmdutils, runners
27 from qutebrowser.utils import log, utils, debug
28 from qutebrowser.completion.models import miscmodels
29 
30 
31 @attr.s
32 class CompletionInfo:
33 
34     """Context passed into all completion functions."""
35 
36     config = attr.ib()
37     keyconf = attr.ib()
38     win_id = attr.ib()
39 
40 
41 class Completer(QObject):
42 
43     """Completer which manages completions in a CompletionView.
44 
45     Attributes:
46         _cmd: The statusbar Command object this completer belongs to.
47         _win_id: The id of the window that owns this object.
48         _timer: The timer used to trigger the completion update.
49         _last_cursor_pos: The old cursor position so we avoid double completion
50                           updates.
51         _last_text: The old command text so we avoid double completion updates.
52         _last_completion_func: The completion function used for the last text.
53     """
54 
55     def __init__(self, *, cmd, win_id, parent=None):
56         super().__init__(parent)
57         self._cmd = cmd
58         self._win_id = win_id
59         self._timer = QTimer()
60         self._timer.setSingleShot(True)
61         self._timer.setInterval(0)
62         self._timer.timeout.connect(self._update_completion)
63         self._last_cursor_pos = None
64         self._last_text = None
65         self._last_completion_func = None
66         self._cmd.update_completion.connect(self.schedule_completion_update)
67 
68     def __repr__(self):
69         return utils.get_repr(self)
70 
71     def _model(self):
72         """Convenience method to get the current completion model."""
73         completion = self.parent()
74         return completion.model()
75 
76     def _get_new_completion(self, before_cursor, under_cursor):
77         """Get the completion function based on the current command text.
78 
79         Args:
80             before_cursor: The command chunks before the cursor.
81             under_cursor: The command chunk under the cursor.
82 
83         Return:
84             A completion model.
85         """
86         if '--' in before_cursor or under_cursor.startswith('-'):
87             # cursor on a flag or after an explicit split (--)
88             return None
89         log.completion.debug("Before removing flags: {}".format(before_cursor))
90         if not before_cursor:
91             # '|' or 'set|'
92             log.completion.debug('Starting command completion')
93             return miscmodels.command
94         try:
95             cmd = cmdutils.cmd_dict[before_cursor[0]]
96         except KeyError:
97             log.completion.debug("No completion for unknown command: {}"
98                                  .format(before_cursor[0]))
99             return None
100 
101         before_cursor = [x for x in before_cursor if not x.startswith('-')]
102         log.completion.debug("After removing flags: {}".format(before_cursor))
103         argpos = len(before_cursor) - 1
104         try:
105             func = cmd.get_pos_arg_info(argpos).completion
106         except IndexError:
107             log.completion.debug("No completion in position {}".format(argpos))
108             return None
109         return func
110 
111     def _quote(self, s):
112         """Quote s if it needs quoting for the commandline.
113 
114         Note we don't use shlex.quote because that quotes a lot of shell
115         metachars we don't need to have quoted.
116         """
117         if not s:
118             return "''"
119         elif any(c in s for c in ' "\'\t\n\\'):
120             # use single quotes, and put single quotes into double quotes
121             # the string $'b is then quoted as '$'"'"'b'
122             return "'" + s.replace("'", "'\"'\"'") + "'"
123         else:
124             return s
125 
126     def _partition(self):
127         """Divide the commandline text into chunks around the cursor position.
128 
129         Return:
130             ([parts_before_cursor], 'part_under_cursor', [parts_after_cursor])
131         """
132         text = self._cmd.text()[len(self._cmd.prefix()):]
133         if not text or not text.strip():
134             # Only ":", empty part under the cursor with nothing before/after
135             return [], '', []
136         parser = runners.CommandParser()
137         result = parser.parse(text, fallback=True, keep=True)
138         parts = [x for x in result.cmdline if x]
139         pos = self._cmd.cursorPosition() - len(self._cmd.prefix())
140         pos = min(pos, len(text))  # Qt treats 2-byte UTF-16 chars as 2 chars
141         log.completion.debug('partitioning {} around position {}'.format(parts,
142                                                                          pos))
143         for i, part in enumerate(parts):
144             pos -= len(part)
145             if pos <= 0:
146                 if part[pos-1:pos+1].isspace():
147                     # cursor is in a space between two existing words
148                     parts.insert(i, '')
149                 prefix = [x.strip() for x in parts[:i]]
150                 center = parts[i].strip()
151                 # strip trailing whitepsace included as a separate token
152                 postfix = [x.strip() for x in parts[i+1:] if not x.isspace()]
153                 log.completion.debug(
154                     "partitioned: {} '{}' {}".format(prefix, center, postfix))
155                 return prefix, center, postfix
156 
157         raise utils.Unreachable("Not all parts consumed: {}".format(parts))
158 
159     @pyqtSlot(str)
160     def on_selection_changed(self, text):
161         """Change the completed part if a new item was selected.
162 
163         Called from the views selectionChanged method.
164 
165         Args:
166             text: Newly selected text.
167         """
168         if text is None:
169             return
170         before, center, after = self._partition()
171         log.completion.debug("Changing {} to '{}'".format(center, text))
172         try:
173             maxsplit = cmdutils.cmd_dict[before[0]].maxsplit
174         except (KeyError, IndexError):
175             maxsplit = None
176         if maxsplit is None:
177             text = self._quote(text)
178         model = self._model()
179         if model.count() == 1 and config.val.completion.quick:
180             # If we only have one item, we want to apply it immediately and go
181             # on to the next part, unless we are quick-completing the part
182             # after maxsplit, so that we don't keep offering completions
183             # (see issue #1519)
184             if maxsplit is not None and maxsplit < len(before):
185                 self._change_completed_part(text, before, after)
186             else:
187                 self._change_completed_part(text, before, after,
188                                             immediate=True)
189         else:
190             self._change_completed_part(text, before, after)
191 
192     @pyqtSlot()
193     def schedule_completion_update(self):
194         """Schedule updating/enabling completion.
195 
196         For performance reasons we don't want to block here, instead we do this
197         in the background.
198 
199         We delay the update only if we've already input some text and ignore
200         updates if the text is shorter than completion.min_chars (unless we're
201         hitting backspace in which case updates won't be ignored).
202         """
203         _cmd, _sep, rest = self._cmd.text().partition(' ')
204         input_length = len(rest)
205         if (0 < input_length < config.val.completion.min_chars and
206                 self._cmd.cursorPosition() > self._last_cursor_pos):
207             log.completion.debug("Ignoring update because the length of "
208                                  "the text is less than completion.min_chars.")
209         elif (self._cmd.cursorPosition() == self._last_cursor_pos and
210               self._cmd.text() == self._last_text):
211             log.completion.debug("Ignoring update because there were no "
212                                  "changes.")
213         else:
214             log.completion.debug("Scheduling completion update.")
215             start_delay = config.val.completion.delay if self._last_text else 0
216             self._timer.start(start_delay)
217         self._last_cursor_pos = self._cmd.cursorPosition()
218         self._last_text = self._cmd.text()
219 
220     @pyqtSlot()
221     def _update_completion(self):
222         """Check if completions are available and activate them."""
223         completion = self.parent()
224 
225         if self._cmd.prefix() != ':':
226             # This is a search or gibberish, so we don't need to complete
227             # anything (yet)
228             # FIXME complete searches
229             # https://github.com/qutebrowser/qutebrowser/issues/32
230             completion.set_model(None)
231             self._last_completion_func = None
232             return
233 
234         before_cursor, pattern, after_cursor = self._partition()
235 
236         log.completion.debug("Updating completion: {} {} {}".format(
237             before_cursor, pattern, after_cursor))
238 
239         pattern = pattern.strip("'\"")
240         func = self._get_new_completion(before_cursor, pattern)
241 
242         if func is None:
243             log.completion.debug('Clearing completion')
244             completion.set_model(None)
245             self._last_completion_func = None
246             return
247 
248         if func != self._last_completion_func:
249             self._last_completion_func = func
250             args = (x for x in before_cursor[1:] if not x.startswith('-'))
251             with debug.log_time(log.completion, 'Starting {} completion'
252                                 .format(func.__name__)):
253                 info = CompletionInfo(config=config.instance,
254                                       keyconf=config.key_instance,
255                                       win_id=self._win_id)
256                 model = func(*args, info=info)
257             with debug.log_time(log.completion, 'Set completion model'):
258                 completion.set_model(model)
259 
260         completion.set_pattern(pattern)
261 
262     def _change_completed_part(self, newtext, before, after, immediate=False):
263         """Change the part we're currently completing in the commandline.
264 
265         Args:
266             text: The text to set (string) for the token under the cursor.
267             before: Commandline tokens before the token under the cursor.
268             after: Commandline tokens after the token under the cursor.
269             immediate: True if the text should be completed immediately
270                        including a trailing space and we shouldn't continue
271                        completing the current item.
272         """
273         text = self._cmd.prefix() + ' '.join(before + [newtext])
274         pos = len(text) + (1 if immediate else 0)
275         if after:
276             text += ' ' + ' '.join(after)
277         elif immediate:
278             # pad with a space if quick-completing the last entry
279             text += ' '
280         log.completion.debug("setting text = '{}', pos = {}".format(text, pos))
281 
282         # generally, we don't want to let self._cmd emit cursorPositionChanged,
283         # because that'll schedule a completion update. That happens when
284         # tabbing through the completions, and we want to change the command
285         # text but we also want to keep the original completion list for the
286         # command the user manually entered. The exception is when we're
287         # immediately completing, in which case we *do* want to update the
288         # completion view so that we can start completing the next part
289         if not immediate:
290             self._cmd.blockSignals(True)
291 
292         self._cmd.setText(text)
293         self._cmd.setCursorPosition(pos)
294         self._cmd.setFocus()
295 
296         self._cmd.blockSignals(False)
297         self._cmd.show_cmd.emit()
298
```
--- 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/completion/completer.py b/qutebrowser/completion/completer.py
--- a/qutebrowser/completion/completer.py
+++ b/qutebrowser/completion/completer.py
@@ -60,7 +60,7 @@
         self._timer.setSingleShot(True)
         self._timer.setInterval(0)
         self._timer.timeout.connect(self._update_completion)
-        self._last_cursor_pos = None
+        self._last_cursor_pos = -1
         self._last_text = None
         self._last_completion_func = None
         self._cmd.update_completion.connect(self.schedule_completion_update)

{"golden_diff": "diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py\n--- a/qutebrowser/completion/completer.py\n+++ b/qutebrowser/completion/completer.py\n@@ -60,7 +60,7 @@\n         self._timer.setSingleShot(True)\n         self._timer.setInterval(0)\n         self._timer.timeout.connect(self._update_completion)\n-        self._last_cursor_pos = None\n+        self._last_cursor_pos = -1\n         self._last_text = None\n         self._last_completion_func = None\n         self._cmd.update_completion.connect(self.schedule_completion_update)\n", "issue": "Crash in schedule_completion_update because self._last_cursor_pos was None\nFrom https://crashes.qutebrowser.org/view/2e422bf5\r\n\r\n```\r\n10:10:35 DEBUG    commands   command:run:485 command called: set-cmd-text ['-s', ':open -t']\r\n10:10:35 DEBUG    commands   command:run:500 Calling qutebrowser.mainwindow.statusbar.command.Command.set_cmd_text_command(<qutebrowser.mainwindow.statusbar.command.Command>, ':open -t', None, True, False, False)\r\n10:10:35 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception\r\nTraceback (most recent call last):\r\n  File \"/usr/lib/python3.6/site-packages/qutebrowser/completion/completer.py\", line 206, in schedule_completion_update\r\n    self._cmd.cursorPosition() > self._last_cursor_pos):\r\nTypeError: '>' not supported between instances of 'int' and 'NoneType'\r\n```\n", "before_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2014-2018 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\"\"\"Completer attached to a CompletionView.\"\"\"\n\nimport attr\nfrom PyQt5.QtCore import pyqtSlot, QObject, QTimer\n\nfrom qutebrowser.config import config\nfrom qutebrowser.commands import cmdutils, runners\nfrom qutebrowser.utils import log, utils, debug\nfrom qutebrowser.completion.models import miscmodels\n\n\n@attr.s\nclass CompletionInfo:\n\n    \"\"\"Context passed into all completion functions.\"\"\"\n\n    config = attr.ib()\n    keyconf = attr.ib()\n    win_id = attr.ib()\n\n\nclass Completer(QObject):\n\n    \"\"\"Completer which manages completions in a CompletionView.\n\n    Attributes:\n        _cmd: The statusbar Command object this completer belongs to.\n        _win_id: The id of the window that owns this object.\n        _timer: The timer used to trigger the completion update.\n        _last_cursor_pos: The old cursor position so we avoid double completion\n                          updates.\n        _last_text: The old command text so we avoid double completion updates.\n        _last_completion_func: The completion function used for the last text.\n    \"\"\"\n\n    def __init__(self, *, cmd, win_id, parent=None):\n        super().__init__(parent)\n        self._cmd = cmd\n        self._win_id = win_id\n        self._timer = QTimer()\n        self._timer.setSingleShot(True)\n        self._timer.setInterval(0)\n        self._timer.timeout.connect(self._update_completion)\n        self._last_cursor_pos = None\n        self._last_text = None\n        self._last_completion_func = None\n        self._cmd.update_completion.connect(self.schedule_completion_update)\n\n    def __repr__(self):\n        return utils.get_repr(self)\n\n    def _model(self):\n        \"\"\"Convenience method to get the current completion model.\"\"\"\n        completion = self.parent()\n        return completion.model()\n\n    def _get_new_completion(self, before_cursor, under_cursor):\n        \"\"\"Get the completion function based on the current command text.\n\n        Args:\n            before_cursor: The command chunks before the cursor.\n            under_cursor: The command chunk under the cursor.\n\n        Return:\n            A completion model.\n        \"\"\"\n        if '--' in before_cursor or under_cursor.startswith('-'):\n            # cursor on a flag or after an explicit split (--)\n            return None\n        log.completion.debug(\"Before removing flags: {}\".format(before_cursor))\n        if not before_cursor:\n            # '|' or 'set|'\n            log.completion.debug('Starting command completion')\n            return miscmodels.command\n        try:\n            cmd = cmdutils.cmd_dict[before_cursor[0]]\n        except KeyError:\n            log.completion.debug(\"No completion for unknown command: {}\"\n                                 .format(before_cursor[0]))\n            return None\n\n        before_cursor = [x for x in before_cursor if not x.startswith('-')]\n        log.completion.debug(\"After removing flags: {}\".format(before_cursor))\n        argpos = len(before_cursor) - 1\n        try:\n            func = cmd.get_pos_arg_info(argpos).completion\n        except IndexError:\n            log.completion.debug(\"No completion in position {}\".format(argpos))\n            return None\n        return func\n\n    def _quote(self, s):\n        \"\"\"Quote s if it needs quoting for the commandline.\n\n        Note we don't use shlex.quote because that quotes a lot of shell\n        metachars we don't need to have quoted.\n        \"\"\"\n        if not s:\n            return \"''\"\n        elif any(c in s for c in ' \"\\'\\t\\n\\\\'):\n            # use single quotes, and put single quotes into double quotes\n            # the string $'b is then quoted as '$'\"'\"'b'\n            return \"'\" + s.replace(\"'\", \"'\\\"'\\\"'\") + \"'\"\n        else:\n            return s\n\n    def _partition(self):\n        \"\"\"Divide the commandline text into chunks around the cursor position.\n\n        Return:\n            ([parts_before_cursor], 'part_under_cursor', [parts_after_cursor])\n        \"\"\"\n        text = self._cmd.text()[len(self._cmd.prefix()):]\n        if not text or not text.strip():\n            # Only \":\", empty part under the cursor with nothing before/after\n            return [], '', []\n        parser = runners.CommandParser()\n        result = parser.parse(text, fallback=True, keep=True)\n        parts = [x for x in result.cmdline if x]\n        pos = self._cmd.cursorPosition() - len(self._cmd.prefix())\n        pos = min(pos, len(text))  # Qt treats 2-byte UTF-16 chars as 2 chars\n        log.completion.debug('partitioning {} around position {}'.format(parts,\n                                                                         pos))\n        for i, part in enumerate(parts):\n            pos -= len(part)\n            if pos <= 0:\n                if part[pos-1:pos+1].isspace():\n                    # cursor is in a space between two existing words\n                    parts.insert(i, '')\n                prefix = [x.strip() for x in parts[:i]]\n                center = parts[i].strip()\n                # strip trailing whitepsace included as a separate token\n                postfix = [x.strip() for x in parts[i+1:] if not x.isspace()]\n                log.completion.debug(\n                    \"partitioned: {} '{}' {}\".format(prefix, center, postfix))\n                return prefix, center, postfix\n\n        raise utils.Unreachable(\"Not all parts consumed: {}\".format(parts))\n\n    @pyqtSlot(str)\n    def on_selection_changed(self, text):\n        \"\"\"Change the completed part if a new item was selected.\n\n        Called from the views selectionChanged method.\n\n        Args:\n            text: Newly selected text.\n        \"\"\"\n        if text is None:\n            return\n        before, center, after = self._partition()\n        log.completion.debug(\"Changing {} to '{}'\".format(center, text))\n        try:\n            maxsplit = cmdutils.cmd_dict[before[0]].maxsplit\n        except (KeyError, IndexError):\n            maxsplit = None\n        if maxsplit is None:\n            text = self._quote(text)\n        model = self._model()\n        if model.count() == 1 and config.val.completion.quick:\n            # If we only have one item, we want to apply it immediately and go\n            # on to the next part, unless we are quick-completing the part\n            # after maxsplit, so that we don't keep offering completions\n            # (see issue #1519)\n            if maxsplit is not None and maxsplit < len(before):\n                self._change_completed_part(text, before, after)\n            else:\n                self._change_completed_part(text, before, after,\n                                            immediate=True)\n        else:\n            self._change_completed_part(text, before, after)\n\n    @pyqtSlot()\n    def schedule_completion_update(self):\n        \"\"\"Schedule updating/enabling completion.\n\n        For performance reasons we don't want to block here, instead we do this\n        in the background.\n\n        We delay the update only if we've already input some text and ignore\n        updates if the text is shorter than completion.min_chars (unless we're\n        hitting backspace in which case updates won't be ignored).\n        \"\"\"\n        _cmd, _sep, rest = self._cmd.text().partition(' ')\n        input_length = len(rest)\n        if (0 < input_length < config.val.completion.min_chars and\n                self._cmd.cursorPosition() > self._last_cursor_pos):\n            log.completion.debug(\"Ignoring update because the length of \"\n                                 \"the text is less than completion.min_chars.\")\n        elif (self._cmd.cursorPosition() == self._last_cursor_pos and\n              self._cmd.text() == self._last_text):\n            log.completion.debug(\"Ignoring update because there were no \"\n                                 \"changes.\")\n        else:\n            log.completion.debug(\"Scheduling completion update.\")\n            start_delay = config.val.completion.delay if self._last_text else 0\n            self._timer.start(start_delay)\n        self._last_cursor_pos = self._cmd.cursorPosition()\n        self._last_text = self._cmd.text()\n\n    @pyqtSlot()\n    def _update_completion(self):\n        \"\"\"Check if completions are available and activate them.\"\"\"\n        completion = self.parent()\n\n        if self._cmd.prefix() != ':':\n            # This is a search or gibberish, so we don't need to complete\n            # anything (yet)\n            # FIXME complete searches\n            # https://github.com/qutebrowser/qutebrowser/issues/32\n            completion.set_model(None)\n            self._last_completion_func = None\n            return\n\n        before_cursor, pattern, after_cursor = self._partition()\n\n        log.completion.debug(\"Updating completion: {} {} {}\".format(\n            before_cursor, pattern, after_cursor))\n\n        pattern = pattern.strip(\"'\\\"\")\n        func = self._get_new_completion(before_cursor, pattern)\n\n        if func is None:\n            log.completion.debug('Clearing completion')\n            completion.set_model(None)\n            self._last_completion_func = None\n            return\n\n        if func != self._last_completion_func:\n            self._last_completion_func = func\n            args = (x for x in before_cursor[1:] if not x.startswith('-'))\n            with debug.log_time(log.completion, 'Starting {} completion'\n                                .format(func.__name__)):\n                info = CompletionInfo(config=config.instance,\n                                      keyconf=config.key_instance,\n                                      win_id=self._win_id)\n                model = func(*args, info=info)\n            with debug.log_time(log.completion, 'Set completion model'):\n                completion.set_model(model)\n\n        completion.set_pattern(pattern)\n\n    def _change_completed_part(self, newtext, before, after, immediate=False):\n        \"\"\"Change the part we're currently completing in the commandline.\n\n        Args:\n            text: The text to set (string) for the token under the cursor.\n            before: Commandline tokens before the token under the cursor.\n            after: Commandline tokens after the token under the cursor.\n            immediate: True if the text should be completed immediately\n                       including a trailing space and we shouldn't continue\n                       completing the current item.\n        \"\"\"\n        text = self._cmd.prefix() + ' '.join(before + [newtext])\n        pos = len(text) + (1 if immediate else 0)\n        if after:\n            text += ' ' + ' '.join(after)\n        elif immediate:\n            # pad with a space if quick-completing the last entry\n            text += ' '\n        log.completion.debug(\"setting text = '{}', pos = {}\".format(text, pos))\n\n        # generally, we don't want to let self._cmd emit cursorPositionChanged,\n        # because that'll schedule a completion update. That happens when\n        # tabbing through the completions, and we want to change the command\n        # text but we also want to keep the original completion list for the\n        # command the user manually entered. The exception is when we're\n        # immediately completing, in which case we *do* want to update the\n        # completion view so that we can start completing the next part\n        if not immediate:\n            self._cmd.blockSignals(True)\n\n        self._cmd.setText(text)\n        self._cmd.setCursorPosition(pos)\n        self._cmd.setFocus()\n\n        self._cmd.blockSignals(False)\n        self._cmd.show_cmd.emit()\n", "path": "qutebrowser/completion/completer.py"}], "after_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2014-2018 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\"\"\"Completer attached to a CompletionView.\"\"\"\n\nimport attr\nfrom PyQt5.QtCore import pyqtSlot, QObject, QTimer\n\nfrom qutebrowser.config import config\nfrom qutebrowser.commands import cmdutils, runners\nfrom qutebrowser.utils import log, utils, debug\nfrom qutebrowser.completion.models import miscmodels\n\n\n@attr.s\nclass CompletionInfo:\n\n    \"\"\"Context passed into all completion functions.\"\"\"\n\n    config = attr.ib()\n    keyconf = attr.ib()\n    win_id = attr.ib()\n\n\nclass Completer(QObject):\n\n    \"\"\"Completer which manages completions in a CompletionView.\n\n    Attributes:\n        _cmd: The statusbar Command object this completer belongs to.\n        _win_id: The id of the window that owns this object.\n        _timer: The timer used to trigger the completion update.\n        _last_cursor_pos: The old cursor position so we avoid double completion\n                          updates.\n        _last_text: The old command text so we avoid double completion updates.\n        _last_completion_func: The completion function used for the last text.\n    \"\"\"\n\n    def __init__(self, *, cmd, win_id, parent=None):\n        super().__init__(parent)\n        self._cmd = cmd\n        self._win_id = win_id\n        self._timer = QTimer()\n        self._timer.setSingleShot(True)\n        self._timer.setInterval(0)\n        self._timer.timeout.connect(self._update_completion)\n        self._last_cursor_pos = -1\n        self._last_text = None\n        self._last_completion_func = None\n        self._cmd.update_completion.connect(self.schedule_completion_update)\n\n    def __repr__(self):\n        return utils.get_repr(self)\n\n    def _model(self):\n        \"\"\"Convenience method to get the current completion model.\"\"\"\n        completion = self.parent()\n        return completion.model()\n\n    def _get_new_completion(self, before_cursor, under_cursor):\n        \"\"\"Get the completion function based on the current command text.\n\n        Args:\n            before_cursor: The command chunks before the cursor.\n            under_cursor: The command chunk under the cursor.\n\n        Return:\n            A completion model.\n        \"\"\"\n        if '--' in before_cursor or under_cursor.startswith('-'):\n            # cursor on a flag or after an explicit split (--)\n            return None\n        log.completion.debug(\"Before removing flags: {}\".format(before_cursor))\n        if not before_cursor:\n            # '|' or 'set|'\n            log.completion.debug('Starting command completion')\n            return miscmodels.command\n        try:\n            cmd = cmdutils.cmd_dict[before_cursor[0]]\n        except KeyError:\n            log.completion.debug(\"No completion for unknown command: {}\"\n                                 .format(before_cursor[0]))\n            return None\n\n        before_cursor = [x for x in before_cursor if not x.startswith('-')]\n        log.completion.debug(\"After removing flags: {}\".format(before_cursor))\n        argpos = len(before_cursor) - 1\n        try:\n            func = cmd.get_pos_arg_info(argpos).completion\n        except IndexError:\n            log.completion.debug(\"No completion in position {}\".format(argpos))\n            return None\n        return func\n\n    def _quote(self, s):\n        \"\"\"Quote s if it needs quoting for the commandline.\n\n        Note we don't use shlex.quote because that quotes a lot of shell\n        metachars we don't need to have quoted.\n        \"\"\"\n        if not s:\n            return \"''\"\n        elif any(c in s for c in ' \"\\'\\t\\n\\\\'):\n            # use single quotes, and put single quotes into double quotes\n            # the string $'b is then quoted as '$'\"'\"'b'\n            return \"'\" + s.replace(\"'\", \"'\\\"'\\\"'\") + \"'\"\n        else:\n            return s\n\n    def _partition(self):\n        \"\"\"Divide the commandline text into chunks around the cursor position.\n\n        Return:\n            ([parts_before_cursor], 'part_under_cursor', [parts_after_cursor])\n        \"\"\"\n        text = self._cmd.text()[len(self._cmd.prefix()):]\n        if not text or not text.strip():\n            # Only \":\", empty part under the cursor with nothing before/after\n            return [], '', []\n        parser = runners.CommandParser()\n        result = parser.parse(text, fallback=True, keep=True)\n        parts = [x for x in result.cmdline if x]\n        pos = self._cmd.cursorPosition() - len(self._cmd.prefix())\n        pos = min(pos, len(text))  # Qt treats 2-byte UTF-16 chars as 2 chars\n        log.completion.debug('partitioning {} around position {}'.format(parts,\n                                                                         pos))\n        for i, part in enumerate(parts):\n            pos -= len(part)\n            if pos <= 0:\n                if part[pos-1:pos+1].isspace():\n                    # cursor is in a space between two existing words\n                    parts.insert(i, '')\n                prefix = [x.strip() for x in parts[:i]]\n                center = parts[i].strip()\n                # strip trailing whitepsace included as a separate token\n                postfix = [x.strip() for x in parts[i+1:] if not x.isspace()]\n                log.completion.debug(\n                    \"partitioned: {} '{}' {}\".format(prefix, center, postfix))\n                return prefix, center, postfix\n\n        raise utils.Unreachable(\"Not all parts consumed: {}\".format(parts))\n\n    @pyqtSlot(str)\n    def on_selection_changed(self, text):\n        \"\"\"Change the completed part if a new item was selected.\n\n        Called from the views selectionChanged method.\n\n        Args:\n            text: Newly selected text.\n        \"\"\"\n        if text is None:\n            return\n        before, center, after = self._partition()\n        log.completion.debug(\"Changing {} to '{}'\".format(center, text))\n        try:\n            maxsplit = cmdutils.cmd_dict[before[0]].maxsplit\n        except (KeyError, IndexError):\n            maxsplit = None\n        if maxsplit is None:\n            text = self._quote(text)\n        model = self._model()\n        if model.count() == 1 and config.val.completion.quick:\n            # If we only have one item, we want to apply it immediately and go\n            # on to the next part, unless we are quick-completing the part\n            # after maxsplit, so that we don't keep offering completions\n            # (see issue #1519)\n            if maxsplit is not None and maxsplit < len(before):\n                self._change_completed_part(text, before, after)\n            else:\n                self._change_completed_part(text, before, after,\n                                            immediate=True)\n        else:\n            self._change_completed_part(text, before, after)\n\n    @pyqtSlot()\n    def schedule_completion_update(self):\n        \"\"\"Schedule updating/enabling completion.\n\n        For performance reasons we don't want to block here, instead we do this\n        in the background.\n\n        We delay the update only if we've already input some text and ignore\n        updates if the text is shorter than completion.min_chars (unless we're\n        hitting backspace in which case updates won't be ignored).\n        \"\"\"\n        _cmd, _sep, rest = self._cmd.text().partition(' ')\n        input_length = len(rest)\n        if (0 < input_length < config.val.completion.min_chars and\n                self._cmd.cursorPosition() > self._last_cursor_pos):\n            log.completion.debug(\"Ignoring update because the length of \"\n                                 \"the text is less than completion.min_chars.\")\n        elif (self._cmd.cursorPosition() == self._last_cursor_pos and\n              self._cmd.text() == self._last_text):\n            log.completion.debug(\"Ignoring update because there were no \"\n                                 \"changes.\")\n        else:\n            log.completion.debug(\"Scheduling completion update.\")\n            start_delay = config.val.completion.delay if self._last_text else 0\n            self._timer.start(start_delay)\n        self._last_cursor_pos = self._cmd.cursorPosition()\n        self._last_text = self._cmd.text()\n\n    @pyqtSlot()\n    def _update_completion(self):\n        \"\"\"Check if completions are available and activate them.\"\"\"\n        completion = self.parent()\n\n        if self._cmd.prefix() != ':':\n            # This is a search or gibberish, so we don't need to complete\n            # anything (yet)\n            # FIXME complete searches\n            # https://github.com/qutebrowser/qutebrowser/issues/32\n            completion.set_model(None)\n            self._last_completion_func = None\n            return\n\n        before_cursor, pattern, after_cursor = self._partition()\n\n        log.completion.debug(\"Updating completion: {} {} {}\".format(\n            before_cursor, pattern, after_cursor))\n\n        pattern = pattern.strip(\"'\\\"\")\n        func = self._get_new_completion(before_cursor, pattern)\n\n        if func is None:\n            log.completion.debug('Clearing completion')\n            completion.set_model(None)\n            self._last_completion_func = None\n            return\n\n        if func != self._last_completion_func:\n            self._last_completion_func = func\n            args = (x for x in before_cursor[1:] if not x.startswith('-'))\n            with debug.log_time(log.completion, 'Starting {} completion'\n                                .format(func.__name__)):\n                info = CompletionInfo(config=config.instance,\n                                      keyconf=config.key_instance,\n                                      win_id=self._win_id)\n                model = func(*args, info=info)\n            with debug.log_time(log.completion, 'Set completion model'):\n                completion.set_model(model)\n\n        completion.set_pattern(pattern)\n\n    def _change_completed_part(self, newtext, before, after, immediate=False):\n        \"\"\"Change the part we're currently completing in the commandline.\n\n        Args:\n            text: The text to set (string) for the token under the cursor.\n            before: Commandline tokens before the token under the cursor.\n            after: Commandline tokens after the token under the cursor.\n            immediate: True if the text should be completed immediately\n                       including a trailing space and we shouldn't continue\n                       completing the current item.\n        \"\"\"\n        text = self._cmd.prefix() + ' '.join(before + [newtext])\n        pos = len(text) + (1 if immediate else 0)\n        if after:\n            text += ' ' + ' '.join(after)\n        elif immediate:\n            # pad with a space if quick-completing the last entry\n            text += ' '\n        log.completion.debug(\"setting text = '{}', pos = {}\".format(text, pos))\n\n        # generally, we don't want to let self._cmd emit cursorPositionChanged,\n        # because that'll schedule a completion update. That happens when\n        # tabbing through the completions, and we want to change the command\n        # text but we also want to keep the original completion list for the\n        # command the user manually entered. The exception is when we're\n        # immediately completing, in which case we *do* want to update the\n        # completion view so that we can start completing the next part\n        if not immediate:\n            self._cmd.blockSignals(True)\n\n        self._cmd.setText(text)\n        self._cmd.setCursorPosition(pos)\n        self._cmd.setFocus()\n\n        self._cmd.blockSignals(False)\n        self._cmd.show_cmd.emit()\n", "path": "qutebrowser/completion/completer.py"}]}