Simplify text marking in completion.
Also improves performance, see #190.
This commit is contained in:
parent
1917911dd8
commit
0a5cee6ea2
@ -29,8 +29,7 @@ from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
|||||||
from qutebrowser.utils import usertypes, qtutils
|
from qutebrowser.utils import usertypes, qtutils
|
||||||
|
|
||||||
|
|
||||||
Role = usertypes.enum('Role', ['marks', 'sort'], start=Qt.UserRole,
|
Role = usertypes.enum('Role', ['sort'], start=Qt.UserRole, is_int=True)
|
||||||
is_int=True)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseCompletionModel(QStandardItemModel):
|
class BaseCompletionModel(QStandardItemModel):
|
||||||
@ -45,44 +44,6 @@ class BaseCompletionModel(QStandardItemModel):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setColumnCount(3)
|
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):
|
def new_category(self, name, sort=None):
|
||||||
"""Add a new category to the model.
|
"""Add a new category to the model.
|
||||||
|
|
||||||
|
@ -100,20 +100,6 @@ class CompletionFilterModel(QSortFilterProxyModel):
|
|||||||
return index
|
return index
|
||||||
return QModelIndex()
|
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):
|
def setSourceModel(self, model):
|
||||||
"""Override QSortFilterProxyModel's setSourceModel to clear pattern."""
|
"""Override QSortFilterProxyModel's setSourceModel to clear pattern."""
|
||||||
log.completion.debug("Setting source model: {}".format(model))
|
log.completion.debug("Setting source model: {}".format(model))
|
||||||
|
@ -253,6 +253,5 @@ class Completer(QObject):
|
|||||||
completion.hide()
|
completion.hide()
|
||||||
return
|
return
|
||||||
|
|
||||||
self._model().mark_all_items(pattern)
|
|
||||||
if completion.enabled:
|
if completion.enabled:
|
||||||
completion.show()
|
completion.show()
|
||||||
|
@ -39,8 +39,6 @@ class CompletionView(QTreeView):
|
|||||||
Based on QTreeView but heavily customized so root elements show as category
|
Based on QTreeView but heavily customized so root elements show as category
|
||||||
headers, and children show as flat list.
|
headers, and children show as flat list.
|
||||||
|
|
||||||
Highlights completions based on marks in the Role.marks data.
|
|
||||||
|
|
||||||
Class attributes:
|
Class attributes:
|
||||||
COLUMN_WIDTHS: A list of column widths, in percent.
|
COLUMN_WIDTHS: A list of column widths, in percent.
|
||||||
|
|
||||||
|
@ -184,10 +184,6 @@ class CompletionItemDelegate(QStyledItemDelegate):
|
|||||||
self._opt.direction, self._opt.displayAlignment))
|
self._opt.direction, self._opt.displayAlignment))
|
||||||
|
|
||||||
self._doc = QTextDocument(self)
|
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.setDefaultFont(self._opt.font)
|
||||||
self._doc.setDefaultTextOption(text_option)
|
self._doc.setDefaultTextOption(text_option)
|
||||||
self._doc.setDefaultStyleSheet(style.get_stylesheet("""
|
self._doc.setDefaultStyleSheet(style.get_stylesheet("""
|
||||||
@ -197,21 +193,17 @@ class CompletionItemDelegate(QStyledItemDelegate):
|
|||||||
"""))
|
"""))
|
||||||
self._doc.setDocumentMargin(2)
|
self._doc.setDocumentMargin(2)
|
||||||
|
|
||||||
if index.column() == 0 and index.model().pattern:
|
if index.parent().isValid():
|
||||||
# We take a shortcut here by not checking anything if the models
|
pattern = index.model().pattern
|
||||||
# pattern is empty. This is required because the marks data is
|
if index.column() == 0 and pattern:
|
||||||
# invalid in that case (for performance reasons).
|
text = self._opt.text.replace(
|
||||||
marks = index.data(basecompletion.Role.marks)
|
pattern,
|
||||||
if marks is None:
|
'<span class="highlight">{}</span>'.format(pattern))
|
||||||
return
|
self._doc.setHtml(text)
|
||||||
for mark in marks:
|
else:
|
||||||
cur = QTextCursor(self._doc)
|
self._doc.setPlainText(self._opt.text)
|
||||||
cur.setPosition(mark[0])
|
else:
|
||||||
cur.setPosition(mark[1], QTextCursor.KeepAnchor)
|
self._doc.setHtml('<b>{}</b>'.format(html.escape(self._opt.text)))
|
||||||
txt = cur.selectedText()
|
|
||||||
cur.removeSelectedText()
|
|
||||||
cur.insertHtml('<span class="highlight">{}</span>'.format(
|
|
||||||
html.escape(txt)))
|
|
||||||
|
|
||||||
def _draw_focus_rect(self):
|
def _draw_focus_rect(self):
|
||||||
"""Draw the focus rectangle of an ItemViewItem."""
|
"""Draw the focus rectangle of an ItemViewItem."""
|
||||||
|
Loading…
Reference in New Issue
Block a user