///|
/// A rich-text line. `content` excludes the newline; formatting attached to
/// the newline is returned separately as `attributes` (Quill block formats).
pub(all) struct DeltaLine {
  content : Delta
  attributes : Json
  start : Int32
  terminated : Bool
} derive(Eq, Debug)

///|
/// Split an insert-only document into rich-text lines. The final unterminated
/// line is included when it has content. An empty document has no lines.
pub fn Delta::lines(self : Delta) -> Array[DeltaLine] raise DeltaError {
  if !self.is_document() {
    raise Invalid("lines requires an insert-only document")
  }
  let output : Array[DeltaLine] = []
  let mut position = 0
  let mut line_start = 0
  for op in self.ops {
    match op {
      InsertText(text, attrs) => {
        for i in 0.. position += 1
      _ => ()
    }
  }
  if line_start < position {
    output.push({
      content: self.slice(line_start, position),
      attributes: empty_attributes(),
      start: line_start,
      terminated: false,
    })
  }
  output
}

///|
pub fn Delta::line_count(self : Delta) -> Int32 raise DeltaError {
  self.lines().length()
}

///|
/// Visit lines while operations remain inserts. The callback receives the
/// line without its delimiter, delimiter attributes, and a zero-based line
/// number. Returning false stops traversal. A non-insert stops iteration;
/// any preceding complete lines have already been visited.
pub fn Delta::each_line(
  self : Delta,
  visit : (Delta, Json, Int32) -> Bool,
  newline~ : String = "\n",
) -> Unit raise DeltaError {
  if newline.length() == 0 {
    raise Invalid("newline delimiter cannot be empty")
  }
  let mut position = 0
  let mut line_start = 0
  let mut line_index = 0
  for op in self.ops {
    match op {
      InsertText(text, attributes) => {
        let mut i = 0
        while i + newline.length() <= text.length() {
          let mut matches = true
          for j in 0.. position += 1
      _ => return
    }
  }
  if line_start < position {
    ignore(
      visit(self.slice(line_start, position), empty_attributes(), line_index),
    )
  }
}

///|
pub extend DeltaLine with Eq::{equal, not_equal}

///|
pub extend DeltaLine with @moonbitlang/core/debug.Debug::{to_repr}