From 9e53c84a35d5058dc55c31c784f8bba0d45b566a Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 17 Aug 2020 18:14:00 +1000 Subject: [PATCH] fix globs not working in bulk tag add/remove --- rslib/src/search/sqlwriter.rs | 36 +---------------------------------- rslib/src/tags.rs | 11 ++++++----- rslib/src/text.rs | 32 +++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/rslib/src/search/sqlwriter.rs b/rslib/src/search/sqlwriter.rs index b145c4635..5b24f6453 100644 --- a/rslib/src/search/sqlwriter.rs +++ b/rslib/src/search/sqlwriter.rs @@ -9,11 +9,9 @@ use crate::{ err::Result, notes::field_checksum, notetype::NoteTypeID, - text::matches_wildcard, + text::{matches_wildcard, text_to_re}, text::{normalize_to_nfc, strip_html_preserving_image_filenames, without_combining}, }; -use lazy_static::lazy_static; -use regex::{Captures, Regex}; use std::{borrow::Cow, fmt::Write}; pub(crate) struct SqlWriter<'a> { @@ -458,38 +456,6 @@ fn glob_to_re(glob: &str) -> Option { Some(text_to_re(glob)) } -/// Escape text, converting glob characters to regex syntax, then return. -fn text_to_re(glob: &str) -> String { - lazy_static! { - static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap(); - static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap(); - } - - let escaped = regex::escape(glob); - - let text = ESCAPED.replace_all(&escaped, |caps: &Captures| { - if caps.get(0).unwrap().as_str().len() == 2 { - ".*" - } else { - r"\*" - } - }); - - let text2 = GLOB.replace_all(&text, |caps: &Captures| { - match caps.get(0).unwrap().as_str() { - "_" => ".", - "%" => ".*", - other => { - // strip off the escaping char - &other[2..] - } - } - .to_string() - }); - - text2.into() -} - #[derive(Debug, PartialEq, Clone, Copy)] pub enum RequiredTable { Notes, diff --git a/rslib/src/tags.rs b/rslib/src/tags.rs index 93b22e41a..a3cd45106 100644 --- a/rslib/src/tags.rs +++ b/rslib/src/tags.rs @@ -5,6 +5,7 @@ use crate::{ collection::Collection, err::{AnkiError, Result}, notes::{NoteID, TransformNoteOutput}, + text::text_to_re, {text::normalize_to_nfc, types::Usn}, }; use regex::{NoExpand, Regex, Replacer}; @@ -123,11 +124,7 @@ impl Collection { // generate regexps let tags = split_tags(tags) .map(|tag| { - let tag = if regex { - tag.into() - } else { - regex::escape(tag) - }; + let tag = if regex { tag.into() } else { text_to_re(tag) }; Regex::new(&format!("(?i){}", tag)) .map_err(|_| AnkiError::invalid_input("invalid regex")) }) @@ -234,6 +231,10 @@ mod test { let note = col.storage.get_note(note.id)?.unwrap(); assert_eq!(note.tags[0], "bar"); + col.replace_tags_for_notes(&[note.id], "b*r", "baz", false)?; + let note = col.storage.get_note(note.id)?.unwrap(); + assert_eq!(note.tags[0], "baz"); + col.replace_tags_for_notes(&[note.id], "b.r", "baz", true)?; let note = col.storage.get_note(note.id)?.unwrap(); assert_eq!(note.tags[0], "baz"); diff --git a/rslib/src/text.rs b/rslib/src/text.rs index 7272b3e6d..57845615e 100644 --- a/rslib/src/text.rs +++ b/rslib/src/text.rs @@ -261,6 +261,38 @@ pub(crate) fn without_combining(s: &str) -> Cow { .into() } +/// Escape text, converting glob characters to regex syntax, then return. +pub(crate) fn text_to_re(glob: &str) -> String { + lazy_static! { + static ref ESCAPED: Regex = Regex::new(r"(\\\\)?\\\*").unwrap(); + static ref GLOB: Regex = Regex::new(r"(\\\\)?[_%]").unwrap(); + } + + let escaped = regex::escape(glob); + + let text = ESCAPED.replace_all(&escaped, |caps: &Captures| { + if caps.get(0).unwrap().as_str().len() == 2 { + ".*" + } else { + r"\*" + } + }); + + let text2 = GLOB.replace_all(&text, |caps: &Captures| { + match caps.get(0).unwrap().as_str() { + "_" => ".", + "%" => ".*", + other => { + // strip off the escaping char + &other[2..] + } + } + .to_string() + }); + + text2.into() +} + #[cfg(test)] mod test { use super::matches_wildcard;