Skip to content

Commit 912663f

Browse files
authored
Perf: Use backend's complete_tag() for tag autocomplete (#4626)
The tag completer was loading all tags into a QStringListModel upfront and relying on Qt's MatchContains to filter them on every keystroke. With large collections, this caused lags on keypress. Instead, use the Rust backend's complete_tag() in splitPath() to fetch a limited set of pre-filtered matches on each keystroke, updating the model dynamically. This is the same call already used by the Svelte tag editor in the Note Editor, which displays completions near-instantaneously. Fixes #3217 ⚠️ Code generated by Claude Sonnet 4.6 Manually tested and confirmed to be working as intended.
1 parent 81eefc5 commit 912663f

File tree

1 file changed

+12
-7
lines changed

1 file changed

+12
-7
lines changed

qt/aqt/tagedit.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
from __future__ import annotations
55

66
import re
7-
from collections.abc import Iterable
7+
from typing import cast
88

99
from anki.collection import Collection
1010
from aqt import gui_hooks
1111
from aqt.qt import *
1212
from aqt.qt import sip
1313

14+
TAG_COMPLETIONS_LIMIT = 500
15+
1416

1517
class TagEdit(QLineEdit):
1618
_completer: QCompleter | TagCompleter
@@ -29,18 +31,16 @@ def __init__(self, parent: QWidget, type: int = 0) -> None:
2931
self._completer = QCompleter(self.model, parent)
3032
self._completer.setCompletionMode(QCompleter.CompletionMode.PopupCompletion)
3133
self._completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
32-
self._completer.setFilterMode(Qt.MatchFlag.MatchContains)
3334
self.setCompleter(self._completer)
3435

3536
def setCol(self, col: Collection) -> None:
3637
"Set the current col, updating list of available tags."
3738
self.col = col
38-
l: Iterable[str]
3939
if self.type == 0:
40-
l = self.col.tags.all()
40+
pass
4141
else:
42-
l = (d.name for d in self.col.decks.all_names_and_ids())
43-
self.model.setStringList(l)
42+
l = list(d.name for d in self.col.decks.all_names_and_ids())
43+
self.model.setStringList(l)
4444

4545
def focusInEvent(self, evt: QFocusEvent | None) -> None:
4646
QLineEdit.focusInEvent(self, evt)
@@ -137,7 +137,12 @@ def splitPath(self, tags: str | None) -> list[str]:
137137
self.cursor = len(self.tags) - 1
138138
else:
139139
self.cursor = stripped_tags.count(" ", 0, p)
140-
return [self.tags[self.cursor]]
140+
current_tag = self.tags[self.cursor]
141+
matches = self.edit.col._backend.complete_tag(
142+
input=current_tag, match_limit=TAG_COMPLETIONS_LIMIT
143+
)
144+
cast(QStringListModel, self.model()).setStringList(list(matches))
145+
return [""]
141146

142147
def pathFromIndex(self, idx: QModelIndex) -> str:
143148
if self.cursor is None:

0 commit comments

Comments
 (0)