From 35c7cad2d95f776c0dc238c8b84cc5ab6c3ac52a Mon Sep 17 00:00:00 2001 From: RisingOrange Date: Tue, 28 Jan 2025 22:42:47 +0100 Subject: [PATCH 1/3] Preserve custom note type CSS --- src/anking_notetypes/constants.py | 19 ++++- src/anking_notetypes/utils.py | 112 +++++++++++++++++++----------- 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/src/anking_notetypes/constants.py b/src/anking_notetypes/constants.py index 941fc4e..965991c 100644 --- a/src/anking_notetypes/constants.py +++ b/src/anking_notetypes/constants.py @@ -1,3 +1,6 @@ +import re + + NOTETYPE_COPY_RE = r"{notetype_base_name}-[a-zA-Z0-9]{{5}}" ANKIHUB_NOTETYPE_RE = r"{notetype_base_name} \(.+ / .+\)" @@ -8,10 +11,24 @@ r"[\w\W]*" f"" ) -ANKIHUB_TEMPLATE_END_COMMENT = ( + +ANKIHUB_HTML_END_COMMENT = ( "" ) +ANKIHUB_CSS_END_COMMENT = ( + "/*\n" + "ANKIHUB_END\n" + "Text below this comment will not be modified by AnkiHub or AnKing add-ons.\n" + "Do not edit or remove this comment if you want to protect the content below.\n" + "*/" +) +ANKIHUB_HTML_END_COMMENT_RE = re.compile( + rf"{re.escape(ANKIHUB_HTML_END_COMMENT)}(?P[\w\W]*)" +) +ANKIHUB_CSS_END_COMMENT_RE = re.compile( + rf"{re.escape(ANKIHUB_CSS_END_COMMENT)}(?P[\w\W]*)" +) diff --git a/src/anking_notetypes/utils.py b/src/anking_notetypes/utils.py index f9f0410..a95bf8b 100644 --- a/src/anking_notetypes/utils.py +++ b/src/anking_notetypes/utils.py @@ -1,9 +1,16 @@ import re import time +from copy import deepcopy from aqt import mw -from .constants import ANKIHUB_TEMPLATE_END_COMMENT, ANKIHUB_TEMPLATE_SNIPPET_RE +from .constants import ( + ANKIHUB_CSS_END_COMMENT, + ANKIHUB_CSS_END_COMMENT_RE, + ANKIHUB_HTML_END_COMMENT, + ANKIHUB_HTML_END_COMMENT_RE, + ANKIHUB_TEMPLATE_SNIPPET_RE, +) from .notetype_setting_definitions import anking_notetype_model try: @@ -28,53 +35,78 @@ def update_notetype_to_newest_version( new_model = adjust_field_ords(model, new_model) - # the order is important here - # the end comment must be added after the ankihub snippet - retain_ankihub_modifications_to_templates(model, new_model) - retain_content_below_ankihub_end_comment_or_add_end_comment(model, new_model) + new_model = _retain_content_below_ankihub_end_comment_or_add_end_comment( + model, new_model + ) model.update(new_model) -def retain_ankihub_modifications_to_templates( +def _retain_content_below_ankihub_end_comment_or_add_end_comment( old_model: "NotetypeDict", new_model: "NotetypeDict" ) -> "NotetypeDict": + updated_templates = [] for old_template, new_template in zip(old_model["tmpls"], new_model["tmpls"]): - for template_type in ["qfmt", "afmt"]: - m = re.search(ANKIHUB_TEMPLATE_SNIPPET_RE, old_template[template_type]) - if not m: - continue - - new_template[template_type] = ( - new_template[template_type].rstrip("\n ") + "\n\n" + m.group(0) + updated_template = deepcopy(new_template) + for template_side in ["qfmt", "afmt"]: + updated_template[template_side] = _updated_note_type_content( + old_template[template_side], + new_template[template_side], + content_type="html", ) - - return new_model - - -def retain_content_below_ankihub_end_comment_or_add_end_comment( - old_model: "NotetypeDict", new_model: "NotetypeDict" -) -> "NotetypeDict": - # will add the end comment if it doesn't exist - for old_template, new_template in zip(old_model["tmpls"], new_model["tmpls"]): - for template_type in ["qfmt", "afmt"]: - m = re.search( - rf"{ANKIHUB_TEMPLATE_END_COMMENT}[\w\W]*", - old_template[template_type], - ) - if m: - new_template[template_type] = ( - new_template[template_type].rstrip("\n ") + "\n\n" + m.group(0) - ) - else: - new_template[template_type] = ( - new_template[template_type].rstrip("\n ") - + "\n\n" - + ANKIHUB_TEMPLATE_END_COMMENT - + "\n\n" - ) - - return new_model + updated_templates.append(updated_template) + + result = deepcopy(new_model) + result["tmpls"] = updated_templates + + result["css"] = _updated_note_type_content( + old_content=old_model["css"], + new_content=new_model["css"], + content_type="css", + ) + + return result + + +def _updated_note_type_content( + old_content: str, + new_content: str, + content_type: str, +) -> str: + """Returns updated content with preserved content below ankihub end comment. + + Args: + old_content: Original content to preserve custom additions from + new_content: New base content to use + content_type: Either "html" or "css" to determine comment style + """ + if content_type == "html": + end_comment = ANKIHUB_HTML_END_COMMENT + end_comment_pattern = ANKIHUB_HTML_END_COMMENT_RE + else: + end_comment = ANKIHUB_CSS_END_COMMENT + end_comment_pattern = ANKIHUB_CSS_END_COMMENT_RE + + snippet_match = re.search(ANKIHUB_TEMPLATE_SNIPPET_RE, old_content) + snippet_to_migrate = snippet_match.group() if snippet_match else "" + + text_to_migrate_match = re.search(end_comment_pattern, old_content) + text_to_migrate = ( + text_to_migrate_match.group("text_to_migrate") if text_to_migrate_match else "" + ) + + # Remove end comment and content below it. + # It will be added back below. + result = re.sub(end_comment_pattern, "", new_content) + + return ( + result.rstrip("\n ") + + (f"\n{snippet_to_migrate}" if snippet_to_migrate else "") + + "\n\n" + + end_comment + + "\n" + + text_to_migrate.strip("\n ") + ) def adjust_field_ords( From f51f4c7c215997ac0647dcd45942f7c0952107ce Mon Sep 17 00:00:00 2001 From: RisingOrange Date: Tue, 28 Jan 2025 22:51:23 +0100 Subject: [PATCH 2/3] Edit docstring --- src/anking_notetypes/utils.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/anking_notetypes/utils.py b/src/anking_notetypes/utils.py index a95bf8b..aa7579c 100644 --- a/src/anking_notetypes/utils.py +++ b/src/anking_notetypes/utils.py @@ -35,14 +35,12 @@ def update_notetype_to_newest_version( new_model = adjust_field_ords(model, new_model) - new_model = _retain_content_below_ankihub_end_comment_or_add_end_comment( - model, new_model - ) + new_model = _retain_ankihub_modifications(model, new_model) model.update(new_model) -def _retain_content_below_ankihub_end_comment_or_add_end_comment( +def _retain_ankihub_modifications( old_model: "NotetypeDict", new_model: "NotetypeDict" ) -> "NotetypeDict": updated_templates = [] @@ -73,10 +71,11 @@ def _updated_note_type_content( new_content: str, content_type: str, ) -> str: - """Returns updated content with preserved content below ankihub end comment. + """Returns new_content with preserved ankihub modifications and + preserved content below the ankihub end comment. Args: - old_content: Original content to preserve custom additions from + old_content: Original content to preserve ankihub modifications and custom additions from new_content: New base content to use content_type: Either "html" or "css" to determine comment style """ From 3c2fb90fbb0cce728026fca2f9704309768f342b Mon Sep 17 00:00:00 2001 From: RisingOrange Date: Tue, 28 Jan 2025 22:57:26 +0100 Subject: [PATCH 3/3] ref: Rename variable --- src/anking_notetypes/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/anking_notetypes/utils.py b/src/anking_notetypes/utils.py index aa7579c..c795ca2 100644 --- a/src/anking_notetypes/utils.py +++ b/src/anking_notetypes/utils.py @@ -87,7 +87,7 @@ def _updated_note_type_content( end_comment_pattern = ANKIHUB_CSS_END_COMMENT_RE snippet_match = re.search(ANKIHUB_TEMPLATE_SNIPPET_RE, old_content) - snippet_to_migrate = snippet_match.group() if snippet_match else "" + ankihub_snippet = snippet_match.group() if snippet_match else "" text_to_migrate_match = re.search(end_comment_pattern, old_content) text_to_migrate = ( @@ -100,7 +100,7 @@ def _updated_note_type_content( return ( result.rstrip("\n ") - + (f"\n{snippet_to_migrate}" if snippet_to_migrate else "") + + (f"\n{ankihub_snippet}" if ankihub_snippet else "") + "\n\n" + end_comment + "\n"