diff --git a/spec/editor-view-spec.coffee b/spec/editor-view-spec.coffee index 8aa3399a5..c7fc72a6f 100644 --- a/spec/editor-view-spec.coffee +++ b/spec/editor-view-spec.coffee @@ -2832,3 +2832,22 @@ describe "EditorView", -> setEditorWidthInChars(editorView, 100) $(window).trigger 'resize' expect(editorView.editor.getSoftWrapColumn()).toBe 100 + + describe "character width caching", -> + describe "when soft wrap is enabled", -> + it "correctly calculates the the position left for a column", -> + editor.setSoftWrap(true) + editorView.setText('lllll 00000') + editorView.setFontFamily('serif') + editorView.setFontSize(10) + editorView.attachToDom() + editorView.setWidthInChars(5) + + expect(editorView.pixelPositionForScreenPosition([0, 5]).left).toEqual 15 + expect(editorView.pixelPositionForScreenPosition([1, 5]).left).toEqual 25 + + # Check that widths are actually being cached + spyOn(editorView, 'measureToColumn').andCallThrough() + editorView.pixelPositionForScreenPosition([0, 5]) + editorView.pixelPositionForScreenPosition([1, 5]) + expect(editorView.measureToColumn.callCount).toBe 0 diff --git a/src/editor-view.coffee b/src/editor-view.coffee index 11350cc8b..9dd32d9b8 100644 --- a/src/editor-view.coffee +++ b/src/editor-view.coffee @@ -1587,36 +1587,31 @@ class EditorView extends View @renderedLines[0].removeChild(lineElement) { top: row * @lineHeight, left } - positionLeftForLineAndColumn: (lineElement, screenRow, column) -> - return 0 if column == 0 + positionLeftForLineAndColumn: (lineElement, screenRow, screenColumn) -> + return 0 if screenColumn == 0 bufferRow = @bufferRowsForScreenRows(screenRow, screenRow)[0] ? screenRow + bufferColumn = @bufferPositionForScreenPosition([screenRow, screenColumn]).column tokenizedLine = @editor.displayBuffer.tokenizedBuffer.tokenizedLines[bufferRow] left = 0 index = 0 + startIndex = @bufferPositionForScreenPosition([screenRow, 0]).column for token in tokenizedLine.tokens for char in token.value - return left if index >= column + return left if index >= bufferColumn - val = @getCharacterWidthCache(token.scopes, char) - if val? - left += val - else - return @measureToColumn(lineElement, tokenizedLine, column) + if index >= startIndex + val = @getCharacterWidthCache(token.scopes, char) + if val? + left += val + else + return @measureToColumn(lineElement, tokenizedLine, screenColumn, startIndex) index++ left - scopesForColumn: (tokenizedLine, column) -> - index = 0 - for token in tokenizedLine.tokens - for char in token.value - return token.scopes if index == column - index++ - null - - measureToColumn: (lineElement, tokenizedLine, column) -> + measureToColumn: (lineElement, tokenizedLine, screenColumn, lineStartBufferColumn) -> left = oldLeft = index = 0 iterator = document.createNodeIterator(lineElement, NodeFilter.SHOW_TEXT, TextNodeFilter) @@ -1630,13 +1625,13 @@ class EditorView extends View for char, i in content # Don't continue caching long lines :racehorse: - break if index > LongLineLength and column < index + break if index > LongLineLength and screenColumn < index # Dont return right away, finish caching the whole line - returnLeft = left if index == column + returnLeft = left if index == screenColumn oldLeft = left - scopes = @scopesForColumn(tokenizedLine, index) + scopes = tokenizedLine.tokenAtBufferColumn(lineStartBufferColumn + index)?.scopes cachedCharWidth = @getCharacterWidthCache(scopes, char) if cachedCharWidth? @@ -1655,7 +1650,7 @@ class EditorView extends View # Assume all the characters are the same width when dealing with long # lines :racehorse: - return column * cachedCharWidth if index > LongLineLength + return screenColumn * cachedCharWidth if index > LongLineLength index++