///|
fn markdown_editor_paste_footnote_definition(
  source : String,
  caret : Int,
  selection : @core.TextRange?,
  input : String,
) -> RichTextInputTransform? {
  let pasted = input.trim().to_owned()
  if markdown_editor_text_length(pasted) != markdown_editor_text_length(input) {
    return None
  }
  let definition = match markdown_editor_pasted_footnote_definition(pasted) {
    Some(definition) => definition
    None => return None
  }
  let caret = markdown_editor_clamp_int(
    caret,
    0,
    markdown_editor_text_length(source),
  )
  let editor_selection : MarkdownEditorSelection = { caret, selection }
  match markdown_editor_footnote_label_at_selection(source, editor_selection) {
    Some(label) => {
      let updated = markdown_editor_upsert_pasted_footnote_definition(
        source,
        label,
        definition.text,
        caret,
      )
      return Some(
        markdown_editor_transform_result(
          text=updated.source,
          caret=caret + updated.anchor_delta,
          selection~,
        ),
      )
    }
    None => ()
  }
  match markdown_editor_active_selection(selection) {
    Some(range) => {
      let source_length = markdown_editor_text_length(source)
      let normalized = range.normalized()
      let start = markdown_editor_clamp_int(normalized.start, 0, source_length)
      let end = markdown_editor_clamp_int(normalized.end, start, source_length)
      let selected = markdown_editor_substring(source, start, end)
      let marker = "[^" + definition.label + "]"
      let text = markdown_editor_substring(source, 0, start) +
        selected +
        marker +
        markdown_editor_substring(source, end, source_length)
      let next_selection = @core.TextRange::new(
        start~,
        end=start + markdown_editor_text_length(selected),
      )
      let updated = markdown_editor_upsert_pasted_footnote_definition(
        text,
        definition.label,
        definition.text,
        next_selection.start,
      )
      let selection_shift = updated.anchor_delta
      Some(
        markdown_editor_transform_result(
          text=updated.source,
          caret=next_selection.end + selection_shift,
          selection=Some(
            @core.TextRange::new(
              start=next_selection.start + selection_shift,
              end=next_selection.end + selection_shift,
            ),
          ),
        ),
      )
    }
    None => None
  }
}

///|
fn markdown_editor_pasted_footnote_definition(
  text : String,
) -> MarkdownEditorPastedFootnoteDefinition? {
  if text.contains("\n") {
    return None
  }
  let line : MarkdownLine = {
    text,
    start: 0,
    end: markdown_editor_text_length(text),
  }
  match markdown_editor_footnote_definition_line_text_range(line) {
    Some((label, range)) =>
      Some({
        label,
        text: markdown_editor_substring(text, range.start, range.end),
      })
    None => None
  }
}

///|
fn markdown_editor_upsert_pasted_footnote_definition(
  source : String,
  label : String,
  text : String,
  anchor : Int,
) -> MarkdownEditorFootnoteDefinitionEdit {
  let key = markdown_reference_label_key(label)
  let source_length = markdown_editor_text_length(source)
  for line in markdown_editor_lines(source) {
    match markdown_editor_footnote_definition_line_text_range(line) {
      Some((definition_label, range)) =>
        if markdown_reference_label_key(definition_label) == key {
          let next_source = markdown_editor_substring(source, 0, range.start) +
            text +
            markdown_editor_substring(source, range.end, source_length)
          let delta = markdown_editor_text_length(text) -
            (range.end - range.start)
          return {
            source: next_source,
            anchor_delta: if range.end <= anchor {
              delta
            } else {
              0
            },
          }
        }
      None => ()
    }
  }
  {
    source: source +
    markdown_editor_reference_definition_append_prefix(source) +
    "[^" +
    label +
    "]: " +
    text,
    anchor_delta: 0,
  }
}

