Rendering decorations works well.

Also specs.
This commit is contained in:
Ben Ogle
2014-06-04 09:53:22 -07:00
parent 142eedd705
commit eb59196c02
4 changed files with 82 additions and 11 deletions

View File

@@ -302,6 +302,67 @@ describe "EditorComponent", ->
expect(component.lineNumberNodeForScreenRow(9).textContent).toBe "10"
expect(gutterNode.offsetWidth).toBe initialGutterWidth
fdescribe "when decorations are used", ->
it "renders the gutter-class decorations", ->
node.style.height = 4.5 * lineHeightInPixels + 'px'
component.measureScrollView()
expect(component.lineNumberNodeForScreenRow(9)).toBeFalsy()
editor.addDecorationForBufferRow(9, {type: 'gutter-class', class: 'fancy-class'})
editor.addDecorationForBufferRow(9, {type: 'someother-type', class: 'nope-class'})
verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
expect(component.lineNumberNodeForScreenRow(9).classList.contains('fancy-class')).toBeTruthy()
expect(component.lineNumberNodeForScreenRow(9).classList.contains('nope-class')).toBeFalsy()
it "handles updates to gutter-class decorations", ->
editor.addDecorationForBufferRow(2, {type: 'gutter-class', class: 'fancy-class'})
editor.addDecorationForBufferRow(2, {type: 'someother-type', class: 'nope-class'})
expect(component.lineNumberNodeForScreenRow(2).classList.contains('fancy-class')).toBeTruthy()
expect(component.lineNumberNodeForScreenRow(2).classList.contains('nope-class')).toBeFalsy()
editor.removeDecorationForBufferRow(2, {type: 'gutter-class', class: 'fancy-class'})
editor.removeDecorationForBufferRow(2, {type: 'someother-type', class: 'nope-class'})
expect(component.lineNumberNodeForScreenRow(2).classList.contains('fancy-class')).toBeFalsy()
expect(component.lineNumberNodeForScreenRow(2).classList.contains('nope-class')).toBeFalsy()
it "handles softWrap decorations", ->
editor.addDecorationForBufferRow(1, {type: 'gutter-class', class: 'no-wrap'})
editor.addDecorationForBufferRow(1, {type: 'gutter-class', class: 'wrap-me', softWrap: true})
editor.setSoftWrap(true)
node.style.height = 4.5 * lineHeightInPixels + 'px'
node.style.width = 30 * charWidth + 'px'
component.measureScrollView()
expect(component.lineNumberNodeForScreenRow(2).classList.contains 'no-wrap').toBeTruthy()
expect(component.lineNumberNodeForScreenRow(2).classList.contains 'wrap-me').toBeTruthy()
expect(component.lineNumberNodeForScreenRow(3).classList.contains 'no-wrap').toBeFalsy()
expect(component.lineNumberNodeForScreenRow(3).classList.contains 'wrap-me').toBeTruthy()
# should remove the wrapped decorations
editor.removeDecorationForBufferRow(1, {type: 'gutter-class', class: 'no-wrap'})
editor.removeDecorationForBufferRow(1, {type: 'gutter-class', class: 'wrap-me'})
expect(component.lineNumberNodeForScreenRow(2).classList.contains 'no-wrap').toBeFalsy()
expect(component.lineNumberNodeForScreenRow(2).classList.contains 'wrap-me').toBeFalsy()
expect(component.lineNumberNodeForScreenRow(3).classList.contains 'no-wrap').toBeFalsy()
expect(component.lineNumberNodeForScreenRow(3).classList.contains 'wrap-me').toBeFalsy()
# should add them back when the nodes are not recreated
editor.addDecorationForBufferRow(1, {type: 'gutter-class', class: 'no-wrap'})
editor.addDecorationForBufferRow(1, {type: 'gutter-class', class: 'wrap-me', softWrap: true})
expect(component.lineNumberNodeForScreenRow(2).classList.contains 'no-wrap').toBeTruthy()
expect(component.lineNumberNodeForScreenRow(2).classList.contains 'wrap-me').toBeTruthy()
expect(component.lineNumberNodeForScreenRow(3).classList.contains 'no-wrap').toBeFalsy()
expect(component.lineNumberNodeForScreenRow(3).classList.contains 'wrap-me').toBeTruthy()
describe "cursor rendering", ->
it "renders the currently visible cursors, translated relative to the scroll position", ->
cursor1 = editor.getCursor()

