use super::*;
use crate::bible::Verses;
pub(super) struct TextFill<'a> {
pub bible: Option<&'a Bible>,
pub markup: Option<&'a settings::MarkupSettings>,
pub line_prefix: &'a str,
pub join: &'a str,
}
fn text_placeholder(name: &str) -> Option<Verses> {
let count = |n: &str| n.trim().parse().ok();
match name.split_once(':') {
None if name == "text" => Some(Verses::All),
Some(("first", n)) => count(n).map(Verses::First),
Some(("last", n)) => count(n).map(Verses::Last),
_ => None,
}
}
impl Server {
pub(super) fn fill_template(
&self,
template: &str,
found: &BibleMatch,
translation: Option<&Translation>,
fill: &TextFill,
) -> Option<String> {
let books = self.matcher.data().books();
let named = fill.bible.and_then(|b| self.translation_of(b, translation));
let template = settings::fill_translation(template, named);
let mut filled = String::new();
let mut rest = template.as_str();
while let Some(open) = rest.find('{') {
filled.push_str(&rest[..open]);
let after = &rest[open + 1..];
let Some(close) = after.find('}') else {
filled.push_str(&rest[open..]);
return Some(filled);
};
let name = &after[..close];
let value = match name {
"reference" => Some(self.reference(found)),
"osis" => Some(found.psg.to_osis(books).unwrap_or_default()),
"usfm" => Some(found.psg.to_usfm(books).unwrap_or_default()),
"bible" => Some(fill.bible.map_or("", |b| b.name.as_str()).to_string()),
_ => match text_placeholder(name) {
Some(verses) => Some(self.template_text(found, verses, fill)?),
None => None,
},
};
match value {
Some(value) => filled.push_str(&value),
None => filled.push_str(&rest[open..open + close + 2]),
}
rest = &after[close + 1..];
}
filled.push_str(rest);
Some(filled)
}
fn template_text(&self, found: &BibleMatch, verses: Verses, fill: &TextFill) -> Option<String> {
let text = fill
.bible?
.passage_verses(&found.psg, fill.markup, verses)?
.text;
let lines: Vec<String> = text
.lines()
.map(|line| format!("{}{line}", fill.line_prefix).trim_end().to_string())
.collect();
match fill.join {
"\n" => Some(lines.join("\n")),
join => Some(
(lines.iter().map(|l| l.trim()).filter(|l| !l.is_empty()))
.collect::<Vec<_>>()
.join(join),
),
}
}
}