///|
fn markdown_editor_paste_autolink(
  source : String,
  caret : Int,
  selection : @core.TextRange?,
  input : String,
) -> RichTextInputTransform? {
  if markdown_editor_active_selection(selection) is Some(_) ||
    markdown_editor_any_code_block_at_content_offset(source, caret, selection) {
    return None
  }
  if markdown_editor_text_length(input.trim().to_owned()) !=
    markdown_editor_text_length(input) {
    return None
  }
  let target = markdown_editor_autolink_target_with_trailing_punctuation(input)
  if target.target == "" {
    return None
  }
  let source_length = markdown_editor_text_length(source)
  let caret = markdown_editor_clamp_int(caret, 0, source_length)
  let insert = target.leading + "<" + target.target + ">" + target.trailing
  Some(
    markdown_editor_transform_result(
      text=markdown_editor_substring(source, 0, caret) +
        insert +
        markdown_editor_substring(source, caret, source_length),
      caret=caret + markdown_editor_text_length(insert),
    ),
  )
}

///|
fn markdown_editor_complete_autolink_on_space(
  source : String,
  caret : Int,
  selection : @core.TextRange?,
) -> RichTextInputTransform? {
  if markdown_editor_active_selection(selection) is Some(_) ||
    markdown_editor_any_code_block_at_content_offset(source, caret, selection) {
    return None
  }
  let chars = source.to_array()
  let caret = markdown_editor_clamp_int(caret, 0, chars.length())
  let start = markdown_editor_previous_token_start(chars, caret)
  if start == caret || (start > 0 && chars[start - 1] == '<') {
    return None
  }
  let token = String::from_array(chars[start:caret])
  let target = markdown_editor_autolink_target_with_trailing_punctuation(token)
  if target.target == "" {
    return None
  }
  let replacement = target.leading +
    "<" +
    target.target +
    ">" +
    target.trailing +
    " "
  Some(
    markdown_editor_transform_result(
      text=String::from_array(chars[:start]) +
        replacement +
        String::from_array(chars[caret:]),
      caret=start + markdown_editor_text_length(replacement),
    ),
  )
}

///|
fn markdown_editor_complete_autolink_on_enter(
  source : String,
  caret : Int,
  selection : @core.TextRange?,
  line : String,
) -> RichTextInputTransform? {
  if markdown_editor_active_selection(selection) is Some(_) ||
    markdown_editor_any_code_block_at_content_offset(source, caret, selection) {
    return None
  }
  let chars = source.to_array()
  let caret = markdown_editor_clamp_int(caret, 0, chars.length())
  let start = markdown_editor_previous_token_start(chars, caret)
  if start == caret || (start > 0 && chars[start - 1] == '<') {
    return None
  }
  let token = String::from_array(chars[start:caret])
  let target = markdown_editor_autolink_target_with_trailing_punctuation(token)
  if target.target == "" {
    return None
  }
  let replacement = target.leading +
    "<" +
    target.target +
    ">" +
    target.trailing +
    "\n" +
    markdown_editor_continuation_marker(line)
  Some(
    markdown_editor_transform_result(
      text=String::from_array(chars[:start]) +
        replacement +
        String::from_array(chars[caret:]),
      caret=start + markdown_editor_text_length(replacement),
    ),
  )
}

///|
fn markdown_editor_previous_token_start(
  chars : Array[Char],
  caret : Int,
) -> Int {
  let mut start = markdown_editor_clamp_int(caret, 0, chars.length())
  while start > 0 &&
        chars[start - 1] != ' ' &&
        chars[start - 1] != '\n' &&
        chars[start - 1] != '\t' {
    start = start - 1
  }
  start
}

///|
pub(all) struct MarkdownEditorAutolinkTarget {
  leading : String
  target : String
  trailing : String
} derive(Eq, Debug)

