///|
/// Remove every occurrence and its physical line(s), including inline comments.
/// Standalone comments, empty sections and all other text remain untouched.
pub fn Document::remove(
  self : Document,
  section : String,
  key : String,
) -> Result[Document, Diagnostic] {
  if !editable(self) {
    return Err(edit_problem("EDIT001", "repair syntax errors before editing"))
  }
  let entries = self.entries(section, key)
  if entries.is_empty() {
    return Ok(self)
  }
  let out = StringBuilder()
  let mut cursor = 0
  for n in entries {
    out.write_string(text(self.source, cursor, n.span.start))
    cursor = n.span.end
  }
  out.write_string(text(self.source, cursor, self.source.length()))
  let next = parse(out.to_string(), dialect=self.dialect, limits=self.limits)
  if !editable(next) || !next.entries(section, key).is_empty() {
    return Err(
      edit_problem("EDIT003", "removal failed parse-back verification"),
    )
  }
  Ok(next)
}

///|
pub fn Document::remove_at(
  self : Document,
  section : String,
  key : String,
  occurrence : Int,
) -> Result[Document, Diagnostic] {
  if !editable(self) {
    return Err(edit_problem("EDIT001", "repair syntax errors before editing"))
  }
  let entries = self.entries(section, key)
  if occurrence < 0 || occurrence >= entries.length() {
    return Err(edit_problem("EDIT002", "occurrence does not exist"))
  }
  let n = entries[occurrence]
  let next = parse(
    text(self.source, 0, n.span.start) +
    text(self.source, n.span.end, self.source.length()),
    dialect=self.dialect,
    limits=self.limits,
  )
  if !editable(next) ||
    next.entries(section, key).length() != entries.length() - 1 {
    return Err(
      edit_problem("EDIT003", "removal failed parse-back verification"),
    )
  }
  Ok(next)
}