<commit_before>Point = require 'point'
Range = require 'range'
_ = require 'underscore'

# Internal: Responsible for doing the translations between screen positions and buffer positions.
module.exports =
class LineMap
  maxScreenLineLength: 0

  constructor: ->
    @screenLines = []

  insertAtScreenRow: (bufferRow, screenLines) ->
    @spliceAtScreenRow(bufferRow, 0, screenLines)

  replaceScreenRows: (start, end, screenLines) ->
    @spliceAtScreenRow(start, end - start + 1, screenLines)

  spliceAtScreenRow: (startRow, rowCount, screenLines) ->
    maxLengthCandidates =  screenLines
    for screenLine in @screenLines[startRow...startRow+rowCount]
      if screenLine.text.length == @maxScreenLineLength
        @maxScreenLineLength = 0
        maxLengthCandidates = @screenLines

    _.spliceWithArray(@screenLines, startRow, rowCount, screenLines)

    for screenLine in maxLengthCandidates
      @maxScreenLineLength = Math.max(@maxScreenLineLength, screenLine.text.length)

  # Public: Gets the line for the given screen row.
  #
  # screenRow - A {Number} indicating the screen row.
  #
  # Returns a {ScreenLine}.
  lineForScreenRow: (row) ->
    @screenLines[row]

  # Public: Gets the lines for the given screen row boundaries.
  #
  # start - A {Number} indicating the beginning screen row.
  # end - A {Number} indicating the ending screen row.
  #
  # Returns an {Array} of {ScreenLine}s.
  linesForScreenRows: (startRow, endRow) ->
    @screenLines[startRow..endRow]

  # Public: Given starting and ending screen rows, this returns an array of the
  # buffer rows corresponding to every screen row in the range
  #
  # startRow - The screen row {Number} to start at
  # endRow - The screen row {Integer} to end at (default: {.lastScreenRow})
  #
  # Returns an {Array} of buffer rows as {Integers}s.
  bufferRowsForScreenRows: (startRow, endRow=@lastScreenRow()) ->
    bufferRows = []
    bufferRow = 0
    for screenLine, screenRow in @screenLines
      break if screenRow > endRow
      bufferRows.push(bufferRow) if screenRow >= startRow
      bufferRow += screenLine.bufferRows

    bufferRows

  getScreenLineCount: ->
    @screenLines.length

  # Retrieves the last screen row in the buffer.
  #
  # Returns an {Integer}.
  lastScreenRow: ->
    @getScreenLineCount() - 1

  clipScreenPosition: (screenPosition, options={}) ->
    { wrapBeyondNewlines, wrapAtSoftNewlines } = options
    { row, column } = Point.fromObject(screenPosition)

    if row < 0
      row = 0
      column = 0
    else if row > @lastScreenRow()
      row = @lastScreenRow()
      column = Infinity
    else if column < 0
      column = 0

    screenLine = options.screenLine ? @lineForScreenRow(row)
    maxScreenColumn = screenLine.getMaxScreenColumn()

    if screenLine.isSoftWrapped() and column >= maxScreenColumn
      if wrapAtSoftNewlines
        row++
        column = 0
      else
        column = screenLine.clipScreenColumn(maxScreenColumn - 1)
    else if wrapBeyondNewlines and column > maxScreenColumn and row < @lastScreenRow()
      row++
      column = 0
    else
      column = screenLine.clipScreenColumn(column, options)
    new Point(row, column)

  # Public: Given a buffer position, this converts it into a screen position.
  #
  # bufferPosition - An object that represents a buffer position. It can be either
  #                  an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
  # options - The same options available to {.clipScreenPosition}.
  #
  # Returns a {Point}.
  screenPositionForBufferPosition: (bufferPosition, options={}) ->
    { row, column } = Point.fromObject(bufferPosition)
    [screenRow, screenLines] = @screenRowAndScreenLinesForBufferRow(row)
    for screenLine in screenLines
      maxBufferColumn = screenLine.getMaxBufferColumn()
      if screenLine.isSoftWrapped() and column > maxBufferColumn
        screenRow++
      else
        if column <= maxBufferColumn
          screenColumn = screenLine.screenColumnForBufferColumn(column)
        else
          screenColumn = Infinity
        break

    options.screenLine = screenLine
    @clipScreenPosition([screenRow, screenColumn], options)

  screenRowAndScreenLinesForBufferRow: (bufferRow) ->
    screenLines = []
    screenRow = 0
    currentBufferRow = 0
    for screenLine in @screenLines
      nextBufferRow = currentBufferRow + screenLine.bufferRows
      if currentBufferRow > bufferRow
        break
      else if currentBufferRow == bufferRow or currentBufferRow <= bufferRow < nextBufferRow
        screenLines.push(screenLine)
      else
        screenRow++
      currentBufferRow = nextBufferRow

    [screenRow, screenLines]

  # Public: Given a buffer range, this converts it into a screen position.
  #
  # screenPosition - An object that represents a buffer position. It can be either
  #                  an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
  # options - The same options available to {.clipScreenPosition}.
  #
  # Returns a {Point}.
  bufferPositionForScreenPosition: (screenPosition, options) ->
    { row, column } = @clipScreenPosition(Point.fromObject(screenPosition), options)
    [bufferRow, screenLine] = @bufferRowAndScreenLineForScreenRow(row)
    bufferColumn = screenLine.bufferColumnForScreenColumn(column)
    new Point(bufferRow, bufferColumn)

  bufferRowAndScreenLineForScreenRow: (screenRow) ->
    bufferRow = 0
    for screenLine, currentScreenRow in @screenLines
      if currentScreenRow == screenRow
        break
      else
        bufferRow += screenLine.bufferRows

    [bufferRow, screenLine]

  # Public: Given a buffer range, this converts it into a screen position.
  #
  # bufferRange - The {Range} to convert
  #
  # Returns a {Range}.
  screenRangeForBufferRange: (bufferRange) ->
    bufferRange = Range.fromObject(bufferRange)
    start = @screenPositionForBufferPosition(bufferRange.start)
    end = @screenPositionForBufferPosition(bufferRange.end)
    new Range(start, end)

  # Public: Given a screen range, this converts it into a buffer position.
  #
  # screenRange - The {Range} to convert
  #
  # Returns a {Range}.
  bufferRangeForScreenRange: (screenRange) ->
    screenRange = Range.fromObject(screenRange)
    start = @bufferPositionForScreenPosition(screenRange.start)
    end = @bufferPositionForScreenPosition(screenRange.end)
    new Range(start, end)

  # Internal:
  logLines: (start=0, end=@screenLineCount() - 1)->
    for row in [start..end]
      line = @lineForScreenRow(row).text
      console.log row, line, line.length<commit_msg>Fix method missing exception in LineMap.logLines<commit_after>Point = require 'point'
