Insert a comment into a word processing document

Inserting a comment requires updating the comments part and adding matching comment range markers or references in the main document body.

The upstream sample attaches a comment to the first paragraph. A general Rust API should make the target range explicit and should fail clearly if the selected paragraph or range does not exist.

Comment markup

<w:comment w:id="0" w:author="Ada">
  <w:p><w:r><w:t>Review this paragraph</w:t></w:r></w:p>
</w:comment>

The same id must be used in the comment and in the document markers:

<w:commentRangeStart w:id="0"/>
<w:r><w:t>Commented text</w:t></w:r>
<w:commentRangeEnd w:id="0"/>
<w:r><w:commentReference w:id="0"/></w:r>

Rust workflow

Read existing comments, allocate the next id, update word/comments.xml, and add markers around the first paragraph:

#![allow(unused)]
fn main() {
pub fn insert_comment(
  path: &Path,
  author: &str,
  comment_text: &str,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
  let mut document = WordprocessingDocument::new_from_file_with_settings(path, lazy_settings())?;
  let main_part = document.main_document_part()?;
  let comments_part = if let Some(part) = main_part.wordprocessing_comments_part(&document) {
    part
  } else {
    main_part.add_new_part_auto_id::<_, WordprocessingCommentsPart>(&mut document)?
  };
  let comments_xml = comments_part
    .data_as_str(&document)?
    .map(str::to_string)
    .unwrap_or_else(empty_comments_xml);
  let comment_id = next_comment_id(&comments_xml);
  let updated_comments = append_comment(&comments_xml, comment_id, author, comment_text)?;
  comments_part.set_data(&mut document, updated_comments.into_bytes())?;

  let document_xml = main_part.data_as_str(&document)?.unwrap_or_default();
  let updated_document = add_comment_markers_to_first_paragraph(document_xml, comment_id)?;
  main_part.set_data(&mut document, updated_document.into_bytes())?;

  let mut buffer = Cursor::new(Vec::new());
  document.save(&mut buffer)?;
  Ok(buffer.into_inner())
}
}

Allocate a new comment id by scanning existing comments and adding one to the maximum id. If the comments part is absent, create it with a comments root before appending the new comment.

In ooxmlsdk, generated schema types include Comments, Comment, CommentRangeStart, CommentRangeEnd, and CommentReference.