mirror of
https://github.com/ankitects/anki.git
synced 2025-12-10 21:36:55 -05:00
do tag rename and tag clearing in background; move logic to tags.py
Because the logic is in rename_tag() now, it means we create a checkpoint even if the tag is orphaned. This is because currently checkpointing is a GUI responsibility. In the future we need to introduce multi-level undo, and should move responsibility for managing it to the backend.
This commit is contained in:
parent
35ce1b0d29
commit
f3fa9daae2
3 changed files with 37 additions and 18 deletions
|
|
@ -13,7 +13,7 @@ from __future__ import annotations
|
|||
|
||||
import pprint
|
||||
import re
|
||||
from typing import Collection, List, Optional, Tuple
|
||||
from typing import Collection, List, Optional, Sequence, Tuple
|
||||
|
||||
import anki # pylint: disable=unused-import
|
||||
from anki.utils import ids2str
|
||||
|
|
@ -92,7 +92,7 @@ class TagManager:
|
|||
return self.col.backend.add_note_tags(nids=nids, tags=tags)
|
||||
|
||||
def bulk_update(
|
||||
self, nids: List[int], tags: str, replacement: str, regex: bool
|
||||
self, nids: Sequence[int], tags: str, replacement: str, regex: bool
|
||||
) -> int:
|
||||
"""Replace space-separated tags, returning changed count.
|
||||
Tags replaced with an empty string will be removed."""
|
||||
|
|
@ -100,6 +100,15 @@ class TagManager:
|
|||
nids=nids, tags=tags, replacement=replacement, regex=regex
|
||||
)
|
||||
|
||||
def rename_tag(self, old: str, new: str) -> int:
|
||||
"Rename provided tag, returning number of changed notes."
|
||||
escaped_name = re.sub(r"[*_\\]", r"\\\g<0>", old)
|
||||
escaped_name = '"{}"'.format(escaped_name.replace('"', '\\"'))
|
||||
nids = self.col.find_notes("tag:" + escaped_name)
|
||||
if not nids:
|
||||
return 0
|
||||
return self.col.tags.bulk_update(nids, old, new, False)
|
||||
|
||||
# legacy routines
|
||||
|
||||
def bulkAdd(self, ids: List[int], tags: str, add: bool = True) -> None:
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from __future__ import annotations
|
|||
import html
|
||||
import re
|
||||
import time
|
||||
from concurrent.futures import Future
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from operator import itemgetter
|
||||
|
|
@ -1649,8 +1650,11 @@ where id in %s"""
|
|||
self.editor.saveNow(self._clearUnusedTags)
|
||||
|
||||
def _clearUnusedTags(self):
|
||||
self.col.tags.registerNotes()
|
||||
self.on_tag_list_update()
|
||||
def on_done(fut: Future):
|
||||
fut.result()
|
||||
self.on_tag_list_update()
|
||||
|
||||
self.mw.taskman.run_in_background(self.col.tags.registerNotes, on_done)
|
||||
|
||||
# Suspending
|
||||
######################################################################
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from concurrent.futures import Future
|
||||
from enum import Enum
|
||||
|
||||
import aqt
|
||||
|
|
@ -92,7 +93,7 @@ class NewSidebarTreeView(SidebarTreeViewBase):
|
|||
a.triggered.connect(lambda _, func=act_func: func(item)) # type: ignore
|
||||
m.exec_(QCursor.pos())
|
||||
|
||||
def rename_deck(self, item: aqt.browser.SidebarItem) -> None:
|
||||
def rename_deck(self, item: "aqt.browser.SidebarItem") -> None:
|
||||
deck = self.mw.col.decks.get(item.id)
|
||||
old_name = deck["name"]
|
||||
new_name = getOnlyText(tr(TR.DECKS_NEW_DECK_NAME), default=old_name)
|
||||
|
|
@ -107,24 +108,29 @@ class NewSidebarTreeView(SidebarTreeViewBase):
|
|||
self.browser.maybeRefreshSidebar()
|
||||
self.mw.deckBrowser.refresh()
|
||||
|
||||
def rename_tag(self, item: aqt.browser.SidebarItem) -> None:
|
||||
def rename_tag(self, item: "aqt.browser.SidebarItem") -> None:
|
||||
self.browser.editor.saveNow(lambda: self._rename_tag(item))
|
||||
|
||||
def _rename_tag(self, item: aqt.browser.SidebarItem) -> None:
|
||||
def _rename_tag(self, item: "aqt.browser.SidebarItem") -> None:
|
||||
old_name = item.name
|
||||
escaped_name = re.sub(r"[*_\\]", r"\\\g<0>", old_name)
|
||||
escaped_name = '"{}"'.format(escaped_name.replace('"', '\\"'))
|
||||
nids = self.col.find_notes("tag:" + escaped_name)
|
||||
if len(nids) == 0:
|
||||
showInfo(tr(TR.BROWSING_TAG_RENAME_WARNING_EMPTY))
|
||||
return
|
||||
new_name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=old_name)
|
||||
if new_name == old_name or not new_name:
|
||||
return
|
||||
|
||||
def do_rename():
|
||||
return self.col.tags.rename_tag(old_name, new_name)
|
||||
|
||||
def on_done(fut: Future):
|
||||
self.mw.requireReset(reason=ResetReason.BrowserAddTags, context=self)
|
||||
self.browser.model.endReset()
|
||||
|
||||
count = fut.result()
|
||||
if not count:
|
||||
showInfo(tr(TR.BROWSING_TAG_RENAME_WARNING_EMPTY))
|
||||
return
|
||||
|
||||
self.browser.clearUnusedTags()
|
||||
|
||||
self.mw.checkpoint(tr(TR.ACTIONS_RENAME_TAG))
|
||||
self.browser.model.beginReset()
|
||||
self.col.tags.bulk_update(list(nids), old_name, new_name, False)
|
||||
self.browser.model.endReset()
|
||||
self.browser.clearUnusedTags()
|
||||
self.mw.requireReset(reason=ResetReason.BrowserAddTags, context=self)
|
||||
self.browser.maybeRefreshSidebar()
|
||||
self.mw.taskman.run_in_background(do_rename, on_done)
|
||||
|
|
|
|||
Loading…
Reference in a new issue