diff --git a/package.json b/package.json index 31b8bb722..ffe6d30e0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "async": "0.2.6", "atom-keymap": "6.3.2", "babel-core": "^5.8.21", - "binary-search-with-index": "^1.3.0", "bootstrap": "^3.3.4", "cached-run-in-this-context": "0.4.1", "clear-cut": "^2.0.1", diff --git a/src/lines-yardstick.coffee b/src/lines-yardstick.coffee index f865a039c..4642a53a6 100644 --- a/src/lines-yardstick.coffee +++ b/src/lines-yardstick.coffee @@ -1,6 +1,5 @@ {Point} = require 'text-buffer' {isPairedCharacter} = require './text-utils' -binarySearch = require 'binary-search-with-index' module.exports = class LinesYardstick @@ -20,8 +19,8 @@ class LinesYardstick targetTop = pixelPosition.top targetLeft = pixelPosition.left defaultCharWidth = @model.getDefaultCharWidth() - return Point(0, 0) if targetTop < 0 row = @lineTopIndex.rowForPixelPosition(targetTop) + targetLeft = 0 if targetTop < 0 targetLeft = Infinity if row > @model.getLastScreenRow() row = Math.min(row, @model.getLastScreenRow()) row = Math.max(0, row) @@ -33,26 +32,40 @@ class LinesYardstick lineOffset = lineNode.getBoundingClientRect().left targetLeft += lineOffset - textNodeComparator = (textNode, position) => + textNodeIndex = @_binarySearch(textNodes, (textNode) => {length: textNodeLength} = textNode rangeRect = @clientRectForRange(textNode, 0, textNodeLength) - return -1 if rangeRect.right < position - return 1 if rangeRect.left > position + return -1 if rangeRect.right < targetLeft + return 1 if rangeRect.left > targetLeft return 0 + ) - textNodeIndex = binarySearch(textNodes, targetLeft, textNodeComparator) + textNodeStartColumn = 0 if textNodeIndex >= 0 - textNodeStartColumn = textNodes - .slice(0, textNodeIndex) - .reduce(((totalLength, node) -> totalLength + node.length), 0) - charIndex = @charIndexForScreenPosition(textNodes[textNodeIndex], targetLeft) + textNodeStartColumn += textNodes[i].length for i in [0...textNodeIndex] - return Point(row, textNodeStartColumn + charIndex) + textNode = textNodes[textNodeIndex] + {textContent: textNodeContent} = textNode + rangeRect = null + nextCharIndex = -1 - textNodeStartColumn = textNodes - .reduce(((totalLength, node) -> totalLength + node.length), 0) + characterIndex = @_binarySearch(textNodeContent, (char, charIndex) => + if isPairedCharacter(textNodeContent, charIndex) + nextCharIndex = charIndex + 2 + else + nextCharIndex = charIndex + 1 + rangeRect = @clientRectForRange(textNode, charIndex, nextCharIndex) + return -1 if rangeRect.right < targetLeft + return 1 if rangeRect.left > targetLeft + return 0 + ) + if targetLeft <= ((rangeRect.left + rangeRect.right) / 2) + return Point(row, textNodeStartColumn + characterIndex) + return Point(row, textNodeStartColumn + nextCharIndex) + + textNodeStartColumn += node.length for node in textNodes return Point(row, textNodeStartColumn) pixelPositionForScreenPosition: (screenPosition) -> @@ -104,21 +117,17 @@ class LinesYardstick @rangeForMeasurement.setEnd(textNode, endIndex) @rangeForMeasurement.getClientRects()[0] ? @rangeForMeasurement.getBoundingClientRect() - charIndexForScreenPosition: (textNode, targetLeft) -> - {textContent: textNodeContent} = textNode - rangeRect = null - nextCharIndex = -1 - characterComparator = (char, position, charIndex) => - if isPairedCharacter(textNodeContent, charIndex) - nextCharIndex = charIndex + 2 + _binarySearch: (array, compare) -> + low = 0 + high = array.length - 1 + while low <= high + mid = low + (high - low >> 1) + comparison = compare(array[mid], mid) + if comparison < 0 + low = mid + 1 + else if comparison > 0 + high = mid - 1 else - nextCharIndex = charIndex + 1 - rangeRect = @clientRectForRange(textNode, charIndex, nextCharIndex) - return -1 if rangeRect.right < position - return 1 if rangeRect.left > position - return 0 + return mid - characterIndex = binarySearch(textNodeContent, targetLeft, characterComparator) - if targetLeft <= ((rangeRect.left + rangeRect.right) / 2) - return characterIndex - return nextCharIndex + return -1