///|
fn markdown_editor_autolink_target_with_trailing_punctuation(
  token : String,
) -> MarkdownEditorAutolinkTarget {
  let chars = token.to_array()
  let empty = { leading: "", target: "", trailing: "" }
  if chars.length() > 0 &&
    !markdown_editor_autolink_trailing_punctuation(chars[chars.length() - 1]) &&
    markdown_editor_is_autolink_target(token) {
    return { leading: "", target: token, trailing: "" }
  }
  let mut start = 0
  while start < chars.length() &&
        markdown_editor_autolink_leading_wrapper(chars[start]) {
    start = start + 1
  }
  let mut end = chars.length()
  while end > start &&
        markdown_editor_autolink_trailing_punctuation(chars[end - 1]) {
    end = end - 1
  }
  let wrapper_end = end
  if start > 0 {
    while end > start &&
          markdown_editor_autolink_trailing_wrapper(chars[end - 1]) {
      end = end - 1
    }
  }
  if start == 0 && end == chars.length() {
    return empty
  }
  if !markdown_editor_autolink_wrappers_balanced(chars, start, end, wrapper_end) {
    return empty
  }
  let target = String::from_array(chars[start:end])
  if !markdown_editor_is_autolink_target(target) {
    return empty
  }
  {
    leading: String::from_array(chars[:start]),
    target,
    trailing: String::from_array(chars[end:]),
  }
}

///|
fn markdown_editor_autolink_leading_wrapper(ch : Char) -> Bool {
  ch == '(' || ch == '[' || ch == '{'
}

///|
fn markdown_editor_autolink_trailing_wrapper(ch : Char) -> Bool {
  ch == ')' || ch == ']' || ch == '}'
}

