Skip to content

Commit

Permalink
format files
Browse files Browse the repository at this point in the history
  • Loading branch information
tatsumoto-ren committed Mar 17, 2024
1 parent 5e3dcbe commit 3214f8e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 98 deletions.
10 changes: 5 additions & 5 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ def due_key(card: Card) -> tuple:


def sort_field_key(card: Card) -> str:
return (note := card.note()).values()[note.model()['sortf']]
return (note := card.note()).values()[note.model()["sortf"]]


def custom_field_key(card: Card) -> str:
if (field := config['custom_sort_field']) in (note := card.note()):
if (field := config["custom_sort_field"]) in (note := card.note()):
return note[field]
else:
return sort_field_key(card) # Last resort
Expand Down Expand Up @@ -65,13 +65,13 @@ class Config(AddonConfigManager):

def __init__(self, default: bool = False):
super().__init__(default)
if self['ordering'] not in self._ordering_choices.names():
if self["ordering"] not in self._ordering_choices.names():
print(f"Wrong ordering: {self['ordering']}")
self['ordering'] = next(name for name in OrderingChoices.names())
self["ordering"] = next(name for name in OrderingChoices.names())

@property
def ord_key(self):
return self._ordering_choices[self['ordering']]
return self._ordering_choices[self["ordering"]]

@classmethod
def default(cls):
Expand Down
15 changes: 6 additions & 9 deletions duplicate_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

from gettext import ngettext
from typing import Sequence
from collections.abc import Sequence

from anki.collection import Collection, OpChanges
from anki.notes import Note
Expand All @@ -25,7 +25,7 @@ def duplicate_notes_op(col: Collection, notes: Sequence[Note]) -> OpChanges:
first_card = ref_note.cards()[0]
for key in ref_note.keys():
new_note[key] = ref_note[key]
new_note.tags = [tag for tag in ref_note.tags if tag != 'leech' and tag != 'marked']
new_note.tags = [tag for tag in ref_note.tags if tag != "leech" and tag != "marked"]
col.add_note(new_note, deck_id=(first_card.odid or first_card.did))

return col.merge_undo_entries(pos)
Expand All @@ -35,23 +35,20 @@ def duplicate_notes(browser: Browser) -> None:
notes = [browser.col.get_note(note_id) for note_id in browser.selected_notes()]

