<commit_before>_         = require('lodash')
dom       = require('./lib/dom')
Parchment = require('parchment')


class Range
  constructor: (@start, @end) ->

  shift: (index, length) ->
    [@start, @end] = _.map([@start, @end], (pos) ->
      return pos if index > pos
      if length >= 0
        return pos + length
      else
        return Math.max(index, pos + length)
    )

  isCollapsed: ->
    return @start == @end


class Selection
  @Range: Range

  constructor: (@doc, @emitter) ->
    @root = @doc.domNode
    @range = new Range(0, 0)
    this.update(@emitter.constructor.sources.SILENT)

  checkFocus: ->
    return document.activeElement == @root

  focus: ->
    if @range?
      this.setRange(@range)
    else
      @root.focus()

  prepare: (format, value) ->
    return unless this.checkFocus()
    nativeRange = this._getNativeRange()
    console.log(format, value)

  getBounds: (index) ->
    pos = _.last(@doc.findPath(index))      # TODO inclusive
    return null unless pos?
    leafNode = pos.blot.domNode
    containerBounds = @root.parentNode.getBoundingClientRect()
    range = document.createRange()
    if pos.offset < pos.blot.getLength()
      range.setStart(leafNode, pos.offset)
      range.setEnd(leafNode, pos.offset + 1)
      side = 'left'
    else
      range.setStart(leafNode, pos.offset - 1)
      range.setEnd(leafNode, pos.offset)
      side = 'right'
    bounds = range.getBoundingClientRect()
    return {
      height: bounds.height
      left: bounds[side] - containerBounds.left
      top: bounds.top - containerBounds.top
    }

  getRange: (ignoreFocus = false) ->
    if this.checkFocus()
      nativeRange = this._getNativeRange()
      return null unless nativeRange?
      start = this._positionToIndex(nativeRange.startContainer, nativeRange.startOffset)
      if nativeRange.startContainer == nativeRange.endContainer and nativeRange.startOffset == nativeRange.endOffset
        end = start
      else
        end = this._positionToIndex(nativeRange.endContainer, nativeRange.endOffset)
      return new Range(Math.min(start, end), Math.max(start, end)) # Handle backwards ranges
    else if ignoreFocus
      return @range
    else
      return null

  onUpdate: (range) ->

  preserve: (fn) ->
    nativeRange = this._getNativeRange()
    if nativeRange? and this.checkFocus()
      [startNode, startOffset] = this._encodePosition(nativeRange.startContainer, nativeRange.startOffset)
      [endNode, endOffset] = this._encodePosition(nativeRange.endContainer, nativeRange.endOffset)
      fn()
      [startNode, startOffset] = this._decodePosition(startNode, startOffset)
      [endNode, endOffset] = this._decodePosition(endNode, endOffset)
      this._setNativeRange(startNode, startOffset, endNode, endOffset)
    else
      fn()

  scrollIntoView: () ->
    return unless @range
    editor = @emitter.editor
    startBounds = editor.getBounds(@range.start)
    endBounds = if @range.isCollapsed() then startBounds else editor.getBounds(@range.end)
    containerBounds = editor.root.parentNode.getBoundingClientRect()
    containerHeight = containerBounds.bottom - containerBounds.top
    if containerHeight < endBounds.top + endBounds.height
      [line, offset] = editor.doc.findLineAt(@range.end)
      line.node.scrollIntoView(false)
    else if startBounds.top < 0
      [line, offset] = editor.doc.findLineAt(@range.start)
      line.node.scrollIntoView()

  setRange: (range, source) ->
    if range?
      [startNode, startOffset] = this._indexToPosition(range.start)
      if range.isCollapsed()
        [endNode, endOffset] = [startNode, startOffset]
      else
        [endNode, endOffset] = this._indexToPosition(range.end)
      this._setNativeRange(startNode, startOffset, endNode, endOffset)
    else
      this._setNativeRange(null)
    this.update(source)

  shiftAfter: (index, length, fn) ->
    range = this.getRange()
    fn()
    if range?
      range.shift(index, length)
      this.setRange(range, 'silent')

  update: (source) ->
    focus = this.checkFocus()
    range = this.getRange(true)
    @range = range
    @emitter.emit(@emitter.constructor.events.SELECTION_CHANGE, toEmit, source) if emit
<commit_msg>code cleanup<commit_after>_         = require('lodash')
dom       = require('./lib/dom')
Parchment = require('parchment')


