prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Port completion.models.listcategory to QRegularExpression
  In `qutebrowser/completion/models/listcategory.py`, we use `QRegExp`, which is going to be removed in Qt 6:
  
  ```python
          rx = QRegExp(val, Qt.CaseInsensitive)
          self.setFilterRegExp(rx)
  ```
  
  We should instead [port](https://doc-snapshots.qt.io/qt6-dev/qtcore-changes-qt6.html#regular-expression-classes) this to use [QRegularExpression](https://doc.qt.io/qt-5/qregularexpression.html) (or, perhaps, Python's `re`?) instead.
  
  ~~(Also, we should probably call `qtutils.ensure_valid(rx)`)~~ (done in `master` already)
  
  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/completion/models/listcategory.py`
  Content:
  ```
  1 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
  2 
  3 # Copyright 2017-2020 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
  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 """Completion category that uses a list of tuples as a data source."""
  21 
  22 import re
  23 from typing import Iterable, Tuple
  24 
  25 from PyQt5.QtCore import Qt, QSortFilterProxyModel, QRegExp
  26 from PyQt5.QtGui import QStandardItem, QStandardItemModel
  27 from PyQt5.QtWidgets import QWidget
  28 
  29 from qutebrowser.completion.models import util
  30 from qutebrowser.utils import qtutils, log
  31 
  32 
  33 class ListCategory(QSortFilterProxyModel):
  34 
  35     """Expose a list of items as a category for the CompletionModel."""
  36 
  37     def __init__(self,
  38                  name: str,
  39                  items: Iterable[Tuple[str, ...]],
  40                  sort: bool = True,
  41                  delete_func: util.DeleteFuncType = None,
  42                  parent: QWidget = None):
  43         super().__init__(parent)
  44         self.name = name
  45         self.srcmodel = QStandardItemModel(parent=self)
  46         self._pattern = ''
  47         # ListCategory filters all columns
  48         self.columns_to_filter = [0, 1, 2]
  49         self.setFilterKeyColumn(-1)
  50         for item in items:
  51             self.srcmodel.appendRow([QStandardItem(x) for x in item])
  52         self.setSourceModel(self.srcmodel)
  53         self.delete_func = delete_func
  54         self._sort = sort
  55 
  56     def set_pattern(self, val):
  57         """Setter for pattern.
  58 
  59         Args:
  60             val: The value to set.
  61         """
  62         self._pattern = val
  63         val = re.sub(r' +', r' ', val)  # See #1919
  64         val = re.escape(val)
  65         val = val.replace(r'\ ', '.*')
  66         rx = QRegExp(val, Qt.CaseInsensitive)
  67         qtutils.ensure_valid(rx)
  68         self.setFilterRegExp(rx)
  69         self.invalidate()
  70         sortcol = 0
  71         self.sort(sortcol)
  72 
  73     def lessThan(self, lindex, rindex):
  74         """Custom sorting implementation.
  75 
  76         Prefers all items which start with self._pattern. Other than that, uses
  77         normal Python string sorting.
  78 
  79         Args:
  80             lindex: The QModelIndex of the left item (*left* < right)
  81             rindex: The QModelIndex of the right item (left < *right*)
  82 
  83         Return:
  84             True if left < right, else False
  85         """
  86         qtutils.ensure_valid(lindex)
  87         qtutils.ensure_valid(rindex)
  88 
  89         left = self.srcmodel.data(lindex)
  90         right = self.srcmodel.data(rindex)
  91 
  92         if left is None or right is None:  # pragma: no cover
  93             log.completion.warning("Got unexpected None value, "
  94                                    "left={!r} right={!r} "
  95                                    "lindex={!r} rindex={!r}"
  96                                    .format(left, right, lindex, rindex))
  97             return False
  98 
  99         leftstart = left.startswith(self._pattern)
  100         rightstart = right.startswith(self._pattern)
  101 
  102         if leftstart and not rightstart:
  103             return True
  104         elif rightstart and not leftstart:
  105             return False
  106         elif self._sort:
  107             return left < right
  108         else:
  109             return False
  110
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/qutebrowser/completion/models/listcategory.py b/qutebrowser/completion/models/listcategory.py
  --- a/qutebrowser/completion/models/listcategory.py
  +++ b/qutebrowser/completion/models/listcategory.py
  @@ -22,7 +22,7 @@
   import re
   from typing import Iterable, Tuple
   
  -from PyQt5.QtCore import Qt, QSortFilterProxyModel, QRegExp
  +from PyQt5.QtCore import QSortFilterProxyModel, QRegularExpression
   from PyQt5.QtGui import QStandardItem, QStandardItemModel
   from PyQt5.QtWidgets import QWidget
   
  @@ -63,9 +63,9 @@
           val = re.sub(r' +', r' ', val)  # See #1919
           val = re.escape(val)
           val = val.replace(r'\ ', '.*')
  -        rx = QRegExp(val, Qt.CaseInsensitive)
  +        rx = QRegularExpression(val, QRegularExpression.CaseInsensitiveOption)
           qtutils.ensure_valid(rx)
  -        self.setFilterRegExp(rx)
  +        self.setFilterRegularExpression(rx)
           self.invalidate()
           sortcol = 0
           self.sort(sortcol)
  
verification_info: {"golden_diff": "diff --git a/qutebrowser/completion/models/listcategory.py b/qutebrowser/completion/models/listcategory.py\n--- a/qutebrowser/completion/models/listcategory.py\n+++ b/qutebrowser/completion/models/listcategory.py\n@@ -22,7 +22,7 @@\n import re\n from typing import Iterable, Tuple\n \n-from PyQt5.QtCore import Qt, QSortFilterProxyModel, QRegExp\n+from PyQt5.QtCore import QSortFilterProxyModel, QRegularExpression\n from PyQt5.QtGui import QStandardItem, QStandardItemModel\n from PyQt5.QtWidgets import QWidget\n \n@@ -63,9 +63,9 @@\n         val = re.sub(r' +', r' ', val)  # See #1919\n         val = re.escape(val)\n         val = val.replace(r'\\ ', '.*')\n-        rx = QRegExp(val, Qt.CaseInsensitive)\n+        rx = QRegularExpression(val, QRegularExpression.CaseInsensitiveOption)\n         qtutils.ensure_valid(rx)\n-        self.setFilterRegExp(rx)\n+        self.setFilterRegularExpression(rx)\n         self.invalidate()\n         sortcol = 0\n         self.sort(sortcol)\n", "issue": "Port completion.models.listcategory to QRegularExpression\nIn `qutebrowser/completion/models/listcategory.py`, we use `QRegExp`, which is going to be removed in Qt 6:\r\n\r\n```python\r\n        rx = QRegExp(val, Qt.CaseInsensitive)\r\n        self.setFilterRegExp(rx)\r\n```\r\n\r\nWe should instead [port](https://doc-snapshots.qt.io/qt6-dev/qtcore-changes-qt6.html#regular-expression-classes) this to use [QRegularExpression](https://doc.qt.io/qt-5/qregularexpression.html) (or, perhaps, Python's `re`?) instead.\r\n\r\n~~(Also, we should probably call `qtutils.ensure_valid(rx)`)~~ (done in `master` already)\r\n\r\ncc @rcorre \n", "before_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2017-2020 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>\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\"\"\"Completion category that uses a list of tuples as a data source.\"\"\"\n\nimport re\nfrom typing import Iterable, Tuple\n\nfrom PyQt5.QtCore import Qt, QSortFilterProxyModel, QRegExp\nfrom PyQt5.QtGui import QStandardItem, QStandardItemModel\nfrom PyQt5.QtWidgets import QWidget\n\nfrom qutebrowser.completion.models import util\nfrom qutebrowser.utils import qtutils, log\n\n\nclass ListCategory(QSortFilterProxyModel):\n\n    \"\"\"Expose a list of items as a category for the CompletionModel.\"\"\"\n\n    def __init__(self,\n                 name: str,\n                 items: Iterable[Tuple[str, ...]],\n                 sort: bool = True,\n                 delete_func: util.DeleteFuncType = None,\n                 parent: QWidget = None):\n        super().__init__(parent)\n        self.name = name\n        self.srcmodel = QStandardItemModel(parent=self)\n        self._pattern = ''\n        # ListCategory filters all columns\n        self.columns_to_filter = [0, 1, 2]\n        self.setFilterKeyColumn(-1)\n        for item in items:\n            self.srcmodel.appendRow([QStandardItem(x) for x in item])\n        self.setSourceModel(self.srcmodel)\n        self.delete_func = delete_func\n        self._sort = sort\n\n    def set_pattern(self, val):\n        \"\"\"Setter for pattern.\n\n        Args:\n            val: The value to set.\n        \"\"\"\n        self._pattern = val\n        val = re.sub(r' +', r' ', val)  # See #1919\n        val = re.escape(val)\n        val = val.replace(r'\\ ', '.*')\n        rx = QRegExp(val, Qt.CaseInsensitive)\n        qtutils.ensure_valid(rx)\n        self.setFilterRegExp(rx)\n        self.invalidate()\n        sortcol = 0\n        self.sort(sortcol)\n\n    def lessThan(self, lindex, rindex):\n        \"\"\"Custom sorting implementation.\n\n        Prefers all items which start with self._pattern. Other than that, uses\n        normal Python string sorting.\n\n        Args:\n            lindex: The QModelIndex of the left item (*left* < right)\n            rindex: The QModelIndex of the right item (left < *right*)\n\n        Return:\n            True if left < right, else False\n        \"\"\"\n        qtutils.ensure_valid(lindex)\n        qtutils.ensure_valid(rindex)\n\n        left = self.srcmodel.data(lindex)\n        right = self.srcmodel.data(rindex)\n\n        if left is None or right is None:  # pragma: no cover\n            log.completion.warning(\"Got unexpected None value, \"\n                                   \"left={!r} right={!r} \"\n                                   \"lindex={!r} rindex={!r}\"\n                                   .format(left, right, lindex, rindex))\n            return False\n\n        leftstart = left.startswith(self._pattern)\n        rightstart = right.startswith(self._pattern)\n\n        if leftstart and not rightstart:\n            return True\n        elif rightstart and not leftstart:\n            return False\n        elif self._sort:\n            return left < right\n        else:\n            return False\n", "path": "qutebrowser/completion/models/listcategory.py"}], "after_files": [{"content": "# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:\n\n# Copyright 2017-2020 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>\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\"\"\"Completion category that uses a list of tuples as a data source.\"\"\"\n\nimport re\nfrom typing import Iterable, Tuple\n\nfrom PyQt5.QtCore import QSortFilterProxyModel, QRegularExpression\nfrom PyQt5.QtGui import QStandardItem, QStandardItemModel\nfrom PyQt5.QtWidgets import QWidget\n\nfrom qutebrowser.completion.models import util\nfrom qutebrowser.utils import qtutils, log\n\n\nclass ListCategory(QSortFilterProxyModel):\n\n    \"\"\"Expose a list of items as a category for the CompletionModel.\"\"\"\n\n    def __init__(self,\n                 name: str,\n                 items: Iterable[Tuple[str, ...]],\n                 sort: bool = True,\n                 delete_func: util.DeleteFuncType = None,\n                 parent: QWidget = None):\n        super().__init__(parent)\n        self.name = name\n        self.srcmodel = QStandardItemModel(parent=self)\n        self._pattern = ''\n        # ListCategory filters all columns\n        self.columns_to_filter = [0, 1, 2]\n        self.setFilterKeyColumn(-1)\n        for item in items:\n            self.srcmodel.appendRow([QStandardItem(x) for x in item])\n        self.setSourceModel(self.srcmodel)\n        self.delete_func = delete_func\n        self._sort = sort\n\n    def set_pattern(self, val):\n        \"\"\"Setter for pattern.\n\n        Args:\n            val: The value to set.\n        \"\"\"\n        self._pattern = val\n        val = re.sub(r' +', r' ', val)  # See #1919\n        val = re.escape(val)\n        val = val.replace(r'\\ ', '.*')\n        rx = QRegularExpression(val, QRegularExpression.CaseInsensitiveOption)\n        qtutils.ensure_valid(rx)\n        self.setFilterRegularExpression(rx)\n        self.invalidate()\n        sortcol = 0\n        self.sort(sortcol)\n\n    def lessThan(self, lindex, rindex):\n        \"\"\"Custom sorting implementation.\n\n        Prefers all items which start with self._pattern. Other than that, uses\n        normal Python string sorting.\n\n        Args:\n            lindex: The QModelIndex of the left item (*left* < right)\n            rindex: The QModelIndex of the right item (left < *right*)\n\n        Return:\n            True if left < right, else False\n        \"\"\"\n        qtutils.ensure_valid(lindex)\n        qtutils.ensure_valid(rindex)\n\n        left = self.srcmodel.data(lindex)\n        right = self.srcmodel.data(rindex)\n\n        if left is None or right is None:  # pragma: no cover\n            log.completion.warning(\"Got unexpected None value, \"\n                                   \"left={!r} right={!r} \"\n                                   \"lindex={!r} rindex={!r}\"\n                                   .format(left, right, lindex, rindex))\n            return False\n\n        leftstart = left.startswith(self._pattern)\n        rightstart = right.startswith(self._pattern)\n\n        if leftstart and not rightstart:\n            return True\n        elif rightstart and not leftstart:\n            return False\n        elif self._sort:\n            return left < right\n        else:\n            return False\n", "path": "qutebrowser/completion/models/listcategory.py"}]}