<commit_before>import * as style from "./style"

const render = Object.create(null), renderStyle = Object.create(null)

let doc = null

export default function toDOM(node, options) {
  doc = options.document
  return renderNodes(node.content, options)
}

toDOM.renderNode = renderNode

function elt(name, ...children) {
  let dom = doc.createElement(name)
  for (let i = 0; i < children.length; i++) {
    let child = children[i]
    dom.appendChild(typeof child == "string" ? doc.createTextNode(child) : child)
  }
  return dom
}

function wrap(node, options, type) {
  let dom = elt(type || node.type.name)
  if (node.type.contains != "inline")
    renderNodesInto(node.content, dom, options)
  else if (options.renderInlineFlat)
    renderInlineContentFlat(node.content, dom, options)
  else
    renderInlineContent(node.content, dom, options)
  return dom
}

function wrapIn(type) {
  return function(node, options) { return wrap(node, options, type) }
}

function renderNodes(nodes, options) {
  let frag = doc.createDocumentFragment()
  renderNodesInto(nodes, frag, options)
  return frag
}

function renderNode(node, options, offset) {
  let dom = render[node.type.name](node, options)
  if (options.onRender)
    dom = options.onRender(node, dom, offset) || dom
  return dom
}

function renderNodesInto(nodes, where, options) {
  for (let i = 0; i < nodes.length; i++)
    where.appendChild(renderNode(nodes[i], options, i))
}

function renderInlineContent(nodes, where, options) {
  let top = where
  let active = []
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i], styles = node.styles
    let keep = 0
    for (; keep < Math.min(active.length, styles.length); ++keep)
      if (!style.same(active[keep], styles[keep])) break
    while (keep < active.length) {
      active.pop()
      top = top.parentNode
    }
    while (active.length < styles.length) {
      let add = styles[active.length]
      active.push(add)
      top = top.appendChild(renderStyle[add.type](add))
    }
    top.appendChild(renderNode(node, options, i))
  }
}

function renderInlineContentFlat(nodes, where, options) {
  let offset = 0
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i], styles = node.styles
    let dom = renderNode(node, options, i)
    for (let j = styles.length - 1; j >= 0; j--) {
      let wrap = renderStyle[styles[j].type](styles[j])
      wrap.appendChild(dom)
      dom = wrap
    }
    dom = options.renderInlineFlat(node, dom, offset) || dom
    where.appendChild(dom)
    offset += node.size
  }
}

// Block nodes

render.blockquote = wrap

render.code_block = (node, options) => {
  let code = wrap(node, options, "code")
  if (node.attrs.params != null)
    code.className = "fence " + node.attrs.params.replace(/(^|\s+)/g, "$&lang-")
  return elt("pre", code)
}

render.heading = (node, options) => wrap(node, options, "h" + node.attrs.level)

render.horizontal_rule = node => elt("hr")

render.bullet_list = (node, options) => {
  let dom = wrap(node, options, "ul")
  let bul = node.attrs.bullet
  dom.setAttribute("class", bul == "+" ? "bullet_plus" : bul == "-" ? "bullet_dash" : "bullet_star")
  if (node.attrs.tight) dom.setAttribute("class", "tight")
  return dom
}<commit_msg>Minimally update inline content when redrawing<commit_after>import * as style from "./style"

const render = Object.create(null), renderStyle = Object.create(null)

let doc = null

export default function toDOM(node, options) {
  doc = options.document
  return renderNodes(node.content, options)
}

toDOM.renderNode = function(node, options, offset) {
  let dom = renderNode(node, options, offset)
  if (options.renderInlineFlat && node.type.type == "inline") {
    dom = wrapInlineFlat(node, dom)
    dom = options.renderInlineFlat(node, dom, offset) || dom
  }
  return dom
}

function elt(name, ...children) {
  let dom = doc.createElement(name)
  for (let i = 0; i < children.length; i++) {
    let child = children[i]
    dom.appendChild(typeof child == "string" ? doc.createTextNode(child) : child)
  }
  return dom
}

function wrap(node, options, type) {
  let dom = elt(type || node.type.name)
  if (node.type.contains != "inline")
    renderNodesInto(node.content, dom, options)
  else if (options.renderInlineFlat)
    renderInlineContentFlat(node.content, dom, options)
  else
    renderInlineContent(node.content, dom, options)
  return dom
}

function wrapIn(type) {
  return function(node, options) { return wrap(node, options, type) }
}

function renderNodes(nodes, options) {
  let frag = doc.createDocumentFragment()
  renderNodesInto(nodes, frag, options)
  return frag
}

function renderNode(node, options, offset) {
  let dom = render[node.type.name](node, options)
  if (options.onRender)
    dom = options.onRender(node, dom, offset) || dom
  return dom
}

function renderNodesInto(nodes, where, options) {
  for (let i = 0; i < nodes.length; i++)
    where.appendChild(renderNode(nodes[i], options, i))
}

function renderInlineContent(nodes, where, options) {
  let top = where
  let active = []
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i], styles = node.styles
    let keep = 0
    for (; keep < Math.min(active.length, styles.length); ++keep)
      if (!style.same(active[keep], styles[keep])) break
    while (keep < active.length) {
      active.pop()
      top = top.parentNode
    }
    while (active.length < styles.length) {
      let add = styles[active.length]
      active.push(add)
      top = top.appendChild(renderStyle[add.type](add))
    }
    top.appendChild(renderNode(node, options, i))
  }
}

function wrapInlineFlat(node, dom) {
  let styles = node.styles
  for (let i = styles.length - 1; i >= 0; i--) {
    let wrap = renderStyle[styles[i].type](styles[i])
    wrap.appendChild(dom)
    dom = wrap
  }
  return dom
}

function renderInlineContentFlat(nodes, where, options) {
  let offset = 0
  for (let i = 0; i < nodes.length; i++) {
    let node = nodes[i]
    let dom = wrapInlineFlat(node, renderNode(node, options, i))
    dom = options.renderInlineFlat(node, dom, offset) || dom
    where.appendChild(dom)
    offset += node.size
  }
}

// Block nodes

render.blockquote = wrap

render.code_block = (node, options) => {
  let code = wrap(node, options, "code")
  if (node.attrs.params != null)
    code.className = "fence " + node.attrs.params.replace(/(^|\s+)/g, "$&lang-")
  return elt("pre", code)
}

render.heading = (node, options) => wrap(node, options, "h" + node.attrs.level)

render.horizontal_rule = node => elt("hr")

render.bullet_list = (node, options) => {
  let dom = wrap(node, options, "ul")
  let bul = node.attrs.bullet
  dom.setAttribute("class", bul == "+" ? "bullet_plus" : bul == "-" ? "bullet_dash" : "bullet_star")
  if (node.attrs.tight) dom.setAttribute("class", "tight")
  return dom
}
{'fraction_non_alphanumeric': 0.14748096074985353, 'fraction_numerical': 0.0023432923257176333, 'mean_word_length': 3.6550783912747105, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1001469', 'n_tokens_mistral': 2264, 'n_tokens_neox': 2265, 'n_words': 587}