<commit_before>import Diff from 'fast-diff'
import debounce from 'lodash.debounce'
import peerColor from './peer-color'
import functionQueue from './fn-queue'

const DEBOUNCE_CUSOR_ACTIVITY_MS = 2000

const bindCodeMirror = (doc, titleEditor, editor) => {
  const thisPeerId = doc.app.ipfs._peerInfo.id.toB58String()
  let cursorGossip
  let titleCollab
  let initialised = false
  let locked = false
  let markers = new Map()
  let queue = functionQueue()

  const applyDiffs = (pos, diffs) => {
    diffs.forEach((d) => {
      const [op, text] = d
      if (op === 0) { // EQUAL
        pos += text.length
      } else if (op === -1) { // DELETE
        for (let i = text.length - 1; i >= 0; i--) {
          try {
            doc.shared.removeAt(pos + i)
          } catch (err) {
            console.error(err)
            onStateChanged()
          }
        }
      } else { // INSERT
        doc.shared.insertAllAt(pos, text.split(''))
        pos += text.length
      }
    })
  }

  const onCodeMirrorChange = debounce((editor) => {
    queue.push(() => {
      if (!initialised || locked) {
        return
      }
      const diffs = Diff(doc.shared.value().join(''), editor.getValue())
      applyDiffs(0, diffs)
    })
  })

  editor.on('change', debounce(onCodeMirrorChange, 1000))

  const onStateChanged = (fromSelf) => {
    if (fromSelf) {
      return
    }
    queue.push(() => {
      let oldText = editor.getValue()
      let newText = doc.shared.value().join('')

      if (oldText === newText) {
        return
      }

      locked = true

      const cursor = editor.getCursor()
      let cursorPos = editor.indexFromPos(cursor)

      const diffs = Diff(oldText, newText)
      let pos = 0
      diffs.forEach((d) => {
        const [op, text] = d
        if (op === 0) { // EQUAL
          pos += text.length
        } else if (op === -1) { // DELETE
          if (text.length) {
            const fromPos = editor.posFromIndex(pos)
            fromPos.external = true
            const toPos = editor.posFromIndex(pos + text.length)
            toPos.external = true
            editor.replaceRange('', fromPos, toPos)

            if (pos < cursorPos) {
              cursorPos -= text.length
            }

            moveMarkersIfAfter(pos, -text.length)
          }
        } else { // INSERT
          if (text.length) {
            const fromPos = editor.posFromIndex(pos)
            fromPos.external = true
            editor.replaceRange(text, fromPos)

            if (pos < cursorPos) {
              cursorPos += text.length
            }
            moveMarkersIfAfter(pos, text.length)
          }
        }<commit_msg>Fix for applying diffs against codemirror<commit_after>import Diff from 'fast-diff'
import debounce from 'lodash.debounce'
import peerColor from './peer-color'
import functionQueue from './fn-queue'

const DEBOUNCE_CUSOR_ACTIVITY_MS = 2000

const bindCodeMirror = (doc, titleEditor, editor) => {
  const thisPeerId = doc.app.ipfs._peerInfo.id.toB58String()
  let cursorGossip
  let titleCollab
  let initialised = false
  let locked = false
  let markers = new Map()
  let queue = functionQueue()

  const applyDiffs = (pos, diffs) => {
    diffs.forEach((d) => {
      const [op, text] = d
      if (op === 0) { // EQUAL
        pos += text.length
      } else if (op === -1) { // DELETE
        for (let i = text.length - 1; i >= 0; i--) {
          try {
            doc.shared.removeAt(pos + i)
          } catch (err) {
            console.error(err)
            onStateChanged()
          }
        }
      } else { // INSERT
        doc.shared.insertAllAt(pos, text.split(''))
        pos += text.length
      }
    })
  }

  const onCodeMirrorChange = debounce((editor) => {
    queue.push(() => {
      if (!initialised || locked) {
        return
      }
      const diffs = Diff(doc.shared.value().join(''), editor.getValue())
      applyDiffs(0, diffs)
    })
  })

  editor.on('change', debounce(onCodeMirrorChange, 1000))

  const onStateChanged = (fromSelf) => {
    if (fromSelf) {
      return
    }
    queue.push(() => {
      let oldText = editor.getValue()
      let newText = doc.shared.value().join('')

      if (oldText === newText) {
        return
      }

      locked = true

      const cursor = editor.getCursor()
      let cursorPos = editor.indexFromPos(cursor)

      const diffs = Diff(oldText, newText)
      let pos = 0
      diffs.forEach((d) => {
        const [op, text] = d
        if (op === 0) { // EQUAL
          pos += text.length
        } else if (op === -1) { // DELETE
          if (text.length) {
            const fromPos = editor.posFromIndex(pos)
            fromPos.external = true
            const toPos = editor.posFromIndex(pos + text.length)
            toPos.external = true
            editor.replaceRange('', fromPos, toPos)

            if (pos < cursorPos) {
              cursorPos -= text.length
            }

            moveMarkersIfAfter(pos, -text.length)
          }
        } else { // INSERT
          if (text.length) {
            const fromPos = editor.posFromIndex(pos)
            fromPos.external = true
            editor.replaceRange(text, fromPos)

            if (pos < cursorPos) {
              cursorPos += text.length
            }
            pos += text.length
            moveMarkersIfAfter(pos, text.length)
          }
        }
{'fraction_non_alphanumeric': 0.12720519962859797, 'fraction_numerical': 0.006685236768802228, 'mean_word_length': 1.7762886597938143, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 21, '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': '7184134', 'n_tokens_mistral': 1693, 'n_tokens_neox': 1617, 'n_words': 389}