View File

@@ -719,8 +719,10 @@ class DisplayBuffer extends Model
rangeForAllLines: ->
new Range([0, 0], @clipScreenPosition([Infinity, Infinity]))
decorationsForBufferRow: (bufferRow) ->
@decorations[bufferRow] ? []
decorationsForBufferRow: (bufferRow, decorationType) ->
decorations = @decorations[bufferRow] ? []
decorations = (dec for dec in decorations when dec.type == decorationType) if decorationType?
decorations
addDecorationForBufferRow: (bufferRow, decoration) ->
@decorations[bufferRow] ?= []

View File

@@ -1058,8 +1058,8 @@ class Editor extends Model
selection.insertText(fn(text))
selection.setBufferRange(range)
decorationsForBufferRow: (bufferRow) ->
@displayBuffer.decorationsForBufferRow(bufferRow)
decorationsForBufferRow: (bufferRow, decorationType) ->
@displayBuffer.decorationsForBufferRow(bufferRow, decorationType)
addDecorationForBufferRow: (bufferRow, decoration) ->
@displayBuffer.addDecorationForBufferRow(bufferRow, decoration)

View File

@@ -9,6 +9,7 @@ module.exports =
GutterComponent = React.createClass
displayName: 'GutterComponent'
mixins: [SubscriberMixin]
decorationType: 'gutter-class'
dummyLineNumberNode: null
@@ -118,6 +119,7 @@ GutterComponent = React.createClass
@lineNumberNodesById[lineNumberId] = lineNumberNode
node.appendChild(lineNumberNode)
@decoratorUpdates = {}
visibleLineNumberIds
removeLineNumberNodes: (lineNumberIdsToPreserve) ->
@@ -139,11 +141,15 @@ GutterComponent = React.createClass
style = "visibility: hidden;"
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped, maxLineNumberDigits)
classes = "line-number"
classes += ' foldable' if not softWrapped and @props.editor.isFoldableAtBufferRow(bufferRow)
classes += ' folded' if @props.editor.isFoldedAtBufferRow(bufferRow)
classes = ['line-number']
classes.push 'foldable' if not softWrapped and @props.editor.isFoldableAtBufferRow(bufferRow)
classes.push 'folded' if @props.editor.isFoldedAtBufferRow(bufferRow)
"<div class=\"#{classes}\" style=\"#{style}\" data-buffer-row=\"#{bufferRow}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
decorations = @props.editor.decorationsForBufferRow(bufferRow, @decorationType)
for decoration in decorations
classes.push(decoration.class) if not softWrapped or softWrapped and decoration.softWrap
"<div class=\"#{classes.join(' ')}\" style=\"#{style}\" data-buffer-row=\"#{bufferRow}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
buildLineNumberInnerHTML: (bufferRow, softWrapped, maxLineNumberDigits) ->
if softWrapped
@@ -163,8 +169,10 @@ GutterComponent = React.createClass
if @decoratorUpdates[bufferRow]?
for change in @decoratorUpdates[bufferRow]
node.classList[change.action](change.decoration.class)
delete @decoratorUpdates[bufferRow]
if change.action == 'add' and (not softWrapped or softWrapped and change.decoration.softWrap)
node.classList.add(change.decoration.class)
else if change.action == 'remove'
node.classList.remove(change.decoration.class)
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
{lineHeightInPixels} = @props
@@ -183,7 +191,7 @@ GutterComponent = React.createClass
if condition then node.classList.add(klass) else node.classList.remove(klass)
onDecorationChanged: (change) ->
if change.decoration.type == 'gutter-class'
if change.decoration.type == @decorationType
@decoratorUpdates[change.bufferRow] ?= []
@decoratorUpdates[change.bufferRow].push change
@forceUpdate()