Range = require 'range'
_ = require 'underscore'

# Internal: Responsible for doing the translations between screen positions and buffer positions.
module.exports =
class LineMap
  maxScreenLineLength: 0

  constructor: ->
    @screenLines = []

  insertAtScreenRow: (bufferRow, screenLines) ->
    @spliceAtScreenRow(bufferRow, 0, screenLines)

  replaceScreenRows: (start, end, screenLines) ->
    @spliceAtScreenRow(start, end - start + 1, screenLines)

  spliceAtScreenRow: (startRow, rowCount, screenLines) ->
    maxLengthCandidates =  screenLines
    for screenLine in @screenLines[startRow...startRow+rowCount]
      if screenLine.text.length == @maxScreenLineLength
        @maxScreenLineLength = 0
        maxLengthCandidates = @screenLines

    _.spliceWithArray(@screenLines, startRow, rowCount, screenLines)

    for screenLine in maxLengthCandidates
      @maxScreenLineLength = Math.max(@maxScreenLineLength, screenLine.text.length)

  # Public: Gets the line for the given screen row.
  #
  # screenRow - A {Number} indicating the screen row.
  #
  # Returns a {ScreenLine}.
  lineForScreenRow: (row) ->
    @screenLines[row]

  # Public: Gets the lines for the given screen row boundaries.
  #
  # start - A {Number} indicating the beginning screen row.
  # end - A {Number} indicating the ending screen row.
  #
  # Returns an {Array} of {ScreenLine}s.
  linesForScreenRows: (startRow, endRow) ->
    @screenLines[startRow..endRow]

  # Public: Given starting and ending screen rows, this returns an array of the
  # buffer rows corresponding to every screen row in the range
  #
  # startRow - The screen row {Number} to start at
  # endRow - The screen row {Integer} to end at (default: {.lastScreenRow})
  #
  # Returns an {Array} of buffer rows as {Integers}s.
  bufferRowsForScreenRows: (startRow, endRow=@lastScreenRow()) ->
    bufferRows = []
    bufferRow = 0
    for screenLine, screenRow in @screenLines
      break if screenRow > endRow
      bufferRows.push(bufferRow) if screenRow >= startRow
      bufferRow += screenLine.bufferRows

    bufferRows

  getScreenLineCount: ->
    @screenLines.length

  # Retrieves the last screen row in the buffer.
  #
  # Returns an {Integer}.
  lastScreenRow: ->
    @getScreenLineCount() - 1

  clipScreenPosition: (screenPosition, options={}) ->
    { wrapBeyondNewlines, wrapAtSoftNewlines } = options
    { row, column } = Point.fromObject(screenPosition)

    if row < 0
      row = 0
      column = 0
    else if row > @lastScreenRow()
      row = @lastScreenRow()
      column = Infinity
    else if column < 0
      column = 0

    screenLine = options.screenLine ? @lineForScreenRow(row)
    maxScreenColumn = screenLine.getMaxScreenColumn()

    if screenLine.isSoftWrapped() and column >= maxScreenColumn
      if wrapAtSoftNewlines
        row++
        column = 0
      else
        column = screenLine.clipScreenColumn(maxScreenColumn - 1)
    else if wrapBeyondNewlines and column > maxScreenColumn and row < @lastScreenRow()
      row++
      column = 0
    else
      column = screenLine.clipScreenColumn(column, options)
    new Point(row, column)

  # Public: Given a buffer position, this converts it into a screen position.
  #
  # bufferPosition - An object that represents a buffer position. It can be either
  #                  an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
  # options - The same options available to {.clipScreenPosition}.
  #
  # Returns a {Point}.
  screenPositionForBufferPosition: (bufferPosition, options={}) ->
    { row, column } = Point.fromObject(bufferPosition)
    [screenRow, screenLines] = @screenRowAndScreenLinesForBufferRow(row)
    for screenLine in screenLines
      maxBufferColumn = screenLine.getMaxBufferColumn()
      if screenLine.isSoftWrapped() and column > maxBufferColumn
        screenRow++
      else
        if column <= maxBufferColumn
          screenColumn = screenLine.screenColumnForBufferColumn(column)
        else
          screenColumn = Infinity
        break

    options.screenLine = screenLine
    @clipScreenPosition([screenRow, screenColumn], options)

  screenRowAndScreenLinesForBufferRow: (bufferRow) ->
    screenLines = []
    screenRow = 0
    currentBufferRow = 0
    for screenLine in @screenLines
      nextBufferRow = currentBufferRow + screenLine.bufferRows
      if currentBufferRow > bufferRow
        break
      else if currentBufferRow == bufferRow or currentBufferRow <= bufferRow < nextBufferRow
        screenLines.push(screenLine)
      else
        screenRow++
      currentBufferRow = nextBufferRow

    [screenRow, screenLines]

  # Public: Given a buffer range, this converts it into a screen position.
  #
  # screenPosition - An object that represents a buffer position. It can be either
  #                  an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
  # options - The same options available to {.clipScreenPosition}.
  #
  # Returns a {Point}.
  bufferPositionForScreenPosition: (screenPosition, options) ->
    { row, column } = @clipScreenPosition(Point.fromObject(screenPosition), options)
    [bufferRow, screenLine] = @bufferRowAndScreenLineForScreenRow(row)
    bufferColumn = screenLine.bufferColumnForScreenColumn(column)
    new Point(bufferRow, bufferColumn)

  bufferRowAndScreenLineForScreenRow: (screenRow) ->
    bufferRow = 0
    for screenLine, currentScreenRow in @screenLines
      if currentScreenRow == screenRow
        break
      else
        bufferRow += screenLine.bufferRows

    [bufferRow, screenLine]

  # Public: Given a buffer range, this converts it into a screen position.
  #
  # bufferRange - The {Range} to convert
  #
  # Returns a {Range}.
  screenRangeForBufferRange: (bufferRange) ->
    bufferRange = Range.fromObject(bufferRange)
    start = @screenPositionForBufferPosition(bufferRange.start)
    end = @screenPositionForBufferPosition(bufferRange.end)
    new Range(start, end)

  # Public: Given a screen range, this converts it into a buffer position.
  #
  # screenRange - The {Range} to convert
  #
  # Returns a {Range}.
  bufferRangeForScreenRange: (screenRange) ->
    screenRange = Range.fromObject(screenRange)
    start = @bufferPositionForScreenPosition(screenRange.start)
    end = @bufferPositionForScreenPosition(screenRange.end)
    new Range(start, end)

  # Internal:
  logLines: (start=0, end=@getScreenLineCount() - 1)->
    for row in [start..end]
      line = @lineForScreenRow(row).text
      console.log row, line, line.length
{'fraction_non_alphanumeric': 0.09029567854435178, 'fraction_numerical': 0.0028809704321455646, 'mean_word_length': 3.4014014014014013, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 51, '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': '6165690', 'n_tokens_mistral': 3809, 'n_tokens_neox': 3682, 'n_words': 1098}