mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Handle scoped character widths in TextEditorPresenter
Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
@@ -284,6 +284,28 @@ describe "TextEditorPresenter", ->
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 20
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 20
|
||||
|
||||
describe "when the scoped character widths change", ->
|
||||
beforeEach ->
|
||||
waitsForPromise -> atom.packages.activatePackage('language-javascript')
|
||||
|
||||
it "updates the width of the lines if the ::scrollWidth changes", ->
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
line1 = editor.tokenizedLineForScreenRow(1)
|
||||
line2 = editor.tokenizedLineForScreenRow(2)
|
||||
|
||||
maxLineLength = editor.getMaxScreenLineLength()
|
||||
|
||||
presenter = new TextEditorPresenter(model: editor, clientHeight: 25, clientWidth: 50, scrollTop: 0, scrollWidth: 70, lineHeight: 10, baseCharacterWidth: 10, lineOverdrawMargin: 0)
|
||||
expect(presenter.state.lines[line0.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line1.id].width).toBe 10 * maxLineLength + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe 10 * maxLineLength + 1
|
||||
|
||||
presenter.setScopedCharWidth(['source.js', 'support.function.js'], 'p', 20)
|
||||
|
||||
expect(presenter.state.lines[line0.id].width).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide
|
||||
expect(presenter.state.lines[line1.id].width).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1
|
||||
expect(presenter.state.lines[line2.id].width).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1
|
||||
|
||||
describe "when the ::baseCharacterWidth changes", ->
|
||||
it "updates the width of the lines if it changes the ::scrollWidth", ->
|
||||
line0 = editor.tokenizedLineForScreenRow(0)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
{CompositeDisposable} = require 'event-kit'
|
||||
{Point} = require 'text-buffer'
|
||||
|
||||
module.exports =
|
||||
class TextEditorPresenter
|
||||
constructor: ({@model, @clientHeight, @clientWidth, @scrollTop, @lineHeight, @baseCharacterWidth, @lineOverdrawMargin}) ->
|
||||
@disposables = new CompositeDisposable
|
||||
@state = {}
|
||||
@charWidthsByScope = {}
|
||||
@subscribeToModel()
|
||||
@buildLinesState()
|
||||
|
||||
@@ -13,7 +15,9 @@ class TextEditorPresenter
|
||||
|
||||
subscribeToModel: ->
|
||||
@disposables.add @model.onDidChange(@updateLinesState.bind(this))
|
||||
@disposables.add @model.onDidChangeSoftWrapped(@updateLinesState.bind(this))
|
||||
@disposables.add @model.onDidChangeSoftWrapped =>
|
||||
@computeScrollWidth()
|
||||
@updateLinesState()
|
||||
|
||||
buildLinesState: ->
|
||||
@state.lines = {}
|
||||
@@ -66,10 +70,12 @@ class TextEditorPresenter
|
||||
endRow = startRow + visibleLinesCount + @lineOverdrawMargin
|
||||
Math.min(@model.getScreenLineCount(), endRow)
|
||||
|
||||
getScrollWidth: ->
|
||||
contentWidth = @model.getMaxScreenLineLength() * @getBaseCharacterWidth()
|
||||
computeScrollWidth: ->
|
||||
contentWidth = @pixelPositionForScreenPosition([@model.getLongestScreenRow(), Infinity]).left
|
||||
contentWidth += 1 unless @model.isSoftWrapped() # account for cursor width
|
||||
Math.max(contentWidth, @getClientWidth())
|
||||
@scrollWidth = Math.max(contentWidth, @getClientWidth())
|
||||
|
||||
getScrollWidth: -> @scrollWidth ? @computeScrollWidth()
|
||||
|
||||
setScrollTop: (@scrollTop) ->
|
||||
@updateLinesState()
|
||||
@@ -83,6 +89,7 @@ class TextEditorPresenter
|
||||
@clientHeight ? @model.getScreenLineCount() * @getLineHeight()
|
||||
|
||||
setClientWidth: (@clientWidth) ->
|
||||
@computeScrollWidth()
|
||||
@updateLinesState()
|
||||
|
||||
getClientWidth: -> @clientWidth
|
||||
@@ -93,6 +100,68 @@ class TextEditorPresenter
|
||||
getLineHeight: -> @lineHeight
|
||||
|
||||
setBaseCharacterWidth: (@baseCharacterWidth) ->
|
||||
@computeScrollWidth()
|
||||
@updateLinesState()
|
||||
|
||||
getBaseCharacterWidth: -> @baseCharacterWidth
|
||||
|
||||
getScopedCharWidth: (scopeNames, char) ->
|
||||
@getScopedCharWidths(scopeNames)[char]
|
||||
|
||||
getScopedCharWidths: (scopeNames) ->
|
||||
scope = @charWidthsByScope
|
||||
for scopeName in scopeNames
|
||||
scope[scopeName] ?= {}
|
||||
scope = scope[scopeName]
|
||||
scope.charWidths ?= {}
|
||||
scope.charWidths
|
||||
|
||||
batchCharacterMeasurement: (fn) ->
|
||||
oldChangeCount = @scopedCharacterWidthsChangeCount
|
||||
@batchingCharacterMeasurement = true
|
||||
fn()
|
||||
@batchingCharacterMeasurement = false
|
||||
@characterWidthsChanged() if oldChangeCount isnt @scopedCharacterWidthsChangeCount
|
||||
|
||||
setScopedCharWidth: (scopeNames, char, width) ->
|
||||
@getScopedCharWidths(scopeNames)[char] = width
|
||||
@scopedCharacterWidthsChangeCount++
|
||||
@characterWidthsChanged() unless @batchingCharacterMeasurement
|
||||
|
||||
characterWidthsChanged: ->
|
||||
@computeScrollWidth()
|
||||
@updateLinesState()
|
||||
|
||||
clearScopedCharWidths: ->
|
||||
@charWidthsByScope = {}
|
||||
|
||||
pixelPositionForScreenPosition: (screenPosition, clip=true) ->
|
||||
screenPosition = Point.fromObject(screenPosition)
|
||||
screenPosition = @model.clipScreenPosition(screenPosition) if clip
|
||||
|
||||
targetRow = screenPosition.row
|
||||
targetColumn = screenPosition.column
|
||||
baseCharacterWidth = @baseCharacterWidth
|
||||
|
||||
top = targetRow * @lineHeightInPixels
|
||||
left = 0
|
||||
column = 0
|
||||
for token in @model.tokenizedLineForScreenRow(targetRow).tokens
|
||||
charWidths = @getScopedCharWidths(token.scopes)
|
||||
|
||||
valueIndex = 0
|
||||
while valueIndex < token.value.length
|
||||
if token.hasPairedCharacter
|
||||
char = token.value.substr(valueIndex, 2)
|
||||
charLength = 2
|
||||
valueIndex += 2
|
||||
else
|
||||
char = token.value[valueIndex]
|
||||
charLength = 1
|
||||
valueIndex++
|
||||
|
||||
return {top, left} if column is targetColumn
|
||||
|
||||
left += charWidths[char] ? baseCharacterWidth unless char is '\0'
|
||||
column += charLength
|
||||
{top, left}
|
||||
|
||||
@@ -720,6 +720,8 @@ class TextEditor extends Model
|
||||
# {Delegates to: DisplayBuffer.getMaxLineLength}
|
||||
getMaxScreenLineLength: -> @displayBuffer.getMaxLineLength()
|
||||
|
||||
getLongestScreenRow: -> @displayBuffer.getLongestScreenRow()
|
||||
|
||||
# Returns the range for the given buffer row.
|
||||
#
|
||||
# * `row` A row {Number}.
|
||||
|
||||
Reference in New Issue
Block a user