We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Completing URL with '&' shows '&amp;'
Consider this URL: https://wiki.archlinux.org/api.php?action=query&pageids=12345

After writing `action=query` in the `:open` prompt, it is highlighted correctly. After adding `&` (i.e. the filter is `action=query&`), the URL is changed to `https://wiki.archlinux.org/api.php?action=query&amp;pageids=12345` in the completer and the pattern is still highlighted. After adding anything what follows in the URL, e.g. `action=query&pageids`, the URL is changed back to the original and nothing is highlighted, although the URL still matches the filter as expected.

--- 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/completiondelegate.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 """Completion item delegate for CompletionView.
21 
22 We use this to be able to highlight parts of the text.
23 """
24 
25 import re
26 import html
27 
28 from PyQt5.QtWidgets import QStyle, QStyleOptionViewItem, QStyledItemDelegate
29 from PyQt5.QtCore import QRectF, QSize, Qt
30 from PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption,
31                          QAbstractTextDocumentLayout)
32 
33 from qutebrowser.config import config
34 from qutebrowser.utils import qtutils, jinja
35 
36 
37 _cached_stylesheet = None
38 
39 
40 class CompletionItemDelegate(QStyledItemDelegate):
41 
42     """Delegate used by CompletionView to draw individual items.
43 
44     Mainly a cleaned up port of Qt's way to draw a TreeView item, except it
45     uses a QTextDocument to draw the text and add marking.
46 
47     Original implementation:
48         qt/src/gui/styles/qcommonstyle.cpp:drawControl:2153
49 
50     Attributes:
51         _opt: The QStyleOptionViewItem which is used.
52         _style: The style to be used.
53         _painter: The QPainter to be used.
54         _doc: The QTextDocument to be used.
55     """
56 
57     # FIXME this is horribly slow when resizing.
58     # We should probably cache something in _get_textdoc or so, but as soon as
59     # we implement eliding that cache probably isn't worth much anymore...
60     # https://github.com/qutebrowser/qutebrowser/issues/121
61 
62     def __init__(self, parent=None):
63         self._painter = None
64         self._opt = None
65         self._doc = None
66         self._style = None
67         super().__init__(parent)
68 
69     def _draw_background(self):
70         """Draw the background of an ItemViewItem."""
71         self._style.drawPrimitive(self._style.PE_PanelItemViewItem, self._opt,
72                                   self._painter, self._opt.widget)
73 
74     def _draw_icon(self):
75         """Draw the icon of an ItemViewItem."""
76         icon_rect = self._style.subElementRect(
77             self._style.SE_ItemViewItemDecoration, self._opt, self._opt.widget)
78         if not icon_rect.isValid():
79             # The rect seems to be wrong in all kind of ways if no icon should
80             # be displayed.
81             return
82 
83         mode = QIcon.Normal
84         if not self._opt.state & QStyle.State_Enabled:
85             mode = QIcon.Disabled
86         elif self._opt.state & QStyle.State_Selected:
87             mode = QIcon.Selected
88         state = QIcon.On if self._opt.state & QStyle.State_Open else QIcon.Off
89         self._opt.icon.paint(self._painter, icon_rect,
90                              self._opt.decorationAlignment, mode, state)
91 
92     def _draw_text(self, index):
93         """Draw the text of an ItemViewItem.
94 
95         This is the main part where we differ from the original implementation
96         in Qt: We use a QTextDocument to draw text.
97 
98         Args:
99             index: The QModelIndex of the item to draw.
100         """
101         if not self._opt.text:
102             return
103 
104         text_rect_ = self._style.subElementRect(
105             self._style.SE_ItemViewItemText, self._opt, self._opt.widget)
106         qtutils.ensure_valid(text_rect_)
107         margin = self._style.pixelMetric(QStyle.PM_FocusFrameHMargin,
108                                          self._opt, self._opt.widget) + 1
109         # remove width padding
110         text_rect = text_rect_.adjusted(margin, 0, -margin, 0)
111         qtutils.ensure_valid(text_rect)
112         # move text upwards a bit
113         if index.parent().isValid():
114             text_rect.adjust(0, -1, 0, -1)
115         else:
116             text_rect.adjust(0, -2, 0, -2)
117         self._painter.save()
118         state = self._opt.state
119         if state & QStyle.State_Enabled and state & QStyle.State_Active:
120             cg = QPalette.Normal
121         elif state & QStyle.State_Enabled:
122             cg = QPalette.Inactive
123         else:
124             cg = QPalette.Disabled
125 
126         if state & QStyle.State_Selected:
127             self._painter.setPen(self._opt.palette.color(
128                 cg, QPalette.HighlightedText))
129             # This is a dirty fix for the text jumping by one pixel for
130             # whatever reason.
131             text_rect.adjust(0, -1, 0, 0)
132         else:
133             self._painter.setPen(self._opt.palette.color(cg, QPalette.Text))
134 
135         if state & QStyle.State_Editing:
136             self._painter.setPen(self._opt.palette.color(cg, QPalette.Text))
137             self._painter.drawRect(text_rect_.adjusted(0, 0, -1, -1))
138 
139         self._painter.translate(text_rect.left(), text_rect.top())
140         self._get_textdoc(index)
141         self._draw_textdoc(text_rect, index.column())
142         self._painter.restore()
143 
144     def _draw_textdoc(self, rect, col):
145         """Draw the QTextDocument of an item.
146 
147         Args:
148             rect: The QRect to clip the drawing to.
149         """
150         # We can't use drawContents because then the color would be ignored.
151         clip = QRectF(0, 0, rect.width(), rect.height())
152         self._painter.save()
153 
154         if self._opt.state & QStyle.State_Selected:
155             color = config.val.colors.completion.item.selected.fg
156         elif not self._opt.state & QStyle.State_Enabled:
157             color = config.val.colors.completion.category.fg
158         else:
159             colors = config.val.colors.completion.fg
160             # if multiple colors are set, use different colors per column
161             color = colors[col % len(colors)]
162         self._painter.setPen(color)
163 
164         ctx = QAbstractTextDocumentLayout.PaintContext()
165         ctx.palette.setColor(QPalette.Text, self._painter.pen().color())
166         if clip.isValid():
167             self._painter.setClipRect(clip)
168             ctx.clip = clip
169         self._doc.documentLayout().draw(self._painter, ctx)
170         self._painter.restore()
171 
172     def _get_textdoc(self, index):
173         """Create the QTextDocument of an item.
174 
175         Args:
176             index: The QModelIndex of the item to draw.
177         """
178         # FIXME we probably should do eliding here. See
179         # qcommonstyle.cpp:viewItemDrawText
180         # https://github.com/qutebrowser/qutebrowser/issues/118
181         text_option = QTextOption()
182         if self._opt.features & QStyleOptionViewItem.WrapText:
183             text_option.setWrapMode(QTextOption.WordWrap)
184         else:
185             text_option.setWrapMode(QTextOption.ManualWrap)
186         text_option.setTextDirection(self._opt.direction)
187         text_option.setAlignment(QStyle.visualAlignment(
188             self._opt.direction, self._opt.displayAlignment))
189 
190         if self._doc is not None:
191             self._doc.deleteLater()
192         self._doc = QTextDocument(self)
193         self._doc.setDefaultFont(self._opt.font)
194         self._doc.setDefaultTextOption(text_option)
195         self._doc.setDocumentMargin(2)
196 
197         assert _cached_stylesheet is not None
198         self._doc.setDefaultStyleSheet(_cached_stylesheet)
199 
200         if index.parent().isValid():
201             view = self.parent()
202             pattern = view.pattern
203             columns_to_filter = index.model().columns_to_filter(index)
204             if index.column() in columns_to_filter and pattern:
205                 repl = r'<span class="highlight">\g<0></span>'
206                 text = re.sub(re.escape(pattern).replace(r'\ ', r'|'),
207                               repl, html.escape(self._opt.text),
208                               flags=re.IGNORECASE)
209                 self._doc.setHtml(text)
210             else:
211                 self._doc.setPlainText(self._opt.text)
212         else:
213             self._doc.setHtml(
214                 '<span style="font: {};">{}</span>'.format(
215                     html.escape(config.val.fonts.completion.category),
216                     html.escape(self._opt.text)))
217 
218     def _draw_focus_rect(self):
219         """Draw the focus rectangle of an ItemViewItem."""
220         state = self._opt.state
221         if not state & QStyle.State_HasFocus:
222             return
223         o = self._opt
224         o.rect = self._style.subElementRect(
225             self._style.SE_ItemViewItemFocusRect, self._opt, self._opt.widget)
226         o.state |= QStyle.State_KeyboardFocusChange | QStyle.State_Item
227         qtutils.ensure_valid(o.rect)
228         if state & QStyle.State_Enabled:
229             cg = QPalette.Normal
230         else:
231             cg = QPalette.Disabled
232         if state & QStyle.State_Selected:
233             role = QPalette.Highlight
234         else:
235             role = QPalette.Window
236         o.backgroundColor = self._opt.palette.color(cg, role)
237         self._style.drawPrimitive(QStyle.PE_FrameFocusRect, o, self._painter,
238                                   self._opt.widget)
239 
240     def sizeHint(self, option, index):
241         """Override sizeHint of QStyledItemDelegate.
242 
243         Return the cell size based on the QTextDocument size, but might not
244         work correctly yet.
245 
246         Args:
247             option: const QStyleOptionViewItem & option
248             index: const QModelIndex & index
249 
250         Return:
251             A QSize with the recommended size.
252         """
253         value = index.data(Qt.SizeHintRole)
254         if value is not None:
255             return value
256         self._opt = QStyleOptionViewItem(option)
257         self.initStyleOption(self._opt, index)
258         self._style = self._opt.widget.style()
259         self._get_textdoc(index)
260         docsize = self._doc.size().toSize()
261         size = self._style.sizeFromContents(QStyle.CT_ItemViewItem, self._opt,
262                                             docsize, self._opt.widget)
263         qtutils.ensure_valid(size)
264         return size + QSize(10, 3)
265 
266     def paint(self, painter, option, index):
267         """Override the QStyledItemDelegate paint function.
268 
269         Args:
270             painter: QPainter * painter
271             option: const QStyleOptionViewItem & option
272             index: const QModelIndex & index
273         """
274         self._painter = painter
275         self._painter.save()
276         self._opt = QStyleOptionViewItem(option)
277         self.initStyleOption(self._opt, index)
278         self._style = self._opt.widget.style()
279 
280         self._draw_background()
281         self._draw_icon()
282         self._draw_text(index)
283         self._draw_focus_rect()
284 
285         self._painter.restore()
286 
287 
288 @config.change_filter('colors.completion.match.fg', function=True)
289 def _update_stylesheet():
290     """Update the cached stylesheet."""
291     stylesheet = """
292         .highlight {
293             color: {{ conf.colors.completion.match.fg }};
294         }
295     """
296     with jinja.environment.no_autoescape():
297         template = jinja.environment.from_string(stylesheet)
298 
299     global _cached_stylesheet
300     _cached_stylesheet = template.render(conf=config.val)
301 
302 
303 def init():
304     """Initialize the cached stylesheet."""
305     _update_stylesheet()
306     config.instance.changed.connect(_update_stylesheet)
307
```
--- 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/completiondelegate.py b/qutebrowser/completion/completiondelegate.py
--- a/qutebrowser/completion/completiondelegate.py
+++ b/qutebrowser/completion/completiondelegate.py
@@ -203,9 +203,9 @@
             columns_to_filter = index.model().columns_to_filter(index)
             if index.column() in columns_to_filter and pattern:
                 repl = r'<span class="highlight">\g<0></span>'
-                text = re.sub(re.escape(pattern).replace(r'\ ', r'|'),
-                              repl, html.escape(self._opt.text),
-                              flags=re.IGNORECASE)
+                pat = html.escape(re.escape(pattern)).replace(r'\ ', r'|')
+                txt = html.escape(self._opt.text)
+                text = re.sub(pat, repl, txt, flags=re.IGNORECASE)
                 self._doc.setHtml(text)
             else:
                 self._doc.setPlainText(self._opt.text)

{"golden_diff": "diff --git a/qutebrowser/completion/completiondelegate.py b/qutebrowser/completion/completiondelegate.py\n--- a/qutebrowser/completion/completiondelegate.py\n+++ b/qutebrowser/completion/completiondelegate.py\n@@ -203,9 +203,9 @@\n             columns_to_filter = index.model().columns_to_filter(index)\n             if index.column() in columns_to_filter and pattern:\n                 repl = r'<span class=\"highlight\">\\g<0></span>'\n-                text = re.sub(re.escape(pattern).replace(r'\\ ', r'|'),\n-                              repl, html.escape(self._opt.text),\n-                              flags=re.IGNORECASE)\n+                pat = html.escape(re.escape(pattern)).replace(r'\\ ', r'|')\n+                txt = html.escape(self._opt.text)\n+                text = re.sub(pat, repl, txt, flags=re.IGNORECASE)\n                 self._doc.setHtml(text)\n             else:\n                 self._doc.setPlainText(self._opt.text)\n", "issue": "Completing URL with '&' shows '&amp;'\nConsider this URL: https://wiki.archlinux.org/api.php?action=query&pageids=12345\r\n\r\nAfter writing `action=query` in the `:open` prompt, it is highlighted correctly. After adding `&` (i.e. the filter is `action=query&`), the URL is changed to `https://wiki.archlinux.org/api.php?action=query&amp;pageids=12345` in the completer and the pattern is still highlighted. After adding anything what follows in the URL, e.g. `action=query&pageids`, the URL is changed back to the original and nothing is highlighted, although the URL still matches the filter as expected.\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\"\"\"Completion item delegate for CompletionView.\n\nWe use this to be able to highlight parts of the text.\n\"\"\"\n\nimport re\nimport html\n\nfrom PyQt5.QtWidgets import QStyle, QStyleOptionViewItem, QStyledItemDelegate\nfrom PyQt5.QtCore import QRectF, QSize, Qt\nfrom PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption,\n                         QAbstractTextDocumentLayout)\n\nfrom qutebrowser.config import config\nfrom qutebrowser.utils import qtutils, jinja\n\n\n_cached_stylesheet = None\n\n\nclass CompletionItemDelegate(QStyledItemDelegate):\n\n    \"\"\"Delegate used by CompletionView to draw individual items.\n\n    Mainly a cleaned up port of Qt's way to draw a TreeView item, except it\n    uses a QTextDocument to draw the text and add marking.\n\n    Original implementation:\n        qt/src/gui/styles/qcommonstyle.cpp:drawControl:2153\n\n    Attributes:\n        _opt: The QStyleOptionViewItem which is used.\n        _style: The style to be used.\n        _painter: The QPainter to be used.\n        _doc: The QTextDocument to be used.\n    \"\"\"\n\n    # FIXME this is horribly slow when resizing.\n    # We should probably cache something in _get_textdoc or so, but as soon as\n    # we implement eliding that cache probably isn't worth much anymore...\n    # https://github.com/qutebrowser/qutebrowser/issues/121\n\n    def __init__(self, parent=None):\n        self._painter = None\n        self._opt = None\n        self._doc = None\n        self._style = None\n        super().__init__(parent)\n\n    def _draw_background(self):\n        \"\"\"Draw the background of an ItemViewItem.\"\"\"\n        self._style.drawPrimitive(self._style.PE_PanelItemViewItem, self._opt,\n                                  self._painter, self._opt.widget)\n\n    def _draw_icon(self):\n        \"\"\"Draw the icon of an ItemViewItem.\"\"\"\n        icon_rect = self._style.subElementRect(\n            self._style.SE_ItemViewItemDecoration, self._opt, self._opt.widget)\n        if not icon_rect.isValid():\n            # The rect seems to be wrong in all kind of ways if no icon should\n            # be displayed.\n            return\n\n        mode = QIcon.Normal\n        if not self._opt.state & QStyle.State_Enabled:\n            mode = QIcon.Disabled\n        elif self._opt.state & QStyle.State_Selected:\n            mode = QIcon.Selected\n        state = QIcon.On if self._opt.state & QStyle.State_Open else QIcon.Off\n        self._opt.icon.paint(self._painter, icon_rect,\n                             self._opt.decorationAlignment, mode, state)\n\n    def _draw_text(self, index):\n        \"\"\"Draw the text of an ItemViewItem.\n\n        This is the main part where we differ from the original implementation\n        in Qt: We use a QTextDocument to draw text.\n\n        Args:\n            index: The QModelIndex of the item to draw.\n        \"\"\"\n        if not self._opt.text:\n            return\n\n        text_rect_ = self._style.subElementRect(\n            self._style.SE_ItemViewItemText, self._opt, self._opt.widget)\n        qtutils.ensure_valid(text_rect_)\n        margin = self._style.pixelMetric(QStyle.PM_FocusFrameHMargin,\n                                         self._opt, self._opt.widget) + 1\n        # remove width padding\n        text_rect = text_rect_.adjusted(margin, 0, -margin, 0)\n        qtutils.ensure_valid(text_rect)\n        # move text upwards a bit\n        if index.parent().isValid():\n            text_rect.adjust(0, -1, 0, -1)\n        else:\n            text_rect.adjust(0, -2, 0, -2)\n        self._painter.save()\n        state = self._opt.state\n        if state & QStyle.State_Enabled and state & QStyle.State_Active:\n            cg = QPalette.Normal\n        elif state & QStyle.State_Enabled:\n            cg = QPalette.Inactive\n        else:\n            cg = QPalette.Disabled\n\n        if state & QStyle.State_Selected:\n            self._painter.setPen(self._opt.palette.color(\n                cg, QPalette.HighlightedText))\n            # This is a dirty fix for the text jumping by one pixel for\n            # whatever reason.\n            text_rect.adjust(0, -1, 0, 0)\n        else:\n            self._painter.setPen(self._opt.palette.color(cg, QPalette.Text))\n\n        if state & QStyle.State_Editing:\n            self._painter.setPen(self._opt.palette.color(cg, QPalette.Text))\n            self._painter.drawRect(text_rect_.adjusted(0, 0, -1, -1))\n\n        self._painter.translate(text_rect.left(), text_rect.top())\n        self._get_textdoc(index)\n        self._draw_textdoc(text_rect, index.column())\n        self._painter.restore()\n\n    def _draw_textdoc(self, rect, col):\n        \"\"\"Draw the QTextDocument of an item.\n\n        Args:\n            rect: The QRect to clip the drawing to.\n        \"\"\"\n        # We can't use drawContents because then the color would be ignored.\n        clip = QRectF(0, 0, rect.width(), rect.height())\n        self._painter.save()\n\n        if self._opt.state & QStyle.State_Selected:\n            color = config.val.colors.completion.item.selected.fg\n        elif not self._opt.state & QStyle.State_Enabled:\n            color = config.val.colors.completion.category.fg\n        else:\n            colors = config.val.colors.completion.fg\n            # if multiple colors are set, use different colors per column\n            color = colors[col % len(colors)]\n        self._painter.setPen(color)\n\n        ctx = QAbstractTextDocumentLayout.PaintContext()\n        ctx.palette.setColor(QPalette.Text, self._painter.pen().color())\n        if clip.isValid():\n            self._painter.setClipRect(clip)\n            ctx.clip = clip\n        self._doc.documentLayout().draw(self._painter, ctx)\n        self._painter.restore()\n\n    def _get_textdoc(self, index):\n        \"\"\"Create the QTextDocument of an item.\n\n        Args:\n            index: The QModelIndex of the item to draw.\n        \"\"\"\n        # FIXME we probably should do eliding here. See\n        # qcommonstyle.cpp:viewItemDrawText\n        # https://github.com/qutebrowser/qutebrowser/issues/118\n        text_option = QTextOption()\n        if self._opt.features & QStyleOptionViewItem.WrapText:\n            text_option.setWrapMode(QTextOption.WordWrap)\n        else:\n            text_option.setWrapMode(QTextOption.ManualWrap)\n        text_option.setTextDirection(self._opt.direction)\n        text_option.setAlignment(QStyle.visualAlignment(\n            self._opt.direction, self._opt.displayAlignment))\n\n        if self._doc is not None:\n            self._doc.deleteLater()\n        self._doc = QTextDocument(self)\n        self._doc.setDefaultFont(self._opt.font)\n        self._doc.setDefaultTextOption(text_option)\n        self._doc.setDocumentMargin(2)\n\n        assert _cached_stylesheet is not None\n        self._doc.setDefaultStyleSheet(_cached_stylesheet)\n\n        if index.parent().isValid():\n            view = self.parent()\n            pattern = view.pattern\n            columns_to_filter = index.model().columns_to_filter(index)\n            if index.column() in columns_to_filter and pattern:\n                repl = r'<span class=\"highlight\">\\g<0></span>'\n                text = re.sub(re.escape(pattern).replace(r'\\ ', r'|'),\n                              repl, html.escape(self._opt.text),\n                              flags=re.IGNORECASE)\n                self._doc.setHtml(text)\n            else:\n                self._doc.setPlainText(self._opt.text)\n        else:\n            self._doc.setHtml(\n                '<span style=\"font: {};\">{}</span>'.format(\n                    html.escape(config.val.fonts.completion.category),\n                    html.escape(self._opt.text)))\n\n    def _draw_focus_rect(self):\n        \"\"\"Draw the focus rectangle of an ItemViewItem.\"\"\"\n        state = self._opt.state\n        if not state & QStyle.State_HasFocus:\n            return\n        o = self._opt\n        o.rect = self._style.subElementRect(\n            self._style.SE_ItemViewItemFocusRect, self._opt, self._opt.widget)\n        o.state |= QStyle.State_KeyboardFocusChange | QStyle.State_Item\n        qtutils.ensure_valid(o.rect)\n        if state & QStyle.State_Enabled:\n            cg = QPalette.Normal\n        else:\n            cg = QPalette.Disabled\n        if state & QStyle.State_Selected:\n            role = QPalette.Highlight\n        else:\n            role = QPalette.Window\n        o.backgroundColor = self._opt.palette.color(cg, role)\n        self._style.drawPrimitive(QStyle.PE_FrameFocusRect, o, self._painter,\n                                  self._opt.widget)\n\n    def sizeHint(self, option, index):\n        \"\"\"Override sizeHint of QStyledItemDelegate.\n\n        Return the cell size based on the QTextDocument size, but might not\n        work correctly yet.\n\n        Args:\n            option: const QStyleOptionViewItem & option\n            index: const QModelIndex & index\n\n        Return:\n            A QSize with the recommended size.\n        \"\"\"\n        value = index.data(Qt.SizeHintRole)\n        if value is not None:\n            return value\n        self._opt = QStyleOptionViewItem(option)\n        self.initStyleOption(self._opt, index)\n        self._style = self._opt.widget.style()\n        self._get_textdoc(index)\n        docsize = self._doc.size().toSize()\n        size = self._style.sizeFromContents(QStyle.CT_ItemViewItem, self._opt,\n                                            docsize, self._opt.widget)\n        qtutils.ensure_valid(size)\n        return size + QSize(10, 3)\n\n    def paint(self, painter, option, index):\n        \"\"\"Override the QStyledItemDelegate paint function.\n\n        Args:\n            painter: QPainter * painter\n            option: const QStyleOptionViewItem & option\n            index: const QModelIndex & index\n        \"\"\"\n        self._painter = painter\n        self._painter.save()\n        self._opt = QStyleOptionViewItem(option)\n        self.initStyleOption(self._opt, index)\n        self._style = self._opt.widget.style()\n\n        self._draw_background()\n        self._draw_icon()\n        self._draw_text(index)\n        self._draw_focus_rect()\n\n        self._painter.restore()\n\n\n@config.change_filter('colors.completion.match.fg', function=True)\ndef _update_stylesheet():\n    \"\"\"Update the cached stylesheet.\"\"\"\n    stylesheet = \"\"\"\n        .highlight {\n            color: {{ conf.colors.completion.match.fg }};\n        }\n    \"\"\"\n    with jinja.environment.no_autoescape():\n        template = jinja.environment.from_string(stylesheet)\n\n    global _cached_stylesheet\n    _cached_stylesheet = template.render(conf=config.val)\n\n\ndef init():\n    \"\"\"Initialize the cached stylesheet.\"\"\"\n    _update_stylesheet()\n    config.instance.changed.connect(_update_stylesheet)\n", "path": "qutebrowser/completion/completiondelegate.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\"\"\"Completion item delegate for CompletionView.\n\nWe use this to be able to highlight parts of the text.\n\"\"\"\n\nimport re\nimport html\n\nfrom PyQt5.QtWidgets import QStyle, QStyleOptionViewItem, QStyledItemDelegate\nfrom PyQt5.QtCore import QRectF, QSize, Qt\nfrom PyQt5.QtGui import (QIcon, QPalette, QTextDocument, QTextOption,\n                         QAbstractTextDocumentLayout)\n\nfrom qutebrowser.config import config\nfrom qutebrowser.utils import qtutils, jinja\n\n\n_cached_stylesheet = None\n\n\nclass CompletionItemDelegate(QStyledItemDelegate):\n\n    \"\"\"Delegate used by CompletionView to draw individual items.\n\n    Mainly a cleaned up port of Qt's way to draw a TreeView item, except it\n    uses a QTextDocument to draw the text and add marking.\n\n    Original implementation:\n        qt/src/gui/styles/qcommonstyle.cpp:drawControl:2153\n\n    Attributes:\n        _opt: The QStyleOptionViewItem which is used.\n        _style: The style to be used.\n        _painter: The QPainter to be used.\n        _doc: The QTextDocument to be used.\n    \"\"\"\n\n    # FIXME this is horribly slow when resizing.\n    # We should probably cache something in _get_textdoc or so, but as soon as\n    # we implement eliding that cache probably isn't worth much anymore...\n    # https://github.com/qutebrowser/qutebrowser/issues/121\n\n    def __init__(self, parent=None):\n        self._painter = None\n        self._opt = None\n        self._doc = None\n        self._style = None\n        super().__init__(parent)\n\n    def _draw_background(self):\n        \"\"\"Draw the background of an ItemViewItem.\"\"\"\n        self._style.drawPrimitive(self._style.PE_PanelItemViewItem, self._opt,\n                                  self._painter, self._opt.widget)\n\n    def _draw_icon(self):\n        \"\"\"Draw the icon of an ItemViewItem.\"\"\"\n        icon_rect = self._style.subElementRect(\n            self._style.SE_ItemViewItemDecoration, self._opt, self._opt.widget)\n        if not icon_rect.isValid():\n            # The rect seems to be wrong in all kind of ways if no icon should\n            # be displayed.\n            return\n\n        mode = QIcon.Normal\n        if not self._opt.state & QStyle.State_Enabled:\n            mode = QIcon.Disabled\n        elif self._opt.state & QStyle.State_Selected:\n            mode = QIcon.Selected\n        state = QIcon.On if self._opt.state & QStyle.State_Open else QIcon.Off\n        self._opt.icon.paint(self._painter, icon_rect,\n                             self._opt.decorationAlignment, mode, state)\n\n    def _draw_text(self, index):\n        \"\"\"Draw the text of an ItemViewItem.\n\n        This is the main part where we differ from the original implementation\n        in Qt: We use a QTextDocument to draw text.\n\n        Args:\n            index: The QModelIndex of the item to draw.\n        \"\"\"\n        if not self._opt.text:\n            return\n\n        text_rect_ = self._style.subElementRect(\n            self._style.SE_ItemViewItemText, self._opt, self._opt.widget)\n        qtutils.ensure_valid(text_rect_)\n        margin = self._style.pixelMetric(QStyle.PM_FocusFrameHMargin,\n                                         self._opt, self._opt.widget) + 1\n        # remove width padding\n        text_rect = text_rect_.adjusted(margin, 0, -margin, 0)\n        qtutils.ensure_valid(text_rect)\n        # move text upwards a bit\n        if index.parent().isValid():\n            text_rect.adjust(0, -1, 0, -1)\n        else:\n            text_rect.adjust(0, -2, 0, -2)\n        self._painter.save()\n        state = self._opt.state\n        if state & QStyle.State_Enabled and state & QStyle.State_Active:\n            cg = QPalette.Normal\n        elif state & QStyle.State_Enabled:\n            cg = QPalette.Inactive\n        else:\n            cg = QPalette.Disabled\n\n        if state & QStyle.State_Selected:\n            self._painter.setPen(self._opt.palette.color(\n                cg, QPalette.HighlightedText))\n            # This is a dirty fix for the text jumping by one pixel for\n            # whatever reason.\n            text_rect.adjust(0, -1, 0, 0)\n        else:\n            self._painter.setPen(self._opt.palette.color(cg, QPalette.Text))\n\n        if state & QStyle.State_Editing:\n            self._painter.setPen(self._opt.palette.color(cg, QPalette.Text))\n            self._painter.drawRect(text_rect_.adjusted(0, 0, -1, -1))\n\n        self._painter.translate(text_rect.left(), text_rect.top())\n        self._get_textdoc(index)\n        self._draw_textdoc(text_rect, index.column())\n        self._painter.restore()\n\n    def _draw_textdoc(self, rect, col):\n        \"\"\"Draw the QTextDocument of an item.\n\n        Args:\n            rect: The QRect to clip the drawing to.\n        \"\"\"\n        # We can't use drawContents because then the color would be ignored.\n        clip = QRectF(0, 0, rect.width(), rect.height())\n        self._painter.save()\n\n        if self._opt.state & QStyle.State_Selected:\n            color = config.val.colors.completion.item.selected.fg\n        elif not self._opt.state & QStyle.State_Enabled:\n            color = config.val.colors.completion.category.fg\n        else:\n            colors = config.val.colors.completion.fg\n            # if multiple colors are set, use different colors per column\n            color = colors[col % len(colors)]\n        self._painter.setPen(color)\n\n        ctx = QAbstractTextDocumentLayout.PaintContext()\n        ctx.palette.setColor(QPalette.Text, self._painter.pen().color())\n        if clip.isValid():\n            self._painter.setClipRect(clip)\n            ctx.clip = clip\n        self._doc.documentLayout().draw(self._painter, ctx)\n        self._painter.restore()\n\n    def _get_textdoc(self, index):\n        \"\"\"Create the QTextDocument of an item.\n\n        Args:\n            index: The QModelIndex of the item to draw.\n        \"\"\"\n        # FIXME we probably should do eliding here. See\n        # qcommonstyle.cpp:viewItemDrawText\n        # https://github.com/qutebrowser/qutebrowser/issues/118\n        text_option = QTextOption()\n        if self._opt.features & QStyleOptionViewItem.WrapText:\n            text_option.setWrapMode(QTextOption.WordWrap)\n        else:\n            text_option.setWrapMode(QTextOption.ManualWrap)\n        text_option.setTextDirection(self._opt.direction)\n        text_option.setAlignment(QStyle.visualAlignment(\n            self._opt.direction, self._opt.displayAlignment))\n\n        if self._doc is not None:\n            self._doc.deleteLater()\n        self._doc = QTextDocument(self)\n        self._doc.setDefaultFont(self._opt.font)\n        self._doc.setDefaultTextOption(text_option)\n        self._doc.setDocumentMargin(2)\n\n        assert _cached_stylesheet is not None\n        self._doc.setDefaultStyleSheet(_cached_stylesheet)\n\n        if index.parent().isValid():\n            view = self.parent()\n            pattern = view.pattern\n            columns_to_filter = index.model().columns_to_filter(index)\n            if index.column() in columns_to_filter and pattern:\n                repl = r'<span class=\"highlight\">\\g<0></span>'\n                pat = html.escape(re.escape(pattern)).replace(r'\\ ', r'|')\n                txt = html.escape(self._opt.text)\n                text = re.sub(pat, repl, txt, flags=re.IGNORECASE)\n                self._doc.setHtml(text)\n            else:\n                self._doc.setPlainText(self._opt.text)\n        else:\n            self._doc.setHtml(\n                '<span style=\"font: {};\">{}</span>'.format(\n                    html.escape(config.val.fonts.completion.category),\n                    html.escape(self._opt.text)))\n\n    def _draw_focus_rect(self):\n        \"\"\"Draw the focus rectangle of an ItemViewItem.\"\"\"\n        state = self._opt.state\n        if not state & QStyle.State_HasFocus:\n            return\n        o = self._opt\n        o.rect = self._style.subElementRect(\n            self._style.SE_ItemViewItemFocusRect, self._opt, self._opt.widget)\n        o.state |= QStyle.State_KeyboardFocusChange | QStyle.State_Item\n        qtutils.ensure_valid(o.rect)\n        if state & QStyle.State_Enabled:\n            cg = QPalette.Normal\n        else:\n            cg = QPalette.Disabled\n        if state & QStyle.State_Selected:\n            role = QPalette.Highlight\n        else:\n            role = QPalette.Window\n        o.backgroundColor = self._opt.palette.color(cg, role)\n        self._style.drawPrimitive(QStyle.PE_FrameFocusRect, o, self._painter,\n                                  self._opt.widget)\n\n    def sizeHint(self, option, index):\n        \"\"\"Override sizeHint of QStyledItemDelegate.\n\n        Return the cell size based on the QTextDocument size, but might not\n        work correctly yet.\n\n        Args:\n            option: const QStyleOptionViewItem & option\n            index: const QModelIndex & index\n\n        Return:\n            A QSize with the recommended size.\n        \"\"\"\n        value = index.data(Qt.SizeHintRole)\n        if value is not None:\n            return value\n        self._opt = QStyleOptionViewItem(option)\n        self.initStyleOption(self._opt, index)\n        self._style = self._opt.widget.style()\n        self._get_textdoc(index)\n        docsize = self._doc.size().toSize()\n        size = self._style.sizeFromContents(QStyle.CT_ItemViewItem, self._opt,\n                                            docsize, self._opt.widget)\n        qtutils.ensure_valid(size)\n        return size + QSize(10, 3)\n\n    def paint(self, painter, option, index):\n        \"\"\"Override the QStyledItemDelegate paint function.\n\n        Args:\n            painter: QPainter * painter\n            option: const QStyleOptionViewItem & option\n            index: const QModelIndex & index\n        \"\"\"\n        self._painter = painter\n        self._painter.save()\n        self._opt = QStyleOptionViewItem(option)\n        self.initStyleOption(self._opt, index)\n        self._style = self._opt.widget.style()\n\n        self._draw_background()\n        self._draw_icon()\n        self._draw_text(index)\n        self._draw_focus_rect()\n\n        self._painter.restore()\n\n\n@config.change_filter('colors.completion.match.fg', function=True)\ndef _update_stylesheet():\n    \"\"\"Update the cached stylesheet.\"\"\"\n    stylesheet = \"\"\"\n        .highlight {\n            color: {{ conf.colors.completion.match.fg }};\n        }\n    \"\"\"\n    with jinja.environment.no_autoescape():\n        template = jinja.environment.from_string(stylesheet)\n\n    global _cached_stylesheet\n    _cached_stylesheet = template.render(conf=config.val)\n\n\ndef init():\n    \"\"\"Initialize the cached stylesheet.\"\"\"\n    _update_stylesheet()\n    config.instance.changed.connect(_update_stylesheet)\n", "path": "qutebrowser/completion/completiondelegate.py"}]}