diff --git a/qutebrowser/completion/completiondelegate.py b/qutebrowser/completion/completiondelegate.py
index 076b99bed..bc856d1a6 100644
--- a/qutebrowser/completion/completiondelegate.py
+++ b/qutebrowser/completion/completiondelegate.py
@@ -202,11 +202,16 @@ class CompletionItemDelegate(QStyledItemDelegate):
pattern = view.pattern
columns_to_filter = index.model().columns_to_filter(index)
if index.column() in columns_to_filter and pattern:
- repl = r'\g<0>'
- pat = html.escape(re.escape(pattern), quote=False).replace(
- r'\ ', r'|')
- txt = html.escape(self._opt.text, quote=False)
- text = re.sub(pat, repl, txt, flags=re.IGNORECASE)
+ pat = '({})'.format(re.escape(pattern).replace(r'\ ', r'|'))
+ parts = re.split(pat, self._opt.text, flags=re.IGNORECASE)
+ fmt = '{}'
+ escape = lambda s: html.escape(s, quote=False)
+ highlight = lambda s: fmt.format(escape(s))
+ # matches are at every odd index
+ text = ''.join([
+ highlight(s) if i % 2 == 1 else escape(s)
+ for i, s in enumerate(parts)
+ ])
self._doc.setHtml(text)
else:
self._doc.setPlainText(self._opt.text)
diff --git a/tests/unit/completion/test_completiondelegate.py b/tests/unit/completion/test_completiondelegate.py
index 9d22002ee..2118a4528 100644
--- a/tests/unit/completion/test_completiondelegate.py
+++ b/tests/unit/completion/test_completiondelegate.py
@@ -90,6 +90,7 @@ def delegate(mock_style_option, mock_text_document, config_stub, mocker, view):
# https://github.com/qutebrowser/qutebrowser/issues/4199
('foo', "'foo'", "'{foo}'"),
('x', "'x'", "'{x}'"),
+ ('lt', "