allow adjusting tag case in rename

https://forums.ankiweb.net/t/2-1-46-renaming-tags-to-tags-not-working/12426
This commit is contained in:
Damien Elmes 2021-08-19 11:46:01 +10:00
parent d92913eb8c
commit d333d0da74
2 changed files with 21 additions and 14 deletions

View File

@ -73,11 +73,7 @@ impl Collection {
/// Create a tag object, normalize text, and match parents/existing case if available. /// Create a tag object, normalize text, and match parents/existing case if available.
/// True if tag is new. /// True if tag is new.
pub(super) fn prepare_tag_for_registering(&self, tag: &mut Tag) -> Result<bool> { pub(super) fn prepare_tag_for_registering(&self, tag: &mut Tag) -> Result<bool> {
let normalized_name = normalize_tag_name(&tag.name); let normalized_name = normalize_tag_name(&tag.name)?;
if normalized_name.is_empty() {
// this should not be possible
return Err(AnkiError::invalid_input("blank tag"));
}
if let Some(existing_tag) = self.storage.get_tag(&normalized_name)? { if let Some(existing_tag) = self.storage.get_tag(&normalized_name)? {
tag.name = existing_tag.name; tag.name = existing_tag.name;
Ok(false) Ok(false)
@ -99,7 +95,7 @@ impl Collection {
impl Collection { impl Collection {
/// If parent tag(s) exist and differ in case, return a rewritten tag. /// If parent tag(s) exist and differ in case, return a rewritten tag.
fn adjusted_case_for_parents(&self, tag: &str) -> Result<Option<String>> { pub(super) fn adjusted_case_for_parents(&self, tag: &str) -> Result<Option<String>> {
if let Some(parent_tag) = self.first_existing_parent_tag(tag)? { if let Some(parent_tag) = self.first_existing_parent_tag(tag)? {
let child_split: Vec<_> = tag.split("::").collect(); let child_split: Vec<_> = tag.split("::").collect();
let parent_count = parent_tag.matches("::").count() + 1; let parent_count = parent_tag.matches("::").count() + 1;
@ -144,8 +140,8 @@ fn normalized_tag_name_component(comp: &str) -> Cow<str> {
} }
} }
fn normalize_tag_name(name: &str) -> Cow<str> { pub(super) fn normalize_tag_name(name: &str) -> Result<Cow<str>> {
if name let normalized_name: Cow<str> = if name
.split("::") .split("::")
.any(|comp| matches!(normalized_tag_name_component(comp), Cow::Owned(_))) .any(|comp| matches!(normalized_tag_name_component(comp), Cow::Owned(_)))
{ {
@ -157,6 +153,12 @@ fn normalize_tag_name(name: &str) -> Cow<str> {
} else { } else {
// no changes required // no changes required
name.into() name.into()
};
if normalized_name.is_empty() {
// this should not be possible
Err(AnkiError::invalid_input("blank tag"))
} else {
Ok(normalized_name)
} }
} }

View File

@ -1,8 +1,9 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use super::{is_tag_separator, matcher::TagMatcher, Tag}; use super::{is_tag_separator, matcher::TagMatcher};
use crate::prelude::*; use crate::prelude::*;
use crate::tags::register::normalize_tag_name;
impl Collection { impl Collection {
/// Rename a given tag and its children on all notes that reference it, returning changed /// Rename a given tag and its children on all notes that reference it, returning changed
@ -29,10 +30,14 @@ impl Collection {
let usn = self.usn()?; let usn = self.usn()?;
// match existing case if available, and ensure normalized. // ensure normalized+matching parent case, but not case of existing tag.
let mut tag = Tag::new(new_prefix.to_string(), usn); // The matching of parent case is mainly to be consistent with the way
self.prepare_tag_for_registering(&mut tag)?; // decks are handled.
let new_prefix = &tag.name; let new_prefix = normalize_tag_name(new_prefix)?;
let new_prefix = self
.adjusted_case_for_parents(&new_prefix)?
.map(Into::into)
.unwrap_or(new_prefix);
// gather tags that need replacing // gather tags that need replacing
let mut re = TagMatcher::new(old_prefix)?; let mut re = TagMatcher::new(old_prefix)?;
@ -53,7 +58,7 @@ impl Collection {
// replace tags // replace tags
for mut note in matched_notes { for mut note in matched_notes {
let original = note.clone(); let original = note.clone();
note.tags = re.replace(&note.tags, new_prefix); note.tags = re.replace(&note.tags, &new_prefix);
note.set_modified(usn); note.set_modified(usn);
self.update_note_tags_undoable(&note, original)?; self.update_note_tags_undoable(&note, original)?;
} }