Merge branch 'master' into as-tiled-gutter

Conflicts:
	src/text-editor-presenter.coffee
This commit is contained in:
Antonio Scandurra
2015-06-04 21:42:53 +02:00
12 changed files with 159 additions and 94 deletions

View File

@@ -153,6 +153,8 @@ class Decoration
oldProperties = @properties
@properties = translateDecorationParamsOldToNew(newProperties)
@properties.id = @id
if newProperties.type?
@displayBuffer.decorationDidChangeType(this)
@emit 'updated', {oldParams: oldProperties, newParams: newProperties} if Grim.includeDeprecatedAPIs
@emitter.emit 'did-change-properties', {oldProperties, newProperties}

View File

@@ -37,9 +37,11 @@ class DisplayBuffer extends Model
@foldsByMarkerId = {}
@decorationsById = {}
@decorationsByMarkerId = {}
@overlayDecorationsById = {}
@disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings
@disposables.add @tokenizedBuffer.onDidChange @handleTokenizedBufferChange
@disposables.add @buffer.onDidCreateMarker @handleBufferMarkerCreated
@disposables.add @buffer.onDidUpdateMarkers => @emitter.emit 'did-update-markers'
@foldMarkerAttributes = Object.freeze({class: 'fold', displayBufferId: @id})
folds = (new Fold(this, marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes()))
@updateAllScreenLines()
@@ -918,7 +920,16 @@ class DisplayBuffer extends Model
@getDecorations(propertyFilter).filter (decoration) -> decoration.isType('highlight')
getOverlayDecorations: (propertyFilter) ->
@getDecorations(propertyFilter).filter (decoration) -> decoration.isType('overlay')
result = []
for id, decoration of @overlayDecorationsById
result.push(decoration)
if propertyFilter?
result.filter (decoration) ->
for key, value of propertyFilter
return false unless decoration.properties[key] is value
true
else
result
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
decorationsByMarkerId = {}
@@ -933,6 +944,7 @@ class DisplayBuffer extends Model
@disposables.add decoration.onDidDestroy => @removeDecoration(decoration)
@decorationsByMarkerId[marker.id] ?= []
@decorationsByMarkerId[marker.id].push(decoration)
@overlayDecorationsById[decoration.id] = decoration if decoration.isType('overlay')
@decorationsById[decoration.id] = decoration
@emit 'decoration-added', decoration if Grim.includeDeprecatedAPIs
@emitter.emit 'did-add-decoration', decoration
@@ -949,6 +961,10 @@ class DisplayBuffer extends Model
@emit 'decoration-removed', decoration if Grim.includeDeprecatedAPIs
@emitter.emit 'did-remove-decoration', decoration
delete @decorationsByMarkerId[marker.id] if decorations.length is 0
delete @overlayDecorationsById[decoration.id]
decorationsForMarkerId: (markerId) ->
@decorationsByMarkerId[markerId]
# Retrieves a {Marker} based on its id.
#
@@ -1242,6 +1258,12 @@ class DisplayBuffer extends Model
foldForMarker: (marker) ->
@foldsByMarkerId[marker.id]
decorationDidChangeType: (decoration) ->
if decoration.isType('overlay')
@overlayDecorationsById[decoration.id] = decoration
else
delete @overlayDecorationsById[decoration.id]
if Grim.includeDeprecatedAPIs
DisplayBuffer.properties
softWrapped: null

View File

@@ -0,0 +1,12 @@
module.exports =
class MarkerObservationWindow
constructor: (@displayBuffer, @bufferWindow) ->
setScreenRange: (range) ->
@bufferWindow.setRange(@displayBuffer.bufferRangeForScreenRange(range))
setBufferRange: (range) ->
@bufferWindow.setRange(range)
destroy: ->
@bufferWindow.destroy()

View File