///|
fn markdown_editor_autolink_wrappers_balanced(
  chars : Array[Char],
  start : Int,
  end : Int,
  wrapper_end : Int,
) -> Bool {
  let trailing = wrapper_end - end
  if start > trailing {
    return false
  }
  for index in 0.. Bool {
  (open == '(' && close == ')') ||
  (open == '[' && close == ']') ||
  (open == '{' && close == '}')
}

///|
fn markdown_editor_autolink_trailing_punctuation(ch : Char) -> Bool {
  ch == '.' || ch == ',' || ch == ';' || ch == ':' || ch == '!' || ch == '?'
}

///|
fn markdown_editor_paste_html_block(
  source : String,
  caret : Int,
  selection : @core.TextRange?,
  input : String,
) -> RichTextInputTransform? {
  if markdown_editor_any_code_block_at_content_offset(source, caret, selection) {
    return None
  }
  let html = match markdown_editor_pasted_html_block(input) {
    Some(html) => html
    None => return None
  }
  let editor_selection : MarkdownEditorSelection = { caret, selection }
  if markdown_editor_active_selection(selection) is None {
    match markdown_editor_html_block_at_selection(source, editor_selection) {
      Some(block) => {
        let source_length = markdown_editor_text_length(source)
        return Some(
          markdown_editor_transform_result(
            text=markdown_editor_substring(source, 0, block.source_range.start) +
              html +
              markdown_editor_substring(
                source,
                block.source_range.end,
                source_length,
              ),
            caret=block.source_range.start + markdown_editor_text_length(html),
          ),
        )
      }
      None => ()
    }
  }
  markdown_editor_paste_block_text_as_block(source, caret, selection, html)
}

///|
fn markdown_editor_pasted_html_block(input : String) -> String? {
  let text = input.trim().to_owned()
  if text == "" || !markdown_editor_pasted_html_block_head_supported(text) {
    return None
  }
  let blocks = parse_markdown(text)
  if blocks.length() != 1 {
    return None
  }
  match blocks[0].kind {
    MarkdownBlockKind::HtmlBlock => Some(text)
    _ => None
  }
}

///|
fn markdown_editor_pasted_html_block_head_supported(text : String) -> Bool {
  let chars = text.to_array()
  let mut start = 0
  while start < chars.length() && (chars[start] == ' ' || chars[start] == '\t') {
    start = start + 1
  }
  if start + 4 <= chars.length() &&
    chars[start] == '<' &&
    chars[start + 1] == '!' &&
    chars[start + 2] == '-' &&
    chars[start + 3] == '-' {
    return true
  }
  if start + 2 <= chars.length() &&
    chars[start] == '<' &&
    (chars[start + 1] == '!' || chars[start + 1] == '?') {
    return true
  }
  if start + 2 >= chars.length() || chars[start] != '<' {
    return false
  }
  let name_start = start + 1
  if chars[name_start] == '/' ||
    !markdown_html_tag_name_start_char(chars[name_start]) {
    return false
  }
  let mut name_end = name_start + 1
  while name_end < chars.length() &&
        markdown_html_tag_name_char(chars[name_end]) {
    name_end = name_end + 1
  }
  markdown_editor_html_block_tag_name_supported(
    String::from_array(chars[name_start:name_end]).to_lower(),
  )
}

///|
fn markdown_editor_html_block_tag_name_supported(name : String) -> Bool {
  for
    candidate in [
      "address", "article", "aside", "base", "basefont", "blockquote", "body", "caption",
      "center", "col", "colgroup", "dd", "details", "dialog", "dir", "div", "dl",
      "dt", "fieldset", "figcaption", "figure", "footer", "form", "frame", "frameset",
      "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hr", "html", "iframe",
      "legend", "li", "link", "main", "menu", "menuitem", "nav", "noframes", "ol",
      "optgroup", "option", "p", "param", "pre", "script", "search", "section", "style",
      "summary", "table", "tbody", "td", "tfoot", "th", "thead", "title", "tr", "track",
      "ul",
    ] {
    if name == candidate {
      return true
    }
  }
  false
}

///|
fn markdown_editor_paste_reference_over_selection(
  source : String,
  caret : Int,
  selection : @core.TextRange?,
  input : String,
) -> RichTextInputTransform? {
  let target = input.trim().to_owned()
  if markdown_editor_text_length(target) != markdown_editor_text_length(input) {
    return None
  }
  let paste = match markdown_editor_reference_command_for_paste_target(target) {
    Some(paste) => paste
    None => return None
  }
  let chars = source.to_array()
  let caret = markdown_editor_clamp_int(caret, 0, chars.length())
  let editor_selection : MarkdownEditorSelection = { caret, selection }
  match markdown_editor_active_selection(selection) {
    Some(range) => {
      if paste.reference_style {
        return markdown_editor_paste_reference_label_over_selection(
          source, range, paste,
        )
      }
      let result = markdown_editor_set_reference_target(
        source,
        ({ caret: range.end, selection: Some(range) } : MarkdownEditorSelection),
        paste.command,
        paste.target,
      )
      Some(
        markdown_editor_transform_result(
          text=result.source,
          caret=result.caret,
          selection=result.selection,
        ),
      )
    }
    None => {
      if paste.reference_style {
        let image = match paste.command {
          SetImageTarget(_) => true
          _ => false
        }
        let context = if image {
          markdown_editor_image_context(source, editor_selection)
        } else {
          markdown_editor_link_context(source, editor_selection)
        }
        match context {
          Some(context) =>
            return Some(
              markdown_editor_reference_label_transform(
                source,
                context.range,
                context.bounds.open_start,
                markdown_editor_reference_bounds_full_end(context.bounds),
                paste.target,
                paste.definition_text,
                image~,
              ),
            )
          None => ()
        }
        return None
      }
      let has_context = match paste.command {
        SetImageTarget(_) =>
          markdown_editor_image_context(source, editor_selection) is Some(_)
        SetLinkTarget(_) =>
          markdown_editor_link_context(source, editor_selection) is Some(_)
        _ => false
      }
      if !has_context {
        return None
      }
      let result = markdown_editor_set_reference_target(
        source,
        editor_selection,
        paste.command,
        paste.target,
      )
      Some(
        markdown_editor_transform_result(
          text=result.source,
          caret=result.caret,
          selection=result.selection,
        ),
      )
    }
  }
}

///|
pub(all) struct MarkdownEditorPasteReferenceCommand {
  command : MarkdownEditorCommand
  target : String
  reference_style : Bool
  definition_text : String
}

///|
fn markdown_editor_reference_command_for_paste_target(
  text : String,
) -> MarkdownEditorPasteReferenceCommand? {
  match markdown_editor_pasted_reference_definition(text) {
    Some(definition) =>
      return Some({
        command: SetLinkTarget(definition.target),
        target: definition.label,
        reference_style: true,
        definition_text: definition.definition_text,
      })
    None => ()
  }
  match markdown_editor_pasted_reference_target(text) {
    Some(reference) =>
      if reference.image {
        Some({
          command: SetImageTarget(reference.target),
          target: reference.target,
          reference_style: reference.reference_style,
          definition_text: "",
        })
      } else {
        Some({
          command: SetLinkTarget(reference.target),
          target: reference.target,
          reference_style: reference.reference_style,
          definition_text: "",
        })
      }
    None =>
      if markdown_editor_is_image_source(text) {
        Some({
          command: SetImageTarget(text),
          target: text,
          reference_style: false,
          definition_text: "",
        })
      } else if markdown_editor_is_autolink_target(text) {
        Some({
          command: SetLinkTarget(text),
          target: text,
          reference_style: false,
          definition_text: "",
        })
      } else {
        None
      }
  }
}

///|
pub(all) struct MarkdownEditorPastedReferenceTarget {
  target : String
  image : Bool
  reference_style : Bool
}

///|
pub(all) struct MarkdownEditorPastedReferenceDefinition {
  label : String
  target : String
  definition_text : String
}

///|
fn markdown_editor_pasted_reference_definition(
  text : String,
) -> MarkdownEditorPastedReferenceDefinition? {
  if text.contains("\n") {
    return None
  }
  let line : MarkdownLine = {
    text,
    start: 0,
    end: markdown_editor_text_length(text),
  }
  match markdown_editor_reference_definition_line_target_range(line) {
    Some((label, target_range)) => {
      if label.has_prefix("^") {
        return None
      }
      Some({
        label,
        target: markdown_editor_substring(
          text,
          target_range.start,
          target_range.end,
        ),
        definition_text: text,
      })
    }
    None => None
  }
}

///|
fn markdown_editor_pasted_reference_target(
  text : String,
) -> MarkdownEditorPastedReferenceTarget? {
  if text.contains("\n") {
    return None
  }
  let chars = text.to_array()
  let (image, label_start) = if chars.length() >= 4 &&
    chars[0] == '!' &&
    chars[1] == '[' {
    (true, 2)
  } else if chars.length() >= 3 && chars[0] == '[' {
    (false, 1)
  } else {
    return None
  }
  let close = match
    markdown_editor_find_unescaped_char(chars, label_start, ']') {
    Some(index) => index
    None => return None
  }
  if close + 1 == chars.length() {
    let target = markdown_editor_markdown_reference_label_token(
      String::from_array(chars[label_start:close]),
    )
    if target == "" {
      return None
    }
    return Some({ target, image, reference_style: true })
  }
  if chars[close + 1] == '[' {
    let reference_start = close + 2
    let reference_close = match
      markdown_editor_find_unescaped_char(chars, reference_start, ']') {
      Some(index) => index
      None => return None
    }
    if reference_close != chars.length() - 1 {
      return None
    }
    let explicit = markdown_editor_markdown_reference_label_token(
      String::from_array(chars[reference_start:reference_close]),
    )
    let target = if explicit == "" {
      markdown_editor_markdown_reference_label_token(
        String::from_array(chars[label_start:close]),
      )
    } else {
      explicit
    }
    if target == "" {
      return None
    }
    return Some({ target, image, reference_style: true })
  }
  if close + 2 >= chars.length() ||
    chars[close + 1] != '(' ||
    chars[chars.length() - 1] != ')' ||
    markdown_editor_char_is_escaped(chars, chars.length() - 1) {
    return None
  }
  let target = markdown_editor_markdown_reference_target_token(
    String::from_array(chars[close + 2:chars.length() - 1]),
  )
  if target == "" {
    return None
  }
  if image && !markdown_editor_is_image_source(target) {
    return None
  }
  Some({ target, image, reference_style: false })
}

///|
fn markdown_editor_markdown_reference_target_token(raw : String) -> String {
  let text = raw.trim().to_owned()
  if text == "" || text.contains("\n") {
    return ""
  }
  let chars = text.to_array()
  if chars[0] == '<' {
    match markdown_editor_find_unescaped_char(chars, 1, '>') {
      Some(close) =>
        if close == 1 {
          ""
        } else {
          String::from_array(chars[1:close])
        }
      None => ""
    }
  } else {
    let token : Array[Char] = []
    let mut index = 0
    while index < chars.length() && chars[index] != ' ' && chars[index] != '\t' {
      token.push(chars[index])
      index = index + 1
    }
    String::from_array(token)
  }
}

///|
fn markdown_editor_markdown_reference_label_token(raw : String) -> String {
  let text = raw.trim().to_owned()
  if text == "" || text.contains("\n") {
    ""
  } else {
    text
  }
}

///|
fn markdown_editor_paste_reference_label_over_selection(
  source : String,
  range : @core.TextRange,
  paste : MarkdownEditorPasteReferenceCommand,
) -> RichTextInputTransform? {
  let image = match paste.command {
    SetImageTarget(_) => true
    _ => false
  }
  let selection : MarkdownEditorSelection = {
    caret: range.end,
    selection: Some(range),
  }
  let context = if image {
    markdown_editor_image_context(source, selection)
  } else {
    markdown_editor_link_context(source, selection)
  }
  match context {
    Some(context) =>
      Some(
        markdown_editor_reference_label_transform(
          source,
          context.range,
          context.bounds.open_start,
          markdown_editor_reference_bounds_full_end(context.bounds),
          paste.target,
          paste.definition_text,
          image~,
        ),
      )
    None => {
      let normalized = range.normalized()
      Some(
        markdown_editor_reference_label_transform(
          source,
          normalized,
          normalized.start,
          normalized.end,
          paste.target,
          paste.definition_text,
          image~,
        ),
      )
    }
  }
}

///|
fn markdown_editor_reference_label_transform(
  source : String,
  visible_range : @core.TextRange,
  replace_start : Int,
  replace_end : Int,
  label : String,
  definition_text : String,
  image~ : Bool,
) -> RichTextInputTransform {
  let source_length = markdown_editor_text_length(source)
  let start = markdown_editor_clamp_int(replace_start, 0, source_length)
  let end = markdown_editor_clamp_int(replace_end, start, source_length)
  let visible_start = markdown_editor_clamp_int(visible_range.start, start, end)
  let visible_end = markdown_editor_clamp_int(
    visible_range.end,
    visible_start,
    end,
  )
  let selected = markdown_editor_substring(source, visible_start, visible_end)
  let prefix = if image { "![" } else { "[" }
  let inserted = prefix + selected + "][" + label + "]"
  let next_selection = @core.TextRange::new(
    start=start + markdown_editor_text_length(prefix),
    end=start +
      markdown_editor_text_length(prefix) +
      markdown_editor_text_length(selected),
  )
  let base_text = markdown_editor_substring(source, 0, start) +
    inserted +
    markdown_editor_substring(source, end, source_length)
  let text = markdown_editor_append_pasted_reference_definition(
    base_text, source, label, definition_text,
  )
  markdown_editor_transform_result(
    text~,
    caret=next_selection.end,
    selection=Some(next_selection),
  )
}

///|
fn markdown_editor_append_pasted_reference_definition(
  text : String,
  original_source : String,
  label : String,
  definition_text : String,
) -> String {
  if definition_text == "" ||
    markdown_editor_reference_definition_target_range(original_source, label)
    is Some(_) {
    text
  } else {
    text +
    markdown_editor_reference_definition_append_prefix(text) +
    definition_text
  }
}

///|
fn markdown_editor_reference_bounds_full_end(
  bounds : MarkdownLinkBounds,
) -> Int {
  markdown_editor_max_int(bounds.close_start, bounds.target_end) + 1
}

///|
fn markdown_editor_find_unescaped_char(
  chars : Array[Char],
  start : Int,
  target : Char,
) -> Int? {
  let mut index = start
  while index < chars.length() {
    if chars[index] == target && !markdown_editor_char_is_escaped(chars, index) {
      return Some(index)
    }
    index = index + 1
  }
  None
}

///|
fn markdown_editor_char_is_escaped(chars : Array[Char], index : Int) -> Bool {
  let mut slash_count = 0
  let mut cursor = index - 1
  while cursor >= 0 && chars[cursor] == '\\' {
    slash_count = slash_count + 1
    cursor = cursor - 1
  }
  slash_count % 2 == 1
}

///|
fn markdown_editor_is_image_source(text : String) -> Bool {
  if text.contains("\n") || text.contains(" ") || text == "" {
    return false
  }
  let lower = text.to_lower()
  markdown_editor_has_image_extension(lower)
}

///|
fn markdown_editor_has_image_extension(text : String) -> Bool {
  for ext in [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp", ".avif"] {
    if text.contains(ext) {
      return true
    }
  }
  false
}

///|
fn markdown_editor_is_plain_url(text : String) -> Bool {
  (text.has_prefix("https://") || text.has_prefix("http://")) &&
  !text.contains("\n") &&
  !text.contains(" ") &&
  markdown_editor_text_length(text) > markdown_editor_text_length("https://")
}

///|
fn markdown_editor_is_autolink_target(text : String) -> Bool {
  markdown_editor_is_plain_url(text) || markdown_editor_is_plain_email(text)
}

///|
fn markdown_editor_is_plain_email(text : String) -> Bool {
  if text == "" ||
    text.contains("\n") ||
    text.contains(" ") ||
    text.contains("<") ||
    text.contains(">") {
    return false
  }
  let chars = text.to_array()
  let mut at_index = -1
  for index in 0..= 0 {
        return false
      }
      at_index = index
    }
  }
  if at_index <= 0 || at_index + 1 >= chars.length() {
    return false
  }
  let local_name = String::from_array(chars[:at_index])
  let domain = String::from_array(chars[at_index + 1:])
  markdown_editor_email_part_supported(local_name, local_part=true) &&
  markdown_editor_email_part_supported(domain, local_part=false) &&
  markdown_editor_email_domain_has_dot(domain)
}

///|
fn markdown_editor_email_part_supported(
  text : String,
  local_part~ : Bool,
) -> Bool {
  if text == "" || text.has_prefix(".") || text.has_suffix(".") {
    return false
  }
  let chars = text.to_array()
  let mut previous_dot = false
  for ch in chars {
    if ch == '.' {
      if previous_dot {
        return false
      }
      previous_dot = true
    } else if markdown_editor_email_char_supported(ch, local_part~) {
      previous_dot = false
    } else {
      return false
    }
  }
  true
}

///|
fn markdown_editor_email_char_supported(ch : Char, local_part~ : Bool) -> Bool {
  markdown_editor_ascii_word_char(ch) ||
  ch == '-' ||
  (local_part && (ch == '+' || ch == '%'))
}

///|
fn markdown_editor_email_domain_has_dot(domain : String) -> Bool {
  let chars = domain.to_array()
  for index in 1..<(chars.length() - 1) {
    if chars[index] == '.' {
      return true
    }
  }
  false
}