diff --git a/proto/backend.proto b/proto/backend.proto index b5ac530dd..2e0f76291 100644 --- a/proto/backend.proto +++ b/proto/backend.proto @@ -18,6 +18,7 @@ message BackendInput { int64 local_minutes_west = 22; string strip_av_tags = 23; string get_av_tags = 24; + string flag_av_tags = 25; } } @@ -32,6 +33,7 @@ message BackendOutput { sint32 local_minutes_west = 22; string strip_av_tags = 23; GetAVTagsOut get_av_tags = 24; + string flag_av_tags = 25; BackendError error = 2047; } diff --git a/pylib/anki/rsbackend.py b/pylib/anki/rsbackend.py index 1d687a6bb..0dc726716 100644 --- a/pylib/anki/rsbackend.py +++ b/pylib/anki/rsbackend.py @@ -170,3 +170,6 @@ class RustBackend: ).get_av_tags.av_tags, ) ) + + def flag_av_tags(self, text: str) -> str: + return self._run_command(pb.BackendInput(flag_av_tags=text)).flag_av_tags diff --git a/rslib/src/backend.rs b/rslib/src/backend.rs index 18b475c48..201fbe7ce 100644 --- a/rslib/src/backend.rs +++ b/rslib/src/backend.rs @@ -10,7 +10,7 @@ use crate::template::{ render_card, without_legacy_template_directives, FieldMap, FieldRequirements, ParsedTemplate, RenderedNode, }; -use crate::text::{av_tags_in_string, strip_av_tags, AVTag}; +use crate::text::{av_tags_in_string, flag_av_tags, strip_av_tags, AVTag}; use prost::Message; use std::collections::{HashMap, HashSet}; use std::path::PathBuf; @@ -101,6 +101,7 @@ impl Backend { } Value::StripAvTags(text) => OValue::StripAvTags(strip_av_tags(&text).into()), Value::GetAvTags(text) => OValue::GetAvTags(self.get_av_tags(&text)), + Value::FlagAvTags(text) => OValue::FlagAvTags(flag_av_tags(&text).into()), }) } diff --git a/rslib/src/text.rs b/rslib/src/text.rs index b3743d8d2..105643bba 100644 --- a/rslib/src/text.rs +++ b/rslib/src/text.rs @@ -3,7 +3,7 @@ use htmlescape; use lazy_static::lazy_static; -use regex::Regex; +use regex::{Captures, Regex}; use std::borrow::Cow; use std::collections::HashSet; use std::ptr; @@ -78,6 +78,14 @@ pub fn strip_av_tags(text: &str) -> Cow { AV_TAGS.replace_all(text, "") } +pub fn flag_av_tags(text: &str) -> Cow { + let mut idx = 0; + AV_TAGS.replace_all(text, |_caps: &Captures| { + let text = format!("[anki:play]{}[/anki:play]", idx); + idx += 1; + text + }) +} pub fn av_tags_in_string(text: &str) -> impl Iterator { AV_TAGS.captures_iter(text).map(|caps| { if let Some(av_file) = caps.get(1) { @@ -141,7 +149,7 @@ pub fn cloze_numbers_in_string(html: &str) -> HashSet { #[cfg(test)] mod test { use crate::text::{ - av_tags_in_string, cloze_numbers_in_string, strip_av_tags, strip_html, + av_tags_in_string, cloze_numbers_in_string, flag_av_tags, strip_av_tags, strip_html, strip_html_preserving_image_filenames, AVTag, }; use std::collections::HashSet; @@ -192,5 +200,10 @@ mod test { }, ] ); + + assert_eq!( + flag_av_tags(s), + "abc[anki:play]0[/anki:play]def[anki:play]1[/anki:play]gh" + ); } }