add ruby filters
This commit is contained in:
parent
d4553e9488
commit
7d7656d86f
@ -7,4 +7,5 @@ pub mod backend;
|
||||
pub mod err;
|
||||
pub mod sched;
|
||||
pub mod template;
|
||||
pub mod template_filters;
|
||||
pub mod text;
|
||||
|
@ -2,6 +2,7 @@
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::err::{AnkiError, Result};
|
||||
use crate::template_filters::apply_filters;
|
||||
use lazy_static::lazy_static;
|
||||
use nom;
|
||||
use nom::branch::alt;
|
||||
@ -377,48 +378,6 @@ fn unknown_field_message(field_name: &str, filters: &[&str]) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
// Filtering
|
||||
//----------------------------------------
|
||||
|
||||
/// Applies built in filters, returning the resulting text and remaining filters.
|
||||
///
|
||||
/// The first non-standard filter that is encountered will terminate processing,
|
||||
/// so non-standard filters must come at the end.
|
||||
fn apply_filters<'a>(text: &'a str, filters: &[&str]) -> (Cow<'a, str>, Vec<String>) {
|
||||
let mut text: Cow<str> = text.into();
|
||||
|
||||
for (idx, &filter_name) in filters.iter().enumerate() {
|
||||
match apply_filter(filter_name, text.as_ref()) {
|
||||
Some(output) => {
|
||||
text = output.into();
|
||||
}
|
||||
None => {
|
||||
// unrecognized filter, return current text and remaining filters
|
||||
return (
|
||||
text,
|
||||
filters.iter().skip(idx).map(ToString::to_string).collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all filters processed
|
||||
(text, vec![])
|
||||
}
|
||||
|
||||
fn apply_filter(filter_name: &str, text: &str) -> Option<String> {
|
||||
let output_text = match filter_name {
|
||||
"text" => text_filter(text),
|
||||
_ => return None,
|
||||
};
|
||||
output_text.into()
|
||||
}
|
||||
|
||||
fn text_filter(text: &str) -> String {
|
||||
// fixme: implement properly
|
||||
Regex::new(r"<.+?>").unwrap().replace_all(text, "").into()
|
||||
}
|
||||
|
||||
// Field requirements
|
||||
//----------------------------------------
|
||||
|
||||
|
145
rslib/src/template_filters.rs
Normal file
145
rslib/src/template_filters.rs
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::text::strip_html;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::{Captures, Regex};
|
||||
use std::borrow::Cow;
|
||||
|
||||
// Filtering
|
||||
//----------------------------------------
|
||||
|
||||
/// Applies built in filters, returning the resulting text and remaining filters.
|
||||
///
|
||||
/// The first non-standard filter that is encountered will terminate processing,
|
||||
/// so non-standard filters must come at the end.
|
||||
pub(crate) fn apply_filters<'a>(text: &'a str, filters: &[&str]) -> (Cow<'a, str>, Vec<String>) {
|
||||
let mut text: Cow<str> = text.into();
|
||||
|
||||
for (idx, &filter_name) in filters.iter().enumerate() {
|
||||
match apply_filter(filter_name, text.as_ref()) {
|
||||
(true, None) => {
|
||||
// filter did not change text
|
||||
}
|
||||
(true, Some(output)) => {
|
||||
// text updated
|
||||
text = output.into();
|
||||
}
|
||||
(false, _) => {
|
||||
// unrecognized filter, return current text and remaining filters
|
||||
return (
|
||||
text,
|
||||
filters.iter().skip(idx).map(ToString::to_string).collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all filters processed
|
||||
(text, vec![])
|
||||
}
|
||||
|
||||
/// Apply one filter.
|
||||
///
|
||||
/// Returns true if filter was valid.
|
||||
/// Returns string if input text changed.
|
||||
fn apply_filter<'a>(filter_name: &str, text: &'a str) -> (bool, Option<String>) {
|
||||
let output_text = match filter_name {
|
||||
"text" => strip_html(text),
|
||||
"furigana" => furigana_filter(text),
|
||||
"kanji" => kanji_filter(text),
|
||||
"kana" => kana_filter(text),
|
||||
_ => return (false, None),
|
||||
};
|
||||
|
||||
(
|
||||
true,
|
||||
match output_text {
|
||||
Cow::Owned(o) => Some(o),
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Cloze filter
|
||||
//----------------------------------------
|
||||
|
||||
// Ruby filters
|
||||
//----------------------------------------
|
||||
|
||||
lazy_static! {
|
||||
static ref FURIGANA: Regex = Regex::new(r" ?([^ >]+?)\[(.+?)\]").unwrap();
|
||||
}
|
||||
|
||||
/// Did furigana regex match a sound tag?
|
||||
fn captured_sound(caps: &Captures) -> bool {
|
||||
caps.get(2).unwrap().as_str().starts_with("sound:")
|
||||
}
|
||||
|
||||
fn kana_filter(text: &str) -> Cow<str> {
|
||||
FURIGANA
|
||||
.replace_all(&text.replace(" ", " "), |caps: &Captures| {
|
||||
if captured_sound(caps) {
|
||||
caps.get(0).unwrap().as_str().to_owned()
|
||||
} else {
|
||||
caps.get(2).unwrap().as_str().to_owned()
|
||||
}
|
||||
})
|
||||
.into_owned()
|
||||
.into()
|
||||
}
|
||||
|
||||
fn kanji_filter(text: &str) -> Cow<str> {
|
||||
FURIGANA
|
||||
.replace_all(&text.replace(" ", " "), |caps: &Captures| {
|
||||
if captured_sound(caps) {
|
||||
caps.get(0).unwrap().as_str().to_owned()
|
||||
} else {
|
||||
caps.get(1).unwrap().as_str().to_owned()
|
||||
}
|
||||
})
|
||||
.into_owned()
|
||||
.into()
|
||||
}
|
||||
|
||||
fn furigana_filter(text: &str) -> Cow<str> {
|
||||
FURIGANA
|
||||
.replace_all(&text.replace(" ", " "), |caps: &Captures| {
|
||||
if captured_sound(caps) {
|
||||
caps.get(0).unwrap().as_str().to_owned()
|
||||
} else {
|
||||
format!(
|
||||
"<ruby><rb>{}</rb><rt>{}</rt></ruby>",
|
||||
caps.get(1).unwrap().as_str(),
|
||||
caps.get(2).unwrap().as_str()
|
||||
)
|
||||
}
|
||||
})
|
||||
.into_owned()
|
||||
.into()
|
||||
}
|
||||
|
||||
// Other filters
|
||||
//----------------------------------------
|
||||
|
||||
// - type
|
||||
// - hint
|
||||
|
||||
// Tests
|
||||
//----------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::template_filters::{furigana_filter, kana_filter, kanji_filter};
|
||||
|
||||
#[test]
|
||||
fn test_furigana() {
|
||||
let text = "test first[second] third[fourth]";
|
||||
assert_eq!(kana_filter(text).as_ref(), "testsecondfourth");
|
||||
assert_eq!(kanji_filter(text).as_ref(), "testfirstthird");
|
||||
assert_eq!(
|
||||
furigana_filter("first[second]").as_ref(),
|
||||
"<ruby><rb>first</rb><rt>second</rt></ruby>"
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user