use crate::shared_strings::write_text_node;
use crate::writer::{Result, XmlWriter};
use std::io::Write;
use xlsbye_core::types::{Comment, ParsedComments};
use xlsbye_core::xml_names::SPREADSHEET_NS;
pub fn write_comments(writer: impl Write, comments: &ParsedComments) -> Result<()> {
let mut writer = XmlWriter::new(writer);
writer.write_xml_declaration()?;
writer.write_start_element_with_ns(
"comments",
[("", SPREADSHEET_NS)],
std::iter::empty::<(&str, &str)>(),
)?;
writer.write_start_element("authors", std::iter::empty::<(&str, &str)>())?;
for author in &comments.authors {
writer.write_text_element("author", std::iter::empty::<(&str, &str)>(), author)?;
}
writer.write_end_element("authors")?;
writer.write_start_element("commentList", std::iter::empty::<(&str, &str)>())?;
for comment in &comments.comments {
write_comment(&mut writer, comment)?;
}
writer.write_end_element("commentList")?;
writer.write_end_element("comments")?;
Ok(())
}
fn write_comment<W: Write>(writer: &mut XmlWriter<W>, comment: &Comment) -> Result<()> {
writer.write_start_element(
"comment",
[
(
"ref",
format!("{}{}", col_to_name(comment.cell_ref.col), comment.cell_ref.row),
),
("authorId", comment.author_index.to_string()),
],
)?;
writer.write_start_element("text", std::iter::empty::<(&str, &str)>())?;
if comment.text.is_empty() {
writer.write_start_element("r", std::iter::empty::<(&str, &str)>())?;
writer.write_text_element("t", std::iter::empty::<(&str, &str)>(), "")?;
writer.write_end_element("r")?;
} else {
for run in &comment.text {
writer.write_start_element("r", std::iter::empty::<(&str, &str)>())?;
write_text_node(writer, "t", &run.text)?;
writer.write_end_element("r")?;
}
}
writer.write_end_element("text")?;
writer.write_end_element("comment")
}
fn col_to_name(mut col: u32) -> String {
let mut letters = Vec::new();
while col > 0 {
let rem = ((col - 1) % 26) as u8;
letters.push((b'A' + rem) as char);
col = (col - 1) / 26;
}
letters.iter().rev().collect()
}
#[cfg(test)]
mod tests {
use super::*;
use xlsbye_core::types::{CellRef, RichTextRun};
#[test]
fn writes_comments_xml() {
let parsed = ParsedComments {
authors: vec!["Author Name".to_string()],
comments: vec![Comment {
cell_ref: CellRef { row: 1, col: 1 },
author_index: 0,
text: vec![RichTextRun {
font_index: None,
text: "Comment text".to_string(),
}],
}],
};
let mut out = Vec::new();
write_comments(&mut out, &parsed).expect("comments xml should be written");
let xml = String::from_utf8(out).expect("utf-8 xml");
assert!(xml.contains("<comments xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"));
assert!(xml.contains("<author>Author Name</author>"));
assert!(xml.contains("<comment ref=\"A1\" authorId=\"0\">"));
assert!(xml.contains("<t>Comment text</t>"));
}
}