Simplify text marking in completion.

Also improves performance, see #190.
This commit is contained in:
Florian Bruhin 2014-10-20 07:43:07 +02:00
parent 1917911dd8
commit 0a5cee6ea2
5 changed files with 12 additions and 76 deletions

View File

@ -29,8 +29,7 @@ from PyQt5.QtGui import QStandardItemModel, QStandardItem
from qutebrowser.utils import usertypes, qtutils
Role = usertypes.enum('Role', ['marks', 'sort'], start=Qt.UserRole,
is_int=True)
Role = usertypes.enum('Role', ['sort'], start=Qt.UserRole, is_int=True)
class BaseCompletionModel(QStandardItemModel):
@ -45,44 +44,6 @@ class BaseCompletionModel(QStandardItemModel):
super().__init__(parent)
self.setColumnCount(3)
def _get_marks(self, needle, haystack):
"""Return the marks for needle in haystack.
Args:
needle: The substring which should match.
haystack: The string where the matches should be in.
Return:
A list of (startidx, endidx) tuples.
"""
pos1 = pos2 = 0
marks = []
if not needle:
return marks
needle = needle.casefold()
haystack = haystack.casefold()
while True:
pos1 = haystack.find(needle, pos2)
if pos1 == -1:
break
pos2 = pos1 + len(needle)
marks.append((pos1, pos2))
return marks
def mark_item(self, index, needle):
"""Mark a string in the givem item.
Args:
index: A QModelIndex of the item to mark.
needle: The string to mark.
"""
qtutils.ensure_valid(index)
haystack = self.data(index)
marks = self._get_marks(needle, haystack)
ok = self.setData(index, marks, Role.marks)
if not ok:
raise ValueError("Error while setting data!")
def new_category(self, name, sort=None):
"""Add a new category to the model.

View File

@ -100,20 +100,6 @@ class CompletionFilterModel(QSortFilterProxyModel):
return index
return QModelIndex()
def mark_all_items(self, text):
"""Mark the given text in all visible items."""
if not text:
return
for i in range(self.rowCount()):
cat = self.index(i, 0)
qtutils.ensure_valid(cat)
for k in range(self.rowCount(cat)):
index = self.index(k, 0, cat)
qtutils.ensure_valid(index)
index = self.mapToSource(index)
qtutils.ensure_valid(index)
self.srcmodel.mark_item(index, text)
def setSourceModel(self, model):
"""Override QSortFilterProxyModel's setSourceModel to clear pattern."""
log.completion.debug("Setting source model: {}".format(model))

View File

@ -253,6 +253,5 @@ class Completer(QObject):
completion.hide()
return
self._model().mark_all_items(pattern)
if completion.enabled:
completion.show()

View File

@ -39,8 +39,6 @@ class CompletionView(QTreeView):
Based on QTreeView but heavily customized so root elements show as category
headers, and children show as flat list.
Highlights completions based on marks in the Role.marks data.
Class attributes:
COLUMN_WIDTHS: A list of column widths, in percent.

View File

@ -184,10 +184,6 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._opt.direction, self._opt.displayAlignment))
self._doc = QTextDocument(self)
if index.parent().isValid():
self._doc.setPlainText(self._opt.text)
else:
self._doc.setHtml('<b>{}</b>'.format(html.escape(self._opt.text)))
self._doc.setDefaultFont(self._opt.font)
self._doc.setDefaultTextOption(text_option)
self._doc.setDefaultStyleSheet(style.get_stylesheet("""
@ -197,21 +193,17 @@ class CompletionItemDelegate(QStyledItemDelegate):
"""))
self._doc.setDocumentMargin(2)
if index.column() == 0 and index.model().pattern:
# We take a shortcut here by not checking anything if the models
# pattern is empty. This is required because the marks data is
# invalid in that case (for performance reasons).
marks = index.data(basecompletion.Role.marks)
if marks is None:
return
for mark in marks:
cur = QTextCursor(self._doc)
cur.setPosition(mark[0])
cur.setPosition(mark[1], QTextCursor.KeepAnchor)
txt = cur.selectedText()
cur.removeSelectedText()
cur.insertHtml('<span class="highlight">{}</span>'.format(
html.escape(txt)))
if index.parent().isValid():
pattern = index.model().pattern
if index.column() == 0 and pattern:
text = self._opt.text.replace(
pattern,
'<span class="highlight">{}</span>'.format(pattern))
self._doc.setHtml(text)
else:
self._doc.setPlainText(self._opt.text)
else:
self._doc.setHtml('<b>{}</b>'.format(html.escape(self._opt.text)))
def _draw_focus_rect(self):
"""Draw the focus rectangle of an ItemViewItem."""