@@ -48,6 +48,7 @@ class Marker
oldTailBufferPosition: null
oldTailScreenPosition: null
wasValid: true
hasChangeObservers: false
###
Section: Construction and Destruction
@@ -57,14 +58,8 @@ class Marker
@emitter = new Emitter
@disposables = new CompositeDisposable
@id = @bufferMarker.id
@oldHeadBufferPosition = @getHeadBufferPosition()
@oldHeadScreenPosition = @getHeadScreenPosition()
@oldTailBufferPosition = @getTailBufferPosition()
@oldTailScreenPosition = @getTailScreenPosition()
@wasValid = @isValid()
@disposables.add @bufferMarker.onDidDestroy => @destroyed()
@disposables.add @bufferMarker.onDidChange (event) => @notifyObservers(event)
# Essential: Destroys the marker, causing it to emit the 'destroyed' event. Once
# destroyed, a marker cannot be restored by undo/redo operations.
@@ -102,6 +97,14 @@ class Marker
#
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
onDidChange: (callback) ->
unless @hasChangeObservers
@oldHeadBufferPosition = @getHeadBufferPosition()
@oldHeadScreenPosition = @getHeadScreenPosition()
@oldTailBufferPosition = @getTailBufferPosition()
@oldTailScreenPosition = @getTailScreenPosition()
@wasValid = @isValid()
@disposables.add @bufferMarker.onDidChange (event) => @notifyObservers(event)
@hasChangeObservers = true
@emitter.on 'did-change', callback
# Essential: Invoke the given callback when the marker is destroyed.

View File