class Range
  constructor: (@start, @end) ->

  shift: (index, length) ->
    [@start, @end] = _.map([@start, @end], (pos) ->
      return pos if index > pos
      if length >= 0
        return pos + length
      else
        return Math.max(index, pos + length)
    )

  isCollapsed: ->
    return @start == @end


class Selection
  @Range: Range

  constructor: (@doc, @emitter) ->
    @root = @doc.domNode
    @range = new Range(0, 0)
    this.update(@emitter.constructor.sources.SILENT)

  checkFocus: ->
    return document.activeElement == @root

  focus: ->
    if @range?
      this.setRange(@range)
    else
      @root.focus()

  prepare: (format, value) ->
    return unless this.checkFocus()
    nativeRange = this._getNativeRange()
    console.log(format, value)

  getBounds: (index) ->
    pos = _.last(@doc.findPath(index))      # TODO inclusive
    return null unless pos?
    leafNode = pos.blot.domNode
    containerBounds = @root.parentNode.getBoundingClientRect()
    range = document.createRange()
    if pos.offset < pos.blot.getLength()
      range.setStart(leafNode, pos.offset)
      range.setEnd(leafNode, pos.offset + 1)
      side = 'left'
    else
      range.setStart(leafNode, pos.offset - 1)
      range.setEnd(leafNode, pos.offset)
      side = 'right'
    bounds = range.getBoundingClientRect()
    return {
      height: bounds.height
      left: bounds[side] - containerBounds.left
      top: bounds.top - containerBounds.top
    }

  getRange: (ignoreFocus = false) ->
    if this.checkFocus()
      nativeRange = this._getNativeRange()
      return null unless nativeRange?
      start = this._positionToIndex(nativeRange.startContainer, nativeRange.startOffset)
      if nativeRange.startContainer == nativeRange.endContainer and nativeRange.startOffset == nativeRange.endOffset
        end = start
      else
        end = this._positionToIndex(nativeRange.endContainer, nativeRange.endOffset)
      return new Range(Math.min(start, end), Math.max(start, end)) # Handle backwards ranges
    else if ignoreFocus
      return @range
    else
      return null

  onUpdate: (range) ->

  preserve: (fn) ->
    nativeRange = this._getNativeRange()
    if nativeRange? and this.checkFocus()
      [startNode, startOffset] = this._encodePosition(nativeRange.startContainer, nativeRange.startOffset)
      [endNode, endOffset] = this._encodePosition(nativeRange.endContainer, nativeRange.endOffset)
      fn()
      [startNode, startOffset] = this._decodePosition(startNode, startOffset)
      [endNode, endOffset] = this._decodePosition(endNode, endOffset)
      this._setNativeRange(startNode, startOffset, endNode, endOffset)
    else
      fn()

  scrollIntoView: () ->
    return unless @range
    startBounds = this.getBounds(@range.start)
    endBounds = if @range.isCollapsed() then startBounds else this.getBounds(@range.end)
    containerBounds = @root.parentNode.getBoundingClientRect()
    containerHeight = containerBounds.bottom - containerBounds.top
    if containerHeight < endBounds.top + endBounds.height
      [line, offset] = @doc.findLineAt(@range.end)
      line.node.scrollIntoView(false)
    else if startBounds.top < 0
      [line, offset] = @doc.findLineAt(@range.start)
      line.node.scrollIntoView()

  setRange: (range, source) ->
    if range?
      [startNode, startOffset] = this._indexToPosition(range.start)
      if range.isCollapsed()
        [endNode, endOffset] = [startNode, startOffset]
      else
        [endNode, endOffset] = this._indexToPosition(range.end)
      this._setNativeRange(startNode, startOffset, endNode, endOffset)
    else
      this._setNativeRange(null)
    this.update(source)

  shiftAfter: (index, length, fn) ->
    range = this.getRange()
    fn()
    if range?
      range.shift(index, length)
      this.setRange(range, 'silent')

  update: (source) ->
    focus = this.checkFocus()
    range = this.getRange(true)
    @range = range
    @emitter.emit(@emitter.constructor.events.SELECTION_CHANGE, toEmit, source) if emit

{'fraction_non_alphanumeric': 0.11673850574712644, 'fraction_numerical': 0.0014367816091954023, 'mean_word_length': 3.0966159882295243, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 39, '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': '4361572', 'n_tokens_mistral': 2538, 'n_tokens_neox': 2490, 'n_words': 561}