//! The bundled templates (DOC-01).
use gpui::App;
/// The three bundled templates (DOC-01).
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Template {
Blank,
Report,
Letter,
}
pub const TEMPLATES: [Template; 3] = [Template::Blank, Template::Report, Template::Letter];
impl Template {
pub fn key(self) -> &'static str {
match self {
Template::Blank => "blank",
Template::Report => "report",
Template::Letter => "letter",
}
}
/// The paragraphs, as (heading level, text); 0 is body.
fn lines(self, cx: &App) -> Vec<(u8, String)> {
let text = |key: &str| ely_ui::i18n::text(cx, key, &[]).to_string();
match self {
Template::Blank => vec![(0, String::new())],
Template::Report => vec![
(9, text("doc.report.title")),
(1, text("doc.report.summary")),
(0, text("doc.body")),
(1, text("doc.report.details")),
(0, text("doc.body")),
],
Template::Letter => vec![
(0, text("doc.letter.sender")),
(0, text("doc.letter.date")),
(0, String::new()),
(0, text("doc.letter.recipient")),
(0, String::new()),
(0, text("doc.letter.greeting")),
(0, text("doc.body")),
(0, String::new()),
(0, text("doc.letter.closing")),
(0, text("doc.letter.sender")),
],
}
}
/// Flat ODF text; level 9 is the Title style.
pub fn fodt(self, cx: &App) -> String {
let body: String = self
.lines(cx)
.into_iter()
.map(|(level, text)| {
let text = escape(&text);
match level {
0 => format!("{text}"),
9 => format!("{text}"),
level => format!("{text}"),
}
})
.collect();
format!(
"\n{body}\n"
)
}
/// The template as the picker's markdown preview.
pub fn preview(self, cx: &App) -> String {
self.lines(cx)
.into_iter()
.map(|(level, text)| match level {
0 => text,
9 => format!("# {text}"),
level => format!("{} {text}", "#".repeat(usize::from(level) + 1)),
})
.collect::>()
.join("\n\n")
}
}
/// XML-escapes template text.
fn escape(text: &str) -> String {
text.replace('&', "&")
.replace('<', "<")
.replace('>', ">")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn template_text_is_escaped() {
assert_eq!(escape("a"), "a<b & c>");
}
}