if 1 <= len(notes) <= LIMIT:
CollectionOp(
browser, lambda col: duplicate_notes_op(col, notes)
).success(
CollectionOp(browser, lambda col: duplicate_notes_op(col, notes)).success(
lambda out: tooltip(
ngettext("%d note duplicated.", "%d notes duplicated.", len(notes)) % len(notes),
parent=browser
ngettext("%d note duplicated.", "%d notes duplicated.", len(notes)) % len(notes), parent=browser
)
).run_in_background()
else:
tooltip(f"Please select at most {LIMIT} notes.")


def setup_context_menu(browser: Browser) -> None:
if config['show_duplicate_notes_button']:
if config["show_duplicate_notes_button"]:
menu = browser.form.menu_Cards
action = menu.addAction("Duplicate notes")
if shortcut := config['duplicate_notes_shortcut']:
if shortcut := config["duplicate_notes_shortcut"]:
action.setShortcut(QKeySequence(shortcut))
qconnect(action.triggered, lambda: duplicate_notes(browser))

Expand Down
14 changes: 7 additions & 7 deletions find_duplicates.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright: Ren Tatsumoto <tatsu at autistici.org>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

from typing import Iterable
from collections.abc import Iterable

import aqt
from anki.collection import Collection
Expand All @@ -18,9 +18,9 @@


def notes_from_search(self: Collection, field_name: str, search: str) -> Iterable[Note]:
return carefully_get_notes(self.find_notes(
self.build_search_string(search, SearchNode(field_name=field_name))
), has_field=field_name)
return carefully_get_notes(
self.find_notes(self.build_search_string(search, SearchNode(field_name=field_name))), has_field=field_name
)


def deep_search_duplicates(self: Collection, field_name: str, search: str) -> list[tuple[str, list]]:
Expand All @@ -32,7 +32,7 @@ def deep_search_duplicates(self: Collection, field_name: str, search: str) -> li


def find_duplicates(self: Collection, field_name: str, search: str, _old: Callable) -> list[tuple[str, list]]:
if config['apply_when_searching_duplicates']:
if config["apply_when_searching_duplicates"]:
return deep_search_duplicates(self, field_name, search)
else:
return _old(self, field_name, search)
Expand All @@ -41,11 +41,11 @@ def find_duplicates(self: Collection, field_name: str, search: str, _old: Callab
def append_apply_checkbox(self: FindDuplicatesDialog, _browser: Browser, _mw: aqt.AnkiQt):
# row, column, rowSpan, columnSpan
self.form.verticalLayout.addWidget(c := QCheckBox(f"Search with {ACTION_NAME}"))
c.setChecked(config['apply_when_searching_duplicates'])
c.setChecked(config["apply_when_searching_duplicates"])

def on_state_changed(checked: int):
# Ref: https://doc.qt.io/qt-6/qt.html#CheckState-enum
config['apply_when_searching_duplicates'] = bool(checked)
config["apply_when_searching_duplicates"] = bool(checked)

qconnect(c.stateChanged, on_state_changed)

Expand Down
11 changes: 5 additions & 6 deletions merge_duplicates.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Copyright: Ren Tatsumoto <tatsu at autistici.org>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html

from typing import Sequence, Optional
from typing import Optional
from collections.abc import Sequence

import anki.errors
from anki.collection import OpChanges
Expand Down Expand Up @@ -45,7 +46,7 @@ def op(self, dupes: list[tuple[str, list[NoteId]]]) -> OpChanges:

for _, dupe_nids in dupes:
if len(chunk := carefully_get_notes(dupe_nids)) > 1:
chunk.sort(key=sort_by_note_cards, reverse=config['reverse_order'])
chunk.sort(key=sort_by_note_cards, reverse=config["reverse_order"])
self._merge_notes(chunk)

mw.col.update_notes(self.notes_to_update)
Expand All @@ -55,9 +56,7 @@ def op(self, dupes: list[tuple[str, list[NoteId]]]) -> OpChanges:

def merge_dupes(parent: QWidget, dupes: list[tuple[str, list[NoteId]]]) -> None:
if len(dupes) > 0:
CollectionOp(
parent, lambda col: MergeDupes(col).op(dupes)
).success(
CollectionOp(parent, lambda col: MergeDupes(col).op(dupes)).success(
lambda out: tooltip(f"Merged {len(dupes)} groups of notes.")
).run_in_background()
else:
Expand All @@ -66,7 +65,7 @@ def merge_dupes(parent: QWidget, dupes: list[tuple[str, list[NoteId]]]) -> None:

def append_merge_duplicates_button(self: FindDuplicatesDialog, dupes: list[tuple[str, list[NoteId]]]):
self._dupes = dupes
if not getattr(self, '_merge_dupes_button', None):
if not getattr(self, "_merge_dupes_button", None):
self._merge_dupes_button = b = self.form.buttonBox.addButton(
MergeDupes.action_name, QDialogButtonBox.ButtonRole.ActionRole
)
Expand Down
59 changes: 29 additions & 30 deletions merge_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import itertools
import re
import unicodedata
from typing import Sequence, Iterator, Any, Iterable
from typing import Any
from collections.abc import Sequence, Iterator, Iterable

from anki import collection
from anki.cards import Card, CardId
Expand All @@ -30,9 +31,9 @@ def strip_html(s: str) -> str:


def strip_punctuation(s: str) -> str:
for char in set(config['punctuation_characters']):
for char in set(config["punctuation_characters"]):
if char in s:
s = s.replace(char, '')
s = s.replace(char, "")
return s


Expand All @@ -41,24 +42,24 @@ def full_width_to_half_width(s: str) -> str:


def remove_furigana(s: str):
return re.sub(r'\s*(\S+)\[[^\[\]]+]', r'\g<1>', s)
return re.sub(r"\s*(\S+)\[[^\[\]]+]", r"\g<1>", s)


def cfg_strip(s: str) -> str:
"""Removes/replaces various characters defined by the user. Called before string comparison."""
if config['ignore_html_tags']:
if config["ignore_html_tags"]:
s = strip_html(s)
if config['ignore_furigana']:
if config["ignore_furigana"]:
s = remove_furigana(s)
if config['ignore_punctuation']:
if config["ignore_punctuation"]:
s = strip_punctuation(s)
if config['full-width_as_half-width']:
if config["full-width_as_half-width"]:
s = full_width_to_half_width(s)
return s.strip()


def interpret_special_chars(s: str) -> str:
return s.replace(r'\n', '\n').replace(r'\t', '\t').replace(r'\r', '\r')
return s.replace(r"\n", "\n").replace(r"\t", "\t").replace(r"\r", "\r")


def tags_in_notes(notes: Sequence[Note]) -> Iterable[str]:
Expand All @@ -73,25 +74,25 @@ def fields_in_notes(notes: Sequence[Note]) -> Iterable[str]:

def merge_tags(recipient: Note, from_notes: Sequence[Note]) -> None:
for tag in tags_in_notes(from_notes):
if not (recipient.has_tag(tag) or tag == 'leech'):
if not (recipient.has_tag(tag) or tag == "leech"):
recipient.add_tag(tag)


def concerned_field_names(recipient_fields: list[str]):
"""
If the user has limited fields to a certain set, apply the setting.
"""
if config['limit_to_fields']:
return set(recipient_fields).intersection(config['limit_to_fields'])
if config["limit_to_fields"]:
return set(recipient_fields).intersection(config["limit_to_fields"])
else:
return recipient_fields


def merge_notes(recipient: Note, from_notes: Sequence[Note], separator: str):
if config['merge_tags'] is True:
if config["merge_tags"] is True:
merge_tags(recipient, from_notes)
for field_name in concerned_field_names(recipient.keys()):
if recipient[field_name].strip() and config['skip_if_not_empty'] is True:
if recipient[field_name].strip() and config["skip_if_not_empty"] is True:
continue
recipient[field_name] = separator.join(
{
Expand Down Expand Up @@ -119,7 +120,7 @@ def __init__(self, col: collection.Collection):
self.col = col
self.notes_to_update: list[Note] = []
self.nids_to_remove: list[NoteId] = []
self.separator = interpret_special_chars(config['field_separator'])
self.separator = interpret_special_chars(config["field_separator"])

def op(self, notes: Sequence[Note]) -> OpChanges:
pos = self.col.add_custom_undo_entry(self.action_name)
Expand All @@ -129,20 +130,24 @@ def op(self, notes: Sequence[Note]) -> OpChanges:
return self.col.merge_undo_entries(pos)

def _merge_notes(self, notes: Sequence[Note]):
if config['avoid_content_loss']:
if config["avoid_content_loss"]:
# notes are already sorted,
# but additional sorting is required to avoid content loss if possible.
notes = reorder_by_common_fields(notes)

if config['delete_original_notes'] is True:
if config["delete_original_notes"] is True:
# If the user wants to delete original notes, simply dump all content into the last note.
merge_notes(notes[-1], notes, self.separator)
self.nids_to_remove.extend([note.id for note in notes][0:-1])
self.notes_to_update.append(notes[-1])
else:
# If not, merge in pairs so that each note receives content of previous notes.
for add_from, add_to in pairs(notes):
merge_notes(add_to, (add_from, add_to,), self.separator)
merge_notes(
recipient=add_to,
from_notes=(add_from, add_to),
separator=self.separator,
)
self.notes_to_update.extend(notes)


Expand All @@ -152,6 +157,7 @@ def notes_by_cards(cards: Sequence[Card]) -> list[Note]:

def is_existing_card(card_id: CardId, browser: Browser) -> bool:
import anki

try:
browser.col.get_card(card_id)
except anki.errors.NotFoundError:
Expand All @@ -175,11 +181,8 @@ def adjust_selection(browser: Browser, selected_cids: Sequence[int]):
If other notes were deleted, select the remaining card after merging.
Prevent selection from jumping all the way to the top when the user presses arrow keys.
"""
if config['delete_original_notes'] is True:
select_card(
browser.table,
card_id=next(cid for cid in selected_cids if is_existing_card(cid, browser))
)
if config["delete_original_notes"] is True:
select_card(browser.table, card_id=next(cid for cid in selected_cids if is_existing_card(cid, browser)))


def after_merge(browser: Browser, notes: Sequence[Note], cids: Sequence[int]):
Expand All @@ -195,15 +198,11 @@ def on_merge_selected(browser: Browser) -> None:
return

sorted_cards = sorted(
(browser.col.get_card(cid) for cid in cids),
key=config.ord_key,
reverse=config['reverse_order']
(browser.col.get_card(cid) for cid in cids), key=config.ord_key, reverse=config["reverse_order"]
)

if len(notes := notes_by_cards(sorted_cards)) > 1:
CollectionOp(
browser, lambda col: MergeNotes(col).op(notes)
).success(
CollectionOp(browser, lambda col: MergeNotes(col).op(notes)).success(
lambda out: after_merge(browser, notes, cids)
).run_in_background()
else:
Expand All @@ -218,7 +217,7 @@ def on_merge_selected(browser: Browser) -> None:
def setup_context_menu(browser: Browser) -> None:
menu = browser.form.menu_Cards
merge_fields_action = menu.addAction(ACTION_NAME)
if shortcut := config['merge_notes_shortcut']:
if shortcut := config["merge_notes_shortcut"]:
merge_fields_action.setShortcut(QKeySequence(shortcut))
qconnect(merge_fields_action.triggered, lambda: on_merge_selected(browser))

Expand Down
Loading

0 comments on commit 3214f8e

Please sign in to comment.