<commit_before>LinesYardstick = require '../src/lines-yardstick'
LineTopIndex = require 'line-top-index'
{Point} = require 'text-buffer'

describe "LinesYardstick", ->
  [editor, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = []

  beforeEach ->
    waitsForPromise ->
      atom.packages.activatePackage('language-javascript')

    waitsForPromise ->
      atom.workspace.open('sample.js').then (o) -> editor = o

    runs ->
      createdLineNodes = []

      buildLineNode = (screenRow) ->
        startIndex = 0
        scopes = []
        screenLine = editor.screenLineForScreenRow(screenRow)
        lineNode = document.createElement("div")
        lineNode.style.whiteSpace = "pre"
        for tagCode in screenLine.tagCodes when tagCode isnt 0
          if editor.displayLayer.isCloseTagCode(tagCode)
            scopes.pop()
          else if editor.displayLayer.isOpenTagCode(tagCode)
            scopes.push(editor.displayLayer.tagForCode(tagCode))
          else
            text = screenLine.lineText.substr(startIndex, tagCode)
            startIndex += tagCode

            span = document.createElement("span")
            span.className = scopes.join(' ').replace(/\.+/g, ' ')
            span.textContent = text
            lineNode.appendChild(span)
        jasmine.attachToDOM(lineNode)
        createdLineNodes.push(lineNode)
        lineNode

      mockLineNodesProvider =
        lineNodesById: {}

        lineIdForScreenRow: (screenRow) ->
          editor.screenLineForScreenRow(screenRow)?.id

        lineNodeForScreenRow: (screenRow) ->
          if id = @lineIdForScreenRow(screenRow)
            @lineNodesById[id] ?= buildLineNode(screenRow)

        textNodesForScreenRow: (screenRow) ->
          lineNode = @lineNodeForScreenRow(screenRow)
          iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT)
          textNodes = []
          textNodes.push(textNode) while textNode = iterator.nextNode()
          textNodes

      editor.setLineHeightInPixels(14)
      lineTopIndex = new LineTopIndex({defaultLineHeight: editor.getLineHeightInPixels()})
      linesYardstick = new LinesYardstick(editor, mockLineNodesProvider, lineTopIndex, atom.grammars)

  afterEach ->
    lineNode.remove() for lineNode in createdLineNodes
    atom.themes.removeStylesheet('test')

  describe "::pixelPositionForScreenPosition(screenPosition)", ->
    it "converts screen positions to pixel positions", ->
      atom.styles.addStyleSheet """
      * {
        font-size: 12px;
        font-family: monospace;
      }
      .syntax--function {
        font-size: 16px
      }
      """

      expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0))).toEqual({left: 0, top: 0})
      expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1))).toEqual({left: 7, top: 0})
      expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5))).toEqual({left: 38, top: 0})
      if process.platform is 'darwin' # One pixel off on left on Win32
        expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 6))).toEqual({left: 43, top: 14})
        expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 9))).toEqual({left: 72, top: 14})
        expect(linesYardstick.pixelPositionForScreenPosition(Point(2, Infinity))).toEqual({left: 287.859375, top: 28})

    it "reuses already computed pixel positions unless it is invalidated", ->
      atom.styles.addStyleSheet """<commit_msg>Adjust LinesYardstick assertion to reflect removal of redundant leading whitespace span<commit_after>LinesYardstick = require '../src/lines-yardstick'
LineTopIndex = require 'line-top-index'
{Point} = require 'text-buffer'

describe "LinesYardstick", ->
  [editor, mockLineNodesProvider, createdLineNodes, linesYardstick, buildLineNode] = []

  beforeEach ->
    waitsForPromise ->
      atom.packages.activatePackage('language-javascript')

    waitsForPromise ->
      atom.workspace.open('sample.js').then (o) -> editor = o

    runs ->
      createdLineNodes = []

      buildLineNode = (screenRow) ->
        startIndex = 0
        scopes = []
        screenLine = editor.screenLineForScreenRow(screenRow)
        lineNode = document.createElement("div")
        lineNode.style.whiteSpace = "pre"
        for tagCode in screenLine.tagCodes when tagCode isnt 0
          if editor.displayLayer.isCloseTagCode(tagCode)
            scopes.pop()
          else if editor.displayLayer.isOpenTagCode(tagCode)
            scopes.push(editor.displayLayer.tagForCode(tagCode))
          else
            text = screenLine.lineText.substr(startIndex, tagCode)
            startIndex += tagCode

            span = document.createElement("span")
            span.className = scopes.join(' ').replace(/\.+/g, ' ')
            span.textContent = text
            lineNode.appendChild(span)
        jasmine.attachToDOM(lineNode)
        createdLineNodes.push(lineNode)
        lineNode

      mockLineNodesProvider =
        lineNodesById: {}

        lineIdForScreenRow: (screenRow) ->
          editor.screenLineForScreenRow(screenRow)?.id

        lineNodeForScreenRow: (screenRow) ->
          if id = @lineIdForScreenRow(screenRow)
            @lineNodesById[id] ?= buildLineNode(screenRow)

        textNodesForScreenRow: (screenRow) ->
          lineNode = @lineNodeForScreenRow(screenRow)
          iterator = document.createNodeIterator(lineNode, NodeFilter.SHOW_TEXT)
          textNodes = []
          textNodes.push(textNode) while textNode = iterator.nextNode()
          textNodes

      editor.setLineHeightInPixels(14)
      lineTopIndex = new LineTopIndex({defaultLineHeight: editor.getLineHeightInPixels()})
      linesYardstick = new LinesYardstick(editor, mockLineNodesProvider, lineTopIndex, atom.grammars)

  afterEach ->
    lineNode.remove() for lineNode in createdLineNodes
    atom.themes.removeStylesheet('test')

  describe "::pixelPositionForScreenPosition(screenPosition)", ->
    it "converts screen positions to pixel positions", ->
      atom.styles.addStyleSheet """
      * {
        font-size: 12px;
        font-family: monospace;
      }
      .syntax--function {
        font-size: 16px
      }
      """

      expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 0))).toEqual({left: 0, top: 0})
      expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 1))).toEqual({left: 7, top: 0})
      expect(linesYardstick.pixelPositionForScreenPosition(Point(0, 5))).toEqual({left: 38, top: 0})
      if process.platform is 'darwin' # One pixel off on left on Win32
        expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 6))).toEqual({left: 43, top: 14})
        expect(linesYardstick.pixelPositionForScreenPosition(Point(1, 9))).toEqual({left: 72, top: 14})
        expect(linesYardstick.pixelPositionForScreenPosition(Point(2, Infinity))).toEqual({left: 287.875, top: 28})

    it "reuses already computed pixel positions unless it is invalidated", ->
      atom.styles.addStyleSheet """
{'fraction_non_alphanumeric': 0.11024070645207236, 'fraction_numerical': 0.01296111665004985, 'mean_word_length': 3.0896913220733837, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 31, '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': '2992859', 'n_tokens_mistral': 2092, 'n_tokens_neox': 1979, 'n_words': 372}