<commit_before>class AsciiIo.TerminalView extends Backbone.View
  tagName: 'pre'
  className: 'terminal'

  initialize: (options) ->
    @cols = options.cols
    @lines = options.lines

    @createChildElements()
    @showCursor true
    @startCursorBlink()
    # this.updateScreen();
    # this.render();
    #
    # this.renderLine(0); // we only need 1 line
    # this.element.css({ width: this.element.width(), height: this.element.height() });

  createChildElements: ->
    i = 0

    while i < @lines
      row = $("<span class=\"line\">")
      @$el.append row
      @$el.append "\n"
      i++

  clearScreen: ->
    # this.lineData.length = 0;
    # @cursorY = @cursorX = 0
    @$el.find(".line").empty()

  render: (changes, cursorX, cursorY) ->
    @$el.find('.cursor').removeClass('cursor')

    for n, data of changes
      c = if parseInt(n) is cursorY then cursorX else undefined
      @renderLine n, data || [], c

  renderLine: (n, data, cursorX) ->
    html = []
    i = 0

    for d in data
      if d
        [char, brush] = d
        html[i] = @createSpan(char, brush, i is cursorX)
      else
        html[i] = ' '
      i++

    @$el.find(".line:eq(" + n + ")").html html.join("")

  createSpan: (char, brush, hasCursor) ->
    prefix = ""
    postfix = ""

    if hasCursor or brush.fg isnt undefined or brush.bg isnt undefined or brush.bright or brush.underline
      prefix = "<span class=\""
      brightOffset = (if brush.bright then 8 else 0)

      if brush.fg isnt undefined
        prefix += " fg" + (brush.fg + brightOffset)
      else if brush.bright
        prefix += " bright"

      if brush.underline
        prefix += " underline"

      prefix += " bg" + brush.bg if brush.bg isnt undefined
      prefix += " cursor visible" if hasCursor
      prefix += "\">"
      postfix = "</span>"

    prefix + char + postfix

  showCursor: (show) ->
    if show
      @$el.addClass "cursor-on"
    else
      @$el.removeClass "cursor-on"

  blinkCursor: ->
    cursor = @$el.find(".cursor")
    if cursor.hasClass("visible")
      cursor.removeClass "visible"
    else
      cursor.addClass "visible"

  resetCursorState: ->
    cursor = @$el.find(".cursor")
    cursor.addClass "visible"

  startCursorBlink: ->
    @cursorTimerId = setInterval(@blinkCursor.bind(this), 500)

  stopCursorBlink: ->
    if @cursorTimerId
      clearInterval @cursorTimerId
      @cursorTimerId = null

  restartCursorBlink: ->
    @stopCursorBlink()
    @resetCursorState()
    @startCursorBlink()

  visualBell: ->
<commit_msg>Orders of magnitude faster rendering<commit_after>class AsciiIo.TerminalView extends Backbone.View
  tagName: 'pre'
  className: 'terminal'

  initialize: (options) ->
    @cols = options.cols
    @lines = options.lines

    @createChildElements()
    @showCursor true
    @startCursorBlink()
    # this.updateScreen();
    # this.render();
    #
    # this.renderLine(0); // we only need 1 line
    # this.element.css({ width: this.element.width(), height: this.element.height() });

  createChildElements: ->
    i = 0

    while i < @lines
      row = $("<span class=\"line\">")
      @$el.append row
      @$el.append "\n"
      i++

  clearScreen: ->
    # this.lineData.length = 0;
    # @cursorY = @cursorX = 0
    @$el.find(".line").empty()

  render: (changes, cursorX, cursorY) ->
    @$el.find('.cursor').removeClass('cursor')

    for n, data of changes
      c = if parseInt(n) is cursorY then cursorX else undefined
      @renderLine n, data || [], c

  renderLine: (n, data, cursorX) ->
    html = ''
    i = 0
    prevBrush = undefined

    for d in data
      if d
        [char, brush] = d

        if brush != prevBrush or i is cursorX or i is (cursorX + 1)
          if prevBrush
            html += '</span>'

          html += @createSpan(brush, i is cursorX)

          prevBrush = brush

        html += char
      else
        html += ' '
      i++

    html += '</span>' if html.length > 0

    @$el.find(".line:eq(" + n + ")").html html #.join("")

  createSpan: (brush, hasCursor) ->
    span = ""

    if hasCursor or brush.fg isnt undefined or brush.bg isnt undefined or brush.bright or brush.underline
      span = "<span class=\""
      brightOffset = (if brush.bright then 8 else 0)

      if brush.fg isnt undefined
        span += " fg" + (brush.fg + brightOffset)
      else if brush.bright
        span += " bright"

      if brush.underline
        span += " underline"

      span += " bg" + brush.bg if brush.bg isnt undefined
      span += " cursor visible" if hasCursor
      span += "\">"

    span

  showCursor: (show) ->
    if show
      @$el.addClass "cursor-on"
    else
      @$el.removeClass "cursor-on"

  blinkCursor: ->
    cursor = @$el.find(".cursor")
    if cursor.hasClass("visible")
      cursor.removeClass "visible"
    else
      cursor.addClass "visible"

  resetCursorState: ->
    cursor = @$el.find(".cursor")
    cursor.addClass "visible"

  startCursorBlink: ->
    @cursorTimerId = setInterval(@blinkCursor.bind(this), 500)

  stopCursorBlink: ->
    if @cursorTimerId
      clearInterval @cursorTimerId
      @cursorTimerId = null

  restartCursorBlink: ->
    @stopCursorBlink()
    @resetCursorState()
    @startCursorBlink()

  visualBell: ->

{'fraction_non_alphanumeric': 0.14095491725318623, 'fraction_numerical': 0.00456534144949591, 'mean_word_length': 2.3405336721728083, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 37, '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': '7316032', 'n_tokens_mistral': 1722, 'n_tokens_neox': 1642, 'n_words': 443}