1use std::fs::File;
4use std::io;
5use std::io::Write;
6
7use super::Render;
8use super::RenderContext;
9use crate::app::App;
10use crate::prelude::*;
11use crate::ProgramMeta;
12
13use crate::project::Format;
14use crate::project::Output;
15use crate::util::xml_support::*;
16use crate::xml_write;
17
18xml_write!(struct ProgramMeta {
19 name,
20 version,
21 description,
22 homepage,
23 authors,
24} -> |w| {
25 w.tag("program")
26 .content()?
27 .field(name)?
28 .field(version)?
29 .field(description)?
30 .field(homepage)?
31 .field(authors)?
32});
33
34impl XmlWrite for Format {
35 fn write<W>(&self, mut writer: &mut Writer<W>) -> quick_xml::Result<()>
36 where
37 W: io::Write,
38 {
39 writer.write_text(self)
40 }
41}
42
43xml_write!(struct Output {
44 file,
45 template,
46 format,
47 toc_sort,
48 toc_sort_key,
49 sans_font,
50 font_size,
51 dpi,
52 tex_runs,
53 script,
54 book_overrides,
55} -> |w| {
56 let _ = file;
57 let _ = template;
58 let _ = book_overrides;
59 w.tag("output")
60 .content()?
61 .field_opt(format)?
62 .field(sans_font)?
63 .field(font_size)?
64 .field(toc_sort)?
65 .field(toc_sort_key)?
66 .field_opt(dpi)?
67 .field(tex_runs)?
68 .field_opt(script)?
69});
70
71xml_write!(struct RenderContext<'a> {
72 book,
73 songs,
74 songs_sorted,
75 notation,
76 output,
77 program,
78} -> |w| {
79 w.tag("songbook")
80 .attr(notation)
81 .content()?
82 .comment("The [book] section in bard.toml")?
83 .field(book)?
84 .comment("References to <song> elements in alphabetically-sorted order")?
85 .value_wrap("songs-sorted", songs_sorted)?
86 .comment("Fields in the [[output]] section in bard.toml")?
87 .value_wrap("output", output)?
88 .comment("Software metadata")?
89 .value(program)?
90 .comment("Song data")?
91 .field(songs)?
92});
93
94#[derive(Debug, Default)]
95pub struct RXml;
96
97impl RXml {
98 pub fn new() -> Self {
99 Self
100 }
101}
102
103impl Render for RXml {
104 fn render(&self, _app: &App, output: &Path, context: RenderContext) -> anyhow::Result<()> {
105 File::create(output)
106 .map_err(Error::from)
107 .and_then(|f| {
108 let mut writer = Writer::new_with_indent(f, b' ', 2);
109 context.write(&mut writer)?;
110
111 let mut f = writer.into_inner();
112 f.write_all(b"\n")?;
113 Ok(())
114 })
115 .with_context(|| format!("Error writing output file: {:?}", output))
116 }
117}