mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00

- Introduced a new transact() method that wraps the return value in a separate struct that describes the changes that were made. - Changes are now gathered from the undo log, so we don't need to guess at what was changed - eg if update_note() is called with identical note contents, no changes are returned. Card changes will only be set if cards were actually generated by the update_note() call, and tag will only be set if a new tag was added. - mw.perform_op() has been updated to expect the op to return the changes, or a structure with the changes in it, and it will use them to fire the change hook, instead of fetching the changes from undo_status(), so there is no risk of race conditions. - the various calls to mw.perform_op() have been split into separate files like card_ops.py. Aside from making the code cleaner, this works around a rather annoying issue with mypy. Because we run it with no_strict_optional, mypy is happy to accept an operation that returns None, despite the type signature saying it requires changes to be returned. Turning no_strict_optional on for the whole codebase is not practical at the moment, but we can enable it for individual files. Still todo: - The cursor keeps moving back to the start of a field when typing - we need to ignore the refresh hook when we are the initiator. - The busy cursor icon should probably be delayed a few hundreds ms. - Still need to think about a nicer way of handling saveNow() - op_made_changes(), op_affects_study_queue() might be better embedded as properties in the object instead
66 lines
1.8 KiB
Python
66 lines
1.8 KiB
Python
# Copyright: Ankitects Pty Ltd and contributors
|
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Optional, Set
|
|
|
|
from anki.hooks import *
|
|
|
|
if TYPE_CHECKING:
|
|
from anki.collection import Collection
|
|
|
|
|
|
class Finder:
|
|
def __init__(self, col: Optional[Collection]) -> None:
|
|
self.col = col.weakref()
|
|
print("Finder() is deprecated, please use col.find_cards() or .find_notes()")
|
|
|
|
def findCards(self, query: Any, order: Any) -> Any:
|
|
return self.col.find_cards(query, order)
|
|
|
|
def findNotes(self, query: Any) -> Any:
|
|
return self.col.find_notes(query)
|
|
|
|
|
|
# Find and replace
|
|
##########################################################################
|
|
|
|
|
|
def findReplace(
|
|
col: Collection,
|
|
nids: List[int],
|
|
src: str,
|
|
dst: str,
|
|
regex: bool = False,
|
|
field: Optional[str] = None,
|
|
fold: bool = True,
|
|
) -> int:
|
|
"Find and replace fields in a note. Returns changed note count."
|
|
print("use col.find_and_replace() instead of findReplace()")
|
|
return col.find_and_replace(
|
|
note_ids=nids,
|
|
search=src,
|
|
replacement=dst,
|
|
regex=regex,
|
|
match_case=not fold,
|
|
field_name=field,
|
|
).count
|
|
|
|
|
|
def fieldNamesForNotes(col: Collection, nids: List[int]) -> List[str]:
|
|
return list(col._backend.field_names_for_notes(nids))
|
|
|
|
|
|
# Find duplicates
|
|
##########################################################################
|
|
|
|
|
|
def fieldNames(col: Collection, downcase: bool = True) -> List:
|
|
fields: Set[str] = set()
|
|
for m in col.models.all():
|
|
for f in m["flds"]:
|
|
name = f["name"].lower() if downcase else f["name"]
|
|
if name not in fields: # slower w/o
|
|
fields.add(name)
|
|
return list(fields)
|