@@ -1,4 +1,4 @@
{CompositeDisposable, Emitter} = require 'event-kit'
{CompositeDisposable, Disposable, Emitter} = require 'event-kit'
{Point, Range} = require 'text-buffer'
_ = require 'underscore-plus'
Decoration = require './decoration'
@@ -25,6 +25,10 @@ class TextEditorPresenter
@disposables = new CompositeDisposable
@emitter = new Emitter
@characterWidthsByScope = {}
@rangesByDecorationId = {}
@lineDecorationsByScreenRow = {}
@lineNumberDecorationsByScreenRow = {}
@customGutterDecorationsByGutterNameAndScreenRow = {}
@transferMeasurementsToModel()
@observeModel()
@observeConfig()
@@ -120,13 +124,21 @@ class TextEditorPresenter
@shouldUpdateLineNumbersState = true
@shouldUpdateGutterOrderState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
@model.onDidUpdateMarkers =>
@shouldUpdateLinesState = true
@shouldUpdateLineNumbersState = true
@shouldUpdateDecorations = true
@shouldUpdateOverlaysState = true
@shouldUpdateCustomGutterDecorationState = true
@emitDidUpdateState()
@disposables.add @model.onDidChangeGrammar(@didChangeGrammar.bind(this))
@disposables.add @model.onDidChangePlaceholderText =>
@shouldUpdateContentState = true
@emitDidUpdateState()
@disposables.add @model.onDidChangeMini =>
@shouldUpdateScrollbarsState = true
@shouldUpdateContentState = true
@@ -138,14 +150,14 @@ class TextEditorPresenter
@shouldUpdateCustomGutterDecorationState = true
@updateScrollbarDimensions()
@updateCommonGutterState()
@emitDidUpdateState()
@disposables.add @model.onDidChangeLineNumberGutterVisible =>
@shouldUpdateLineNumberGutterState = true
@shouldUpdateGutterOrderState = true
@updateCommonGutterState()
@emitDidUpdateState()
@disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this))
@disposables.add @model.onDidAddCursor(@didAddCursor.bind(this))
@disposables.add @model.onDidChangeScrollTop(@setScrollTop.bind(this))
@@ -1089,58 +1101,22 @@ class TextEditorPresenter
observeDecoration: (decoration) ->
decorationDisposables = new CompositeDisposable
decorationDisposables.add decoration.getMarker().onDidChange(@decorationMarkerDidChange.bind(this, decoration))
if decoration.isType('highlight')
decorationDisposables.add decoration.onDidFlash(@highlightDidFlash.bind(this, decoration))
decorationDisposables.add decoration.onDidChangeProperties(@decorationPropertiesDidChange.bind(this, decoration))
decorationDisposables.add decoration.onDidFlash =>
@shouldUpdateDecorations = true
@emitDidUpdateState()
decorationDisposables.add decoration.onDidChangeProperties (event) =>
@decorationPropertiesDidChange(decoration, event)
decorationDisposables.add decoration.onDidDestroy =>
@disposables.remove(decorationDisposables)
decorationDisposables.dispose()
@didDestroyDecoration(decoration)
@disposables.add(decorationDisposables)
decorationMarkerDidChange: (decoration, change) ->
decorationPropertiesDidChange: (decoration, {oldProperties}) ->
@shouldUpdateDecorations = true
if decoration.isType('line') or decoration.isType('gutter')
return if change.textChanged
intersectsVisibleRowRange = false
oldRange = new Range(change.oldTailScreenPosition, change.oldHeadScreenPosition)
newRange = new Range(change.newTailScreenPosition, change.newHeadScreenPosition)
if oldRange.intersectsRowRange(@startRow, @endRow - 1)
@removeFromLineDecorationCaches(decoration, oldRange)
intersectsVisibleRowRange = true
if newRange.intersectsRowRange(@startRow, @endRow - 1)
@addToLineDecorationCaches(decoration, newRange)
intersectsVisibleRowRange = true
if intersectsVisibleRowRange
if decoration.isType('line')
@shouldUpdateLinesState = true
if decoration.isType('line-number')
@shouldUpdateLineNumbersState = true
else if decoration.isType('gutter')
@shouldUpdateCustomGutterDecorationState = true
if decoration.isType('highlight')
return if change.textChanged
@updateHighlightState(decoration)
if decoration.isType('overlay')
@shouldUpdateOverlaysState = true
@emitDidUpdateState()
decorationPropertiesDidChange: (decoration, event) ->
{oldProperties} = event
if decoration.isType('line') or decoration.isType('gutter')
@removePropertiesFromLineDecorationCaches(
decoration.id,
oldProperties,
decoration.getMarker().getScreenRange())
@addToLineDecorationCaches(decoration, decoration.getMarker().getScreenRange())
if decoration.isType('line') or Decoration.isType(oldProperties, 'line')
@shouldUpdateLinesState = true
if decoration.isType('line-number') or Decoration.isType(oldProperties, 'line-number')
@@ -1150,16 +1126,12 @@ class TextEditorPresenter
@shouldUpdateCustomGutterDecorationState = true
else if decoration.isType('overlay')
@shouldUpdateOverlaysState = true
else if decoration.isType('highlight')
@updateHighlightState(decoration, event)
@emitDidUpdateState()
didDestroyDecoration: (decoration) ->
@shouldUpdateDecorations = true
if decoration.isType('line') or decoration.isType('gutter')
@removeFromLineDecorationCaches(decoration, decoration.getMarker().getScreenRange())
if decoration.isType('line')
@shouldUpdateLinesState = true
@shouldUpdateLinesState = true if decoration.isType('line')
if decoration.isType('line-number')
@shouldUpdateLineNumbersState = true
else if decoration.isType('gutter')
@@ -1171,14 +1143,6 @@ class TextEditorPresenter
@emitDidUpdateState()
highlightDidFlash: (decoration) ->
flash = decoration.consumeNextFlash()
if decorationState = @state.content.highlights[decoration.id]
decorationState.flashCount++
decorationState.flashClass = flash.class
decorationState.flashDuration = flash.duration
@emitDidUpdateState()
didAddDecoration: (decoration) ->
@observeDecoration(decoration)
@@ -1198,10 +1162,10 @@ class TextEditorPresenter
@emitDidUpdateState()
updateDecorations: ->
@rangesByDecorationId = {}
@lineDecorationsByScreenRow = {}
@lineNumberDecorationsByScreenRow = {}
@customGutterDecorationsByGutterNameAndScreenRow = {}
@highlightDecorationsById = {}
visibleHighlights = {}
return unless 0 <= @startRow <= @endRow <= Infinity
@@ -1220,16 +1184,19 @@ class TextEditorPresenter
return
removeFromLineDecorationCaches: (decoration, range) ->
@removePropertiesFromLineDecorationCaches(decoration.id, decoration.getProperties(), range)
removeFromLineDecorationCaches: (decoration) ->
@removePropertiesFromLineDecorationCaches(decoration.id, decoration.getProperties())
removePropertiesFromLineDecorationCaches: (decorationId, decorationProperties, range) ->
gutterName = decorationProperties.gutterName
for row in [range.start.row..range.end.row] by 1
delete @lineDecorationsByScreenRow[row]?[decorationId]
delete @lineNumberDecorationsByScreenRow[row]?[decorationId]
delete @customGutterDecorationsByGutterNameAndScreenRow[gutterName]?[row]?[decorationId] if gutterName
return
removePropertiesFromLineDecorationCaches: (decorationId, decorationProperties) ->
if range = @rangesByDecorationId[decorationId]
delete @rangesByDecorationId[decorationId]
gutterName = decorationProperties.gutterName
for row in [range.start.row..range.end.row] by 1
delete @lineDecorationsByScreenRow[row]?[decorationId]
delete @lineNumberDecorationsByScreenRow[row]?[decorationId]
delete @customGutterDecorationsByGutterNameAndScreenRow[gutterName]?[row]?[decorationId] if gutterName
return
addToLineDecorationCaches: (decoration, range) ->
marker = decoration.getMarker()
@@ -1243,6 +1210,8 @@ class TextEditorPresenter
return if properties.onlyEmpty
omitLastRow = range.end.column is 0
@rangesByDecorationId[decoration.id] = range
for row in [range.start.row..range.end.row] by 1
continue if properties.onlyHead and row isnt marker.getHeadScreenPosition().row
continue if omitLastRow and row is range.end.row
@@ -1291,6 +1260,12 @@ class TextEditorPresenter
flashDuration: null
flashClass: null
}
if flash = decoration.consumeNextFlash()
highlightState.flashCount++
highlightState.flashClass = flash.class
highlightState.flashDuration = flash.duration
highlightState.class = properties.class
highlightState.deprecatedRegionClass = properties.deprecatedRegionClass
highlightState.regions = @buildHighlightRegions(range)

