From 102c6b99dd7c8380a0681ef3fe67bd645fae0d15 Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Sat, 15 Sep 2018 14:06:28 -0400 Subject: [PATCH] Don't highlight html escapes in completion. Resolves #4199. To avoid accidentally highlighting characters that were introduced by html escaping the text before feeding it to setHtml, we can't just escape the whole string before adding the highlighting. Instead, we need to break the string up on the pattern, format and escape the individual parts, then join them back together. re.escape includes empty strings if there is a match at the start/end, which ensures that matches always land on odd indices: https://docs.python.org/3/library/re.html#re.split > If there are capturing groups in the separator and it matches at the > start of the string, the result will start with an empty string. The > same holds for the end of the string --- qutebrowser/completion/completiondelegate.py | 15 ++++++++++----- tests/unit/completion/test_completiondelegate.py | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) 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', "