View File

@@ -163,10 +163,10 @@ class TextEditor extends Model
subscribeToDisplayBuffer: ->
@disposables.add @displayBuffer.onDidCreateMarker @handleMarkerCreated
@disposables.add @displayBuffer.onDidUpdateMarkers => @mergeIntersectingSelections()
@disposables.add @displayBuffer.onDidChangeGrammar => @handleGrammarChange()
@disposables.add @displayBuffer.onDidTokenize => @handleTokenization()
@disposables.add @displayBuffer.onDidChange (e) =>
@mergeIntersectingSelections()
@emit 'screen-lines-changed', e if includeDeprecatedAPIs
@emitter.emit 'did-change', e
@@ -461,6 +461,9 @@ class TextEditor extends Model
onDidChangeIcon: (callback) ->
@emitter.on 'did-change-icon', callback
onDidUpdateMarkers: (callback) ->
@displayBuffer.onDidUpdateMarkers(callback)
# Public: Retrieves the current {TextBuffer}.
getBuffer: -> @buffer
@@ -1386,6 +1389,9 @@ class TextEditor extends Model
decorationForId: (id) ->
@displayBuffer.decorationForId(id)
decorationsForMarkerId: (id) ->
@displayBuffer.decorationsForMarkerId(id)
###
Section: Markers
###
@@ -1488,6 +1494,25 @@ class TextEditor extends Model
findMarkers: (properties) ->
@displayBuffer.findMarkers(properties)
# Extended: Observe changes in the set of markers that intersect a particular
# region of the editor.
#
# * `callback` A {Function} to call whenever one or more {Marker}s appears,
# disappears, or moves within the given region.
# * `event` An {Object} with the following keys:
# * `insert` A {Set} containing the ids of all markers that appeared
# in the range.
# * `update` A {Set} containing the ids of all markers that moved within
# the region.
# * `remove` A {Set} containing the ids of all markers that disappeared
# from the region.
#
# Returns a {MarkerObservationWindow}, which allows you to specify the region
# of interest by calling {MarkerObservationWindow::setBufferRange} or
# {MarkerObservationWindow::setScreenRange}.
observeMarkers: (callback) ->
@displayBuffer.observeMarkers(callback)
# Extended: Get the {Marker} for the given marker id.
#
# * `id` {Number} id of the marker

View File

@@ -126,6 +126,7 @@ atom.commands.add 'atom-workspace',
'application:about': -> ipc.send('command', 'application:about')
'application:run-all-specs': -> ipc.send('command', 'application:run-all-specs')
'application:run-benchmarks': -> ipc.send('command', 'application:run-benchmarks')
'application:show-preferences': -> ipc.send('command', 'application:show-settings')
'application:show-settings': -> ipc.send('command', 'application:show-settings')
'application:quit': -> ipc.send('command', 'application:quit')
'application:hide': -> ipc.send('command', 'application:hide')