mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 07:28:08 +03:00
Use DisplayMarkerLayers
I’m creating the DisplayLayer in the DisplayBuffer. In places where our API deviates from DisplayBuffer, I’ll use the DisplayLayer directly from as a property of TextEditor. Otherwise I’ll continue to delegate from the DisplayLayer into the DisplayLayer to minimize impact until the DisplayBuffer can be removed entirely.
This commit is contained in:
parent
5292767084
commit
caf6d7f473
@ -9,7 +9,7 @@ EmptyLineRegExp = /(\r\n[\t ]*\r\n)|(\n[\t ]*\n)/g
|
||||
# where text can be inserted.
|
||||
#
|
||||
# Cursors belong to {TextEditor}s and have some metadata attached in the form
|
||||
# of a {TextEditorMarker}.
|
||||
# of a {DisplayMarker}.
|
||||
module.exports =
|
||||
class Cursor extends Model
|
||||
screenPosition: null
|
||||
@ -129,7 +129,7 @@ class Cursor extends Model
|
||||
Section: Cursor Position Details
|
||||
###
|
||||
|
||||
# Public: Returns the underlying {TextEditorMarker} for the cursor.
|
||||
# Public: Returns the underlying {DisplayMarker} for the cursor.
|
||||
# Useful with overlay {Decoration}s.
|
||||
getMarker: -> @marker
|
||||
|
||||
@ -265,7 +265,7 @@ class Cursor extends Model
|
||||
columnCount-- # subtract 1 for the row move
|
||||
|
||||
column = column - columnCount
|
||||
@setScreenPosition({row, column}, clip: 'backward')
|
||||
@setScreenPosition({row, column}, clipDirection: 'backward')
|
||||
|
||||
# Public: Moves the cursor right one screen column.
|
||||
#
|
||||
@ -292,7 +292,7 @@ class Cursor extends Model
|
||||
columnsRemainingInLine = rowLength
|
||||
|
||||
column = column + columnCount
|
||||
@setScreenPosition({row, column}, clip: 'forward', wrapBeyondNewlines: true, wrapAtSoftNewlines: true)
|
||||
@setScreenPosition({row, column}, clipDirection: 'forward')
|
||||
|
||||
# Public: Moves the cursor to the top of the buffer.
|
||||
moveToTop: ->
|
||||
|
@ -11,7 +11,7 @@ translateDecorationParamsOldToNew = (decorationParams) ->
|
||||
decorationParams.gutterName = 'line-number'
|
||||
decorationParams
|
||||
|
||||
# Essential: Represents a decoration that follows a {TextEditorMarker}. A decoration is
|
||||
# Essential: Represents a decoration that follows a {DisplayMarker}. A decoration is
|
||||
# basically a visual representation of a marker. It allows you to add CSS
|
||||
# classes to line numbers in the gutter, lines, and add selection-line regions
|
||||
# around marked ranges of text.
|
||||
@ -25,7 +25,7 @@ translateDecorationParamsOldToNew = (decorationParams) ->
|
||||
# decoration = editor.decorateMarker(marker, {type: 'line', class: 'my-line-class'})
|
||||
# ```
|
||||
#
|
||||
# Best practice for destroying the decoration is by destroying the {TextEditorMarker}.
|
||||
# Best practice for destroying the decoration is by destroying the {DisplayMarker}.
|
||||
#
|
||||
# ```coffee
|
||||
# marker.destroy()
|
||||
@ -72,7 +72,7 @@ class Decoration
|
||||
|
||||
# Essential: Destroy this marker.
|
||||
#
|
||||
# If you own the marker, you should use {TextEditorMarker::destroy} which will destroy
|
||||
# If you own the marker, you should use {DisplayMarker::destroy} which will destroy
|
||||
# this decoration.
|
||||
destroy: ->
|
||||
return if @destroyed
|
||||
|
@ -8,7 +8,6 @@ Model = require './model'
|
||||
Token = require './token'
|
||||
Decoration = require './decoration'
|
||||
LayerDecoration = require './layer-decoration'
|
||||
TextEditorMarkerLayer = require './text-editor-marker-layer'
|
||||
|
||||
class BufferToScreenConversionError extends Error
|
||||
constructor: (@message, @metadata) ->
|
||||
@ -54,9 +53,9 @@ class DisplayBuffer extends Model
|
||||
@grammarRegistry, @packageManager, @assert
|
||||
})
|
||||
@buffer = @tokenizedBuffer.buffer
|
||||
@displayLayer = @buffer.addDisplayLayer({tabLength: @getTabLength()})
|
||||
@charWidthsByScope = {}
|
||||
@defaultMarkerLayer = new TextEditorMarkerLayer(this, @buffer.getDefaultMarkerLayer(), true)
|
||||
@customMarkerLayersById = {}
|
||||
@defaultMarkerLayer = @displayLayer.addMarkerLayer()
|
||||
@foldsByMarkerId = {}
|
||||
@decorationsById = {}
|
||||
@decorationsByMarkerId = {}
|
||||
@ -835,17 +834,17 @@ class DisplayBuffer extends Model
|
||||
decorationsForMarkerId: (markerId) ->
|
||||
@decorationsByMarkerId[markerId]
|
||||
|
||||
# Retrieves a {TextEditorMarker} based on its id.
|
||||
# Retrieves a {DisplayMarker} based on its id.
|
||||
#
|
||||
# id - A {Number} representing a marker id
|
||||
#
|
||||
# Returns the {TextEditorMarker} (if it exists).
|
||||
# Returns the {DisplayMarker} (if it exists).
|
||||
getMarker: (id) ->
|
||||
@defaultMarkerLayer.getMarker(id)
|
||||
|
||||
# Retrieves the active markers in the buffer.
|
||||
#
|
||||
# Returns an {Array} of existing {TextEditorMarker}s.
|
||||
# Returns an {Array} of existing {DisplayMarker}s.
|
||||
getMarkers: ->
|
||||
@defaultMarkerLayer.getMarkers()
|
||||
|
||||
@ -855,7 +854,7 @@ class DisplayBuffer extends Model
|
||||
# Public: Constructs a new marker at the given screen range.
|
||||
#
|
||||
# range - The marker {Range} (representing the distance between the head and tail)
|
||||
# options - Options to pass to the {TextEditorMarker} constructor
|
||||
# options - Options to pass to the {DisplayMarker} constructor
|
||||
#
|
||||
# Returns a {Number} representing the new marker's ID.
|
||||
markScreenRange: (screenRange, options) ->
|
||||
@ -864,7 +863,7 @@ class DisplayBuffer extends Model
|
||||
# Public: Constructs a new marker at the given buffer range.
|
||||
#
|
||||
# range - The marker {Range} (representing the distance between the head and tail)
|
||||
# options - Options to pass to the {TextEditorMarker} constructor
|
||||
# options - Options to pass to the {DisplayMarker} constructor
|
||||
#
|
||||
# Returns a {Number} representing the new marker's ID.
|
||||
markBufferRange: (bufferRange, options) ->
|
||||
@ -873,7 +872,7 @@ class DisplayBuffer extends Model
|
||||
# Public: Constructs a new marker at the given screen position.
|
||||
#
|
||||
# range - The marker {Range} (representing the distance between the head and tail)
|
||||
# options - Options to pass to the {TextEditorMarker} constructor
|
||||
# options - Options to pass to the {DisplayMarker} constructor
|
||||
#
|
||||
# Returns a {Number} representing the new marker's ID.
|
||||
markScreenPosition: (screenPosition, options) ->
|
||||
@ -882,7 +881,7 @@ class DisplayBuffer extends Model
|
||||
# Public: Constructs a new marker at the given buffer position.
|
||||
#
|
||||
# range - The marker {Range} (representing the distance between the head and tail)
|
||||
# options - Options to pass to the {TextEditorMarker} constructor
|
||||
# options - Options to pass to the {DisplayMarker} constructor
|
||||
#
|
||||
# Returns a {Number} representing the new marker's ID.
|
||||
markBufferPosition: (bufferPosition, options) ->
|
||||
@ -892,7 +891,7 @@ class DisplayBuffer extends Model
|
||||
#
|
||||
# Refer to {DisplayBuffer::findMarkers} for details.
|
||||
#
|
||||
# Returns a {TextEditorMarker} or null
|
||||
# Returns a {DisplayMarker} or null
|
||||
findMarker: (params) ->
|
||||
@defaultMarkerLayer.findMarkers(params)[0]
|
||||
|
||||
@ -913,19 +912,15 @@ class DisplayBuffer extends Model
|
||||
# :containedInBufferRange - A {Range} or range-compatible {Array}. Only
|
||||
# returns markers contained within this range.
|
||||
#
|
||||
# Returns an {Array} of {TextEditorMarker}s
|
||||
# Returns an {Array} of {DisplayMarker}s
|
||||
findMarkers: (params) ->
|
||||
@defaultMarkerLayer.findMarkers(params)
|
||||
|
||||
addMarkerLayer: (options) ->
|
||||
bufferLayer = @buffer.addMarkerLayer(options)
|
||||
@getMarkerLayer(bufferLayer.id)
|
||||
@displayLayer.addMarkerLayer(options)
|
||||
|
||||
getMarkerLayer: (id) ->
|
||||
if layer = @customMarkerLayersById[id]
|
||||
layer
|
||||
else if bufferLayer = @buffer.getMarkerLayer(id)
|
||||
@customMarkerLayersById[id] = new TextEditorMarkerLayer(this, bufferLayer)
|
||||
@displayLayer.getMarkerLayer(id)
|
||||
|
||||
getDefaultMarkerLayer: -> @defaultMarkerLayer
|
||||
|
||||
|
@ -71,13 +71,13 @@ class Gutter
|
||||
isVisible: ->
|
||||
@visible
|
||||
|
||||
# Essential: Add a decoration that tracks a {TextEditorMarker}. When the marker moves,
|
||||
# Essential: Add a decoration that tracks a {DisplayMarker}. When the marker moves,
|
||||
# is invalidated, or is destroyed, the decoration will be updated to reflect
|
||||
# the marker's state.
|
||||
#
|
||||
# ## Arguments
|
||||
#
|
||||
# * `marker` A {TextEditorMarker} you want this decoration to follow.
|
||||
# * `marker` A {DisplayMarker} you want this decoration to follow.
|
||||
# * `decorationParams` An {Object} representing the decoration. It is passed
|
||||
# to {TextEditor::decorateMarker} as its `decorationParams` and so supports
|
||||
# all options documented there.
|
||||
|
@ -48,7 +48,7 @@ class LayerDecoration
|
||||
|
||||
# Essential: Override the decoration properties for a specific marker.
|
||||
#
|
||||
# * `marker` The {TextEditorMarker} or {Marker} for which to override
|
||||
# * `marker` The {DisplayMarker} or {Marker} for which to override
|
||||
# properties.
|
||||
# * `properties` An {Object} containing properties to apply to this marker.
|
||||
# Pass `null` to clear the override.
|
||||
|
@ -1,192 +0,0 @@
|
||||
TextEditorMarker = require './text-editor-marker'
|
||||
|
||||
# Public: *Experimental:* A container for a related set of markers at the
|
||||
# {TextEditor} level. Wraps an underlying {MarkerLayer} on the editor's
|
||||
# {TextBuffer}.
|
||||
#
|
||||
# This API is experimental and subject to change on any release.
|
||||
module.exports =
|
||||
class TextEditorMarkerLayer
|
||||
constructor: (@displayBuffer, @bufferMarkerLayer, @isDefaultLayer) ->
|
||||
@id = @bufferMarkerLayer.id
|
||||
@markersById = {}
|
||||
|
||||
###
|
||||
Section: Lifecycle
|
||||
###
|
||||
|
||||
# Essential: Destroy this layer.
|
||||
destroy: ->
|
||||
if @isDefaultLayer
|
||||
marker.destroy() for id, marker of @markersById
|
||||
else
|
||||
@bufferMarkerLayer.destroy()
|
||||
|
||||
###
|
||||
Section: Querying
|
||||
###
|
||||
|
||||
# Essential: Get an existing marker by its id.
|
||||
#
|
||||
# Returns a {TextEditorMarker}.
|
||||
getMarker: (id) ->
|
||||
if editorMarker = @markersById[id]
|
||||
editorMarker
|
||||
else if bufferMarker = @bufferMarkerLayer.getMarker(id)
|
||||
@markersById[id] = new TextEditorMarker(this, bufferMarker)
|
||||
|
||||
# Essential: Get all markers in the layer.
|
||||
#
|
||||
# Returns an {Array} of {TextEditorMarker}s.
|
||||
getMarkers: ->
|
||||
@bufferMarkerLayer.getMarkers().map ({id}) => @getMarker(id)
|
||||
|
||||
# Public: Get the number of markers in the marker layer.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getMarkerCount: ->
|
||||
@bufferMarkerLayer.getMarkerCount()
|
||||
|
||||
# Public: Find markers in the layer conforming to the given parameters.
|
||||
#
|
||||
# See the documentation for {TextEditor::findMarkers}.
|
||||
findMarkers: (params) ->
|
||||
params = @translateToBufferMarkerParams(params)
|
||||
@bufferMarkerLayer.findMarkers(params).map (stringMarker) => @getMarker(stringMarker.id)
|
||||
|
||||
###
|
||||
Section: Marker creation
|
||||
###
|
||||
|
||||
# Essential: Create a marker on this layer with the given range in buffer
|
||||
# coordinates.
|
||||
#
|
||||
# See the documentation for {TextEditor::markBufferRange}
|
||||
markBufferRange: (bufferRange, options) ->
|
||||
@getMarker(@bufferMarkerLayer.markRange(bufferRange, options).id)
|
||||
|
||||
# Essential: Create a marker on this layer with the given range in screen
|
||||
# coordinates.
|
||||
#
|
||||
# See the documentation for {TextEditor::markScreenRange}
|
||||
markScreenRange: (screenRange, options) ->
|
||||
bufferRange = @displayBuffer.bufferRangeForScreenRange(screenRange)
|
||||
@markBufferRange(bufferRange, options)
|
||||
|
||||
# Public: Create a marker on this layer with the given buffer position and no
|
||||
# tail.
|
||||
#
|
||||
# See the documentation for {TextEditor::markBufferPosition}
|
||||
markBufferPosition: (bufferPosition, options) ->
|
||||
@getMarker(@bufferMarkerLayer.markPosition(bufferPosition, options).id)
|
||||
|
||||
# Public: Create a marker on this layer with the given screen position and no
|
||||
# tail.
|
||||
#
|
||||
# See the documentation for {TextEditor::markScreenPosition}
|
||||
markScreenPosition: (screenPosition, options) ->
|
||||
bufferPosition = @displayBuffer.bufferPositionForScreenPosition(screenPosition)
|
||||
@markBufferPosition(bufferPosition, options)
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
|
||||
# Public: Subscribe to be notified asynchronously whenever markers are
|
||||
# created, updated, or destroyed on this layer. *Prefer this method for
|
||||
# optimal performance when interacting with layers that could contain large
|
||||
# numbers of markers.*
|
||||
#
|
||||
# * `callback` A {Function} that will be called with no arguments when changes
|
||||
# occur on this layer.
|
||||
#
|
||||
# Subscribers are notified once, asynchronously when any number of changes
|
||||
# occur in a given tick of the event loop. You should re-query the layer
|
||||
# to determine the state of markers in which you're interested in. It may
|
||||
# be counter-intuitive, but this is much more efficient than subscribing to
|
||||
# events on individual markers, which are expensive to deliver.
|
||||
#
|
||||
# Returns a {Disposable}.
|
||||
onDidUpdate: (callback) ->
|
||||
@bufferMarkerLayer.onDidUpdate(callback)
|
||||
|
||||
# Public: Subscribe to be notified synchronously whenever markers are created
|
||||
# on this layer. *Avoid this method for optimal performance when interacting
|
||||
# with layers that could contain large numbers of markers.*
|
||||
#
|
||||
# * `callback` A {Function} that will be called with a {TextEditorMarker}
|
||||
# whenever a new marker is created.
|
||||
#
|
||||
# You should prefer {onDidUpdate} when synchronous notifications aren't
|
||||
# absolutely necessary.
|
||||
#
|
||||
# Returns a {Disposable}.
|
||||
onDidCreateMarker: (callback) ->
|
||||
@bufferMarkerLayer.onDidCreateMarker (bufferMarker) =>
|
||||
callback(@getMarker(bufferMarker.id))
|
||||
|
||||
# Public: Subscribe to be notified synchronously when this layer is destroyed.
|
||||
#
|
||||
# Returns a {Disposable}.
|
||||
onDidDestroy: (callback) ->
|
||||
@bufferMarkerLayer.onDidDestroy(callback)
|
||||
|
||||
###
|
||||
Section: Private
|
||||
###
|
||||
|
||||
refreshMarkerScreenPositions: ->
|
||||
for marker in @getMarkers()
|
||||
marker.notifyObservers(textChanged: false)
|
||||
return
|
||||
|
||||
didDestroyMarker: (marker) ->
|
||||
delete @markersById[marker.id]
|
||||
|
||||
translateToBufferMarkerParams: (params) ->
|
||||
bufferMarkerParams = {}
|
||||
for key, value of params
|
||||
switch key
|
||||
when 'startBufferPosition'
|
||||
key = 'startPosition'
|
||||
when 'endBufferPosition'
|
||||
key = 'endPosition'
|
||||
when 'startScreenPosition'
|
||||
key = 'startPosition'
|
||||
value = @displayBuffer.bufferPositionForScreenPosition(value)
|
||||
when 'endScreenPosition'
|
||||
key = 'endPosition'
|
||||
value = @displayBuffer.bufferPositionForScreenPosition(value)
|
||||
when 'startBufferRow'
|
||||
key = 'startRow'
|
||||
when 'endBufferRow'
|
||||
key = 'endRow'
|
||||
when 'startScreenRow'
|
||||
key = 'startRow'
|
||||
value = @displayBuffer.bufferRowForScreenRow(value)
|
||||
when 'endScreenRow'
|
||||
key = 'endRow'
|
||||
value = @displayBuffer.bufferRowForScreenRow(value)
|
||||
when 'intersectsBufferRowRange'
|
||||
key = 'intersectsRowRange'
|
||||
when 'intersectsScreenRowRange'
|
||||
key = 'intersectsRowRange'
|
||||
[startRow, endRow] = value
|
||||
value = [@displayBuffer.bufferRowForScreenRow(startRow), @displayBuffer.bufferRowForScreenRow(endRow)]
|
||||
when 'containsBufferRange'
|
||||
key = 'containsRange'
|
||||
when 'containsBufferPosition'
|
||||
key = 'containsPosition'
|
||||
when 'containedInBufferRange'
|
||||
key = 'containedInRange'
|
||||
when 'containedInScreenRange'
|
||||
key = 'containedInRange'
|
||||
value = @displayBuffer.bufferRangeForScreenRange(value)
|
||||
when 'intersectsBufferRange'
|
||||
key = 'intersectsRange'
|
||||
when 'intersectsScreenRange'
|
||||
key = 'intersectsRange'
|
||||
value = @displayBuffer.bufferRangeForScreenRange(value)
|
||||
bufferMarkerParams[key] = value
|
||||
|
||||
bufferMarkerParams
|
@ -1,371 +0,0 @@
|
||||
_ = require 'underscore-plus'
|
||||
{CompositeDisposable, Emitter} = require 'event-kit'
|
||||
|
||||
# Essential: Represents a buffer annotation that remains logically stationary
|
||||
# even as the buffer changes. This is used to represent cursors, folds, snippet
|
||||
# targets, misspelled words, and anything else that needs to track a logical
|
||||
# location in the buffer over time.
|
||||
#
|
||||
# ### TextEditorMarker Creation
|
||||
#
|
||||
# Use {TextEditor::markBufferRange} rather than creating Markers directly.
|
||||
#
|
||||
# ### Head and Tail
|
||||
#
|
||||
# Markers always have a *head* and sometimes have a *tail*. If you think of a
|
||||
# marker as an editor selection, the tail is the part that's stationary and the
|
||||
# head is the part that moves when the mouse is moved. A marker without a tail
|
||||
# always reports an empty range at the head position. A marker with a head position
|
||||
# greater than the tail is in a "normal" orientation. If the head precedes the
|
||||
# tail the marker is in a "reversed" orientation.
|
||||
#
|
||||
# ### Validity
|
||||
#
|
||||
# Markers are considered *valid* when they are first created. Depending on the
|
||||
# invalidation strategy you choose, certain changes to the buffer can cause a
|
||||
# marker to become invalid, for example if the text surrounding the marker is
|
||||
# deleted. The strategies, in order of descending fragility:
|
||||
#
|
||||
# * __never__: The marker is never marked as invalid. This is a good choice for
|
||||
# markers representing selections in an editor.
|
||||
# * __surround__: The marker is invalidated by changes that completely surround it.
|
||||
# * __overlap__: The marker is invalidated by changes that surround the
|
||||
# start or end of the marker. This is the default.
|
||||
# * __inside__: The marker is invalidated by changes that extend into the
|
||||
# inside of the marker. Changes that end at the marker's start or
|
||||
# start at the marker's end do not invalidate the marker.
|
||||
# * __touch__: The marker is invalidated by a change that touches the marked
|
||||
# region in any way, including changes that end at the marker's
|
||||
# start or start at the marker's end. This is the most fragile strategy.
|
||||
#
|
||||
# See {TextEditor::markBufferRange} for usage.
|
||||
module.exports =
|
||||
class TextEditorMarker
|
||||
bufferMarkerSubscription: null
|
||||
oldHeadBufferPosition: null
|
||||
oldHeadScreenPosition: null
|
||||
oldTailBufferPosition: null
|
||||
oldTailScreenPosition: null
|
||||
wasValid: true
|
||||
hasChangeObservers: false
|
||||
|
||||
###
|
||||
Section: Construction and Destruction
|
||||
###
|
||||
|
||||
constructor: (@layer, @bufferMarker) ->
|
||||
{@displayBuffer} = @layer
|
||||
@emitter = new Emitter
|
||||
@disposables = new CompositeDisposable
|
||||
@id = @bufferMarker.id
|
||||
|
||||
@disposables.add @bufferMarker.onDidDestroy => @destroyed()
|
||||
|
||||
# Essential: Destroys the marker, causing it to emit the 'destroyed' event. Once
|
||||
# destroyed, a marker cannot be restored by undo/redo operations.
|
||||
destroy: ->
|
||||
@bufferMarker.destroy()
|
||||
@disposables.dispose()
|
||||
|
||||
# Essential: Creates and returns a new {TextEditorMarker} with the same properties as
|
||||
# this marker.
|
||||
#
|
||||
# {Selection} markers (markers with a custom property `type: "selection"`)
|
||||
# should be copied with a different `type` value, for example with
|
||||
# `marker.copy({type: null})`. Otherwise, the new marker's selection will
|
||||
# be merged with this marker's selection, and a `null` value will be
|
||||
# returned.
|
||||
#
|
||||
# * `properties` (optional) {Object} properties to associate with the new
|
||||
# marker. The new marker's properties are computed by extending this marker's
|
||||
# properties with `properties`.
|
||||
#
|
||||
# Returns a {TextEditorMarker}.
|
||||
copy: (properties) ->
|
||||
@layer.getMarker(@bufferMarker.copy(properties).id)
|
||||
|
||||
###
|
||||
Section: Event Subscription
|
||||
###
|
||||
|
||||
# Essential: Invoke the given callback when the state of the marker changes.
|
||||
#
|
||||
# * `callback` {Function} to be called when the marker changes.
|
||||
# * `event` {Object} with the following keys:
|
||||
# * `oldHeadBufferPosition` {Point} representing the former head buffer position
|
||||
# * `newHeadBufferPosition` {Point} representing the new head buffer position
|
||||
# * `oldTailBufferPosition` {Point} representing the former tail buffer position
|
||||
# * `newTailBufferPosition` {Point} representing the new tail buffer position
|
||||
# * `oldHeadScreenPosition` {Point} representing the former head screen position
|
||||
# * `newHeadScreenPosition` {Point} representing the new head screen position
|
||||
# * `oldTailScreenPosition` {Point} representing the former tail screen position
|
||||
# * `newTailScreenPosition` {Point} representing the new tail screen position
|
||||
# * `wasValid` {Boolean} indicating whether the marker was valid before the change
|
||||
# * `isValid` {Boolean} indicating whether the marker is now valid
|
||||
# * `hadTail` {Boolean} indicating whether the marker had a tail before the change
|
||||
# * `hasTail` {Boolean} indicating whether the marker now has a tail
|
||||
# * `oldProperties` {Object} containing the marker's custom properties before the change.
|
||||
# * `newProperties` {Object} containing the marker's custom properties after the change.
|
||||
# * `textChanged` {Boolean} indicating whether this change was caused by a textual change
|
||||
# to the buffer or whether the marker was manipulated directly via its public API.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# * `callback` {Function} to be called when the marker is destroyed.
|
||||
#
|
||||
# Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
||||
onDidDestroy: (callback) ->
|
||||
@emitter.on 'did-destroy', callback
|
||||
|
||||
###
|
||||
Section: TextEditorMarker Details
|
||||
###
|
||||
|
||||
# Essential: Returns a {Boolean} indicating whether the marker is valid. Markers can be
|
||||
# invalidated when a region surrounding them in the buffer is changed.
|
||||
isValid: ->
|
||||
@bufferMarker.isValid()
|
||||
|
||||
# Essential: Returns a {Boolean} indicating whether the marker has been destroyed. A marker
|
||||
# can be invalid without being destroyed, in which case undoing the invalidating
|
||||
# operation would restore the marker. Once a marker is destroyed by calling
|
||||
# {TextEditorMarker::destroy}, no undo/redo operation can ever bring it back.
|
||||
isDestroyed: ->
|
||||
@bufferMarker.isDestroyed()
|
||||
|
||||
# Essential: Returns a {Boolean} indicating whether the head precedes the tail.
|
||||
isReversed: ->
|
||||
@bufferMarker.isReversed()
|
||||
|
||||
# Essential: Get the invalidation strategy for this marker.
|
||||
#
|
||||
# Valid values include: `never`, `surround`, `overlap`, `inside`, and `touch`.
|
||||
#
|
||||
# Returns a {String}.
|
||||
getInvalidationStrategy: ->
|
||||
@bufferMarker.getInvalidationStrategy()
|
||||
|
||||
# Essential: Returns an {Object} containing any custom properties associated with
|
||||
# the marker.
|
||||
getProperties: ->
|
||||
@bufferMarker.getProperties()
|
||||
|
||||
# Essential: Merges an {Object} containing new properties into the marker's
|
||||
# existing properties.
|
||||
#
|
||||
# * `properties` {Object}
|
||||
setProperties: (properties) ->
|
||||
@bufferMarker.setProperties(properties)
|
||||
|
||||
matchesProperties: (attributes) ->
|
||||
attributes = @layer.translateToBufferMarkerParams(attributes)
|
||||
@bufferMarker.matchesParams(attributes)
|
||||
|
||||
###
|
||||
Section: Comparing to other markers
|
||||
###
|
||||
|
||||
# Essential: Returns a {Boolean} indicating whether this marker is equivalent to
|
||||
# another marker, meaning they have the same range and options.
|
||||
#
|
||||
# * `other` {TextEditorMarker} other marker
|
||||
isEqual: (other) ->
|
||||
return false unless other instanceof @constructor
|
||||
@bufferMarker.isEqual(other.bufferMarker)
|
||||
|
||||
# Essential: Compares this marker to another based on their ranges.
|
||||
#
|
||||
# * `other` {TextEditorMarker}
|
||||
#
|
||||
# Returns a {Number}
|
||||
compare: (other) ->
|
||||
@bufferMarker.compare(other.bufferMarker)
|
||||
|
||||
###
|
||||
Section: Managing the marker's range
|
||||
###
|
||||
|
||||
# Essential: Gets the buffer range of the display marker.
|
||||
#
|
||||
# Returns a {Range}.
|
||||
getBufferRange: ->
|
||||
@bufferMarker.getRange()
|
||||
|
||||
# Essential: Modifies the buffer range of the display marker.
|
||||
#
|
||||
# * `bufferRange` The new {Range} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
# * `reversed` {Boolean} If true, the marker will to be in a reversed orientation.
|
||||
setBufferRange: (bufferRange, properties) ->
|
||||
@bufferMarker.setRange(bufferRange, properties)
|
||||
|
||||
# Essential: Gets the screen range of the display marker.
|
||||
#
|
||||
# Returns a {Range}.
|
||||
getScreenRange: ->
|
||||
@displayBuffer.screenRangeForBufferRange(@getBufferRange(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Essential: Modifies the screen range of the display marker.
|
||||
#
|
||||
# * `screenRange` The new {Range} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
# * `reversed` {Boolean} If true, the marker will to be in a reversed orientation.
|
||||
setScreenRange: (screenRange, options) ->
|
||||
@setBufferRange(@displayBuffer.bufferRangeForScreenRange(screenRange), options)
|
||||
|
||||
# Essential: Retrieves the buffer position of the marker's start. This will always be
|
||||
# less than or equal to the result of {TextEditorMarker::getEndBufferPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getStartBufferPosition: ->
|
||||
@bufferMarker.getStartPosition()
|
||||
|
||||
# Essential: Retrieves the screen position of the marker's start. This will always be
|
||||
# less than or equal to the result of {TextEditorMarker::getEndScreenPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getStartScreenPosition: ->
|
||||
@displayBuffer.screenPositionForBufferPosition(@getStartBufferPosition(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Essential: Retrieves the buffer position of the marker's end. This will always be
|
||||
# greater than or equal to the result of {TextEditorMarker::getStartBufferPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getEndBufferPosition: ->
|
||||
@bufferMarker.getEndPosition()
|
||||
|
||||
# Essential: Retrieves the screen position of the marker's end. This will always be
|
||||
# greater than or equal to the result of {TextEditorMarker::getStartScreenPosition}.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getEndScreenPosition: ->
|
||||
@displayBuffer.screenPositionForBufferPosition(@getEndBufferPosition(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Extended: Retrieves the buffer position of the marker's head.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getHeadBufferPosition: ->
|
||||
@bufferMarker.getHeadPosition()
|
||||
|
||||
# Extended: Sets the buffer position of the marker's head.
|
||||
#
|
||||
# * `bufferPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setHeadBufferPosition: (bufferPosition, properties) ->
|
||||
@bufferMarker.setHeadPosition(bufferPosition, properties)
|
||||
|
||||
# Extended: Retrieves the screen position of the marker's head.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getHeadScreenPosition: ->
|
||||
@displayBuffer.screenPositionForBufferPosition(@getHeadBufferPosition(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Extended: Sets the screen position of the marker's head.
|
||||
#
|
||||
# * `screenPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setHeadScreenPosition: (screenPosition, properties) ->
|
||||
@setHeadBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, properties))
|
||||
|
||||
# Extended: Retrieves the buffer position of the marker's tail.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getTailBufferPosition: ->
|
||||
@bufferMarker.getTailPosition()
|
||||
|
||||
# Extended: Sets the buffer position of the marker's tail.
|
||||
#
|
||||
# * `bufferPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setTailBufferPosition: (bufferPosition) ->
|
||||
@bufferMarker.setTailPosition(bufferPosition)
|
||||
|
||||
# Extended: Retrieves the screen position of the marker's tail.
|
||||
#
|
||||
# Returns a {Point}.
|
||||
getTailScreenPosition: ->
|
||||
@displayBuffer.screenPositionForBufferPosition(@getTailBufferPosition(), wrapAtSoftNewlines: true)
|
||||
|
||||
# Extended: Sets the screen position of the marker's tail.
|
||||
#
|
||||
# * `screenPosition` The new {Point} to use
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
setTailScreenPosition: (screenPosition, options) ->
|
||||
@setTailBufferPosition(@displayBuffer.bufferPositionForScreenPosition(screenPosition, options))
|
||||
|
||||
# Extended: Returns a {Boolean} indicating whether the marker has a tail.
|
||||
hasTail: ->
|
||||
@bufferMarker.hasTail()
|
||||
|
||||
# Extended: Plants the marker's tail at the current head position. After calling
|
||||
# the marker's tail position will be its head position at the time of the
|
||||
# call, regardless of where the marker's head is moved.
|
||||
#
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
plantTail: ->
|
||||
@bufferMarker.plantTail()
|
||||
|
||||
# Extended: Removes the marker's tail. After calling the marker's head position
|
||||
# will be reported as its current tail position until the tail is planted
|
||||
# again.
|
||||
#
|
||||
# * `properties` (optional) {Object} properties to associate with the marker.
|
||||
clearTail: (properties) ->
|
||||
@bufferMarker.clearTail(properties)
|
||||
|
||||
###
|
||||
Section: Private utility methods
|
||||
###
|
||||
|
||||
# Returns a {String} representation of the marker
|
||||
inspect: ->
|
||||
"TextEditorMarker(id: #{@id}, bufferRange: #{@getBufferRange()})"
|
||||
|
||||
destroyed: ->
|
||||
@layer.didDestroyMarker(this)
|
||||
@emitter.emit 'did-destroy'
|
||||
@emitter.dispose()
|
||||
|
||||
notifyObservers: ({textChanged}) ->
|
||||
textChanged ?= false
|
||||
|
||||
newHeadBufferPosition = @getHeadBufferPosition()
|
||||
newHeadScreenPosition = @getHeadScreenPosition()
|
||||
newTailBufferPosition = @getTailBufferPosition()
|
||||
newTailScreenPosition = @getTailScreenPosition()
|
||||
isValid = @isValid()
|
||||
|
||||
return if isValid is @wasValid and
|
||||
newHeadBufferPosition.isEqual(@oldHeadBufferPosition) and
|
||||
newHeadScreenPosition.isEqual(@oldHeadScreenPosition) and
|
||||
newTailBufferPosition.isEqual(@oldTailBufferPosition) and
|
||||
newTailScreenPosition.isEqual(@oldTailScreenPosition)
|
||||
|
||||
changeEvent = {
|
||||
@oldHeadScreenPosition, newHeadScreenPosition,
|
||||
@oldTailScreenPosition, newTailScreenPosition,
|
||||
@oldHeadBufferPosition, newHeadBufferPosition,
|
||||
@oldTailBufferPosition, newTailBufferPosition,
|
||||
textChanged,
|
||||
isValid
|
||||
}
|
||||
|
||||
@oldHeadBufferPosition = newHeadBufferPosition
|
||||
@oldHeadScreenPosition = newHeadScreenPosition
|
||||
@oldTailBufferPosition = newTailBufferPosition
|
||||
@oldTailScreenPosition = newTailScreenPosition
|
||||
@wasValid = isValid
|
||||
|
||||
@emitter.emit 'did-change', changeEvent
|
@ -116,8 +116,7 @@ class TextEditor extends Model
|
||||
buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode,
|
||||
@config, @assert, @grammarRegistry, @packageManager
|
||||
})
|
||||
@buffer = @displayBuffer.buffer
|
||||
@displayLayer = buffer.addDisplayLayer({tabLength: @displayBuffer.getTabLength()})
|
||||
{@buffer, @displayLayer} = @displayBuffer
|
||||
@selectionsMarkerLayer ?= @addMarkerLayer(maintainHistory: true)
|
||||
|
||||
for marker in @selectionsMarkerLayer.getMarkers()
|
||||
@ -1427,7 +1426,7 @@ class TextEditor extends Model
|
||||
Section: Decorations
|
||||
###
|
||||
|
||||
# Essential: Add a decoration that tracks a {TextEditorMarker}. When the
|
||||
# Essential: Add a decoration that tracks a {DisplayMarker}. When the
|
||||
# marker moves, is invalidated, or is destroyed, the decoration will be
|
||||
# updated to reflect the marker's state.
|
||||
#
|
||||
@ -1448,28 +1447,28 @@ class TextEditor extends Model
|
||||
# </div>
|
||||
# ```
|
||||
# * __overlay__: Positions the view associated with the given item at the head
|
||||
# or tail of the given `TextEditorMarker`.
|
||||
# * __gutter__: A decoration that tracks a {TextEditorMarker} in a {Gutter}. Gutter
|
||||
# or tail of the given `DisplayMarker`.
|
||||
# * __gutter__: A decoration that tracks a {DisplayMarker} in a {Gutter}. Gutter
|
||||
# decorations are created by calling {Gutter::decorateMarker} on the
|
||||
# desired `Gutter` instance.
|
||||
#
|
||||
# ## Arguments
|
||||
#
|
||||
# * `marker` A {TextEditorMarker} you want this decoration to follow.
|
||||
# * `marker` A {DisplayMarker} you want this decoration to follow.
|
||||
# * `decorationParams` An {Object} representing the decoration e.g.
|
||||
# `{type: 'line-number', class: 'linter-error'}`
|
||||
# * `type` There are several supported decoration types. The behavior of the
|
||||
# types are as follows:
|
||||
# * `line` Adds the given `class` to the lines overlapping the rows
|
||||
# spanned by the `TextEditorMarker`.
|
||||
# spanned by the `DisplayMarker`.
|
||||
# * `line-number` Adds the given `class` to the line numbers overlapping
|
||||
# the rows spanned by the `TextEditorMarker`.
|
||||
# the rows spanned by the `DisplayMarker`.
|
||||
# * `highlight` Creates a `.highlight` div with the nested class with up
|
||||
# to 3 nested regions that fill the area spanned by the `TextEditorMarker`.
|
||||
# to 3 nested regions that fill the area spanned by the `DisplayMarker`.
|
||||
# * `overlay` Positions the view associated with the given item at the
|
||||
# head or tail of the given `TextEditorMarker`, depending on the `position`
|
||||
# head or tail of the given `DisplayMarker`, depending on the `position`
|
||||
# property.
|
||||
# * `gutter` Tracks a {TextEditorMarker} in a {Gutter}. Created by calling
|
||||
# * `gutter` Tracks a {DisplayMarker} in a {Gutter}. Created by calling
|
||||
# {Gutter::decorateMarker} on the desired `Gutter` instance.
|
||||
# * `class` This CSS class will be applied to the decorated line number,
|
||||
# line, highlight, or overlay.
|
||||
@ -1477,16 +1476,16 @@ class TextEditor extends Model
|
||||
# corresponding view registered. Only applicable to the `gutter` and
|
||||
# `overlay` types.
|
||||
# * `onlyHead` (optional) If `true`, the decoration will only be applied to
|
||||
# the head of the `TextEditorMarker`. Only applicable to the `line` and
|
||||
# the head of the `DisplayMarker`. Only applicable to the `line` and
|
||||
# `line-number` types.
|
||||
# * `onlyEmpty` (optional) If `true`, the decoration will only be applied if
|
||||
# the associated `TextEditorMarker` is empty. Only applicable to the `gutter`,
|
||||
# the associated `DisplayMarker` is empty. Only applicable to the `gutter`,
|
||||
# `line`, and `line-number` types.
|
||||
# * `onlyNonEmpty` (optional) If `true`, the decoration will only be applied
|
||||
# if the associated `TextEditorMarker` is non-empty. Only applicable to the
|
||||
# if the associated `DisplayMarker` is non-empty. Only applicable to the
|
||||
# `gutter`, `line`, and `line-number` types.
|
||||
# * `position` (optional) Only applicable to decorations of type `overlay`,
|
||||
# controls where the overlay view is positioned relative to the `TextEditorMarker`.
|
||||
# controls where the overlay view is positioned relative to the `DisplayMarker`.
|
||||
# Values can be `'head'` (the default), or `'tail'`.
|
||||
#
|
||||
# Returns a {Decoration} object
|
||||
@ -1497,7 +1496,7 @@ class TextEditor extends Model
|
||||
# marker layer. Can be used to decorate a large number of markers without
|
||||
# having to create and manage many individual decorations.
|
||||
#
|
||||
# * `markerLayer` A {TextEditorMarkerLayer} or {MarkerLayer} to decorate.
|
||||
# * `markerLayer` A {DisplayMarkerLayer} or {MarkerLayer} to decorate.
|
||||
# * `decorationParams` The same parameters that are passed to
|
||||
# {decorateMarker}, except the `type` cannot be `overlay` or `gutter`.
|
||||
#
|
||||
@ -1515,7 +1514,7 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns an {Object} of decorations in the form
|
||||
# `{1: [{id: 10, type: 'line-number', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are {TextEditorMarker} IDs, and the values are an array of decoration
|
||||
# where the keys are {DisplayMarker} IDs, and the values are an array of decoration
|
||||
# params objects attached to the marker.
|
||||
# Returns an empty object when no decorations are found
|
||||
decorationsForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
@ -1610,7 +1609,7 @@ class TextEditor extends Model
|
||||
# region in any way, including changes that end at the marker's
|
||||
# start or start at the marker's end. This is the most fragile strategy.
|
||||
#
|
||||
# Returns a {TextEditorMarker}.
|
||||
# Returns a {DisplayMarker}.
|
||||
markBufferRange: (args...) ->
|
||||
@displayBuffer.markBufferRange(args...)
|
||||
|
||||
@ -1645,7 +1644,7 @@ class TextEditor extends Model
|
||||
# region in any way, including changes that end at the marker's
|
||||
# start or start at the marker's end. This is the most fragile strategy.
|
||||
#
|
||||
# Returns a {TextEditorMarker}.
|
||||
# Returns a {DisplayMarker}.
|
||||
markScreenRange: (args...) ->
|
||||
@displayBuffer.markScreenRange(args...)
|
||||
|
||||
@ -1655,7 +1654,7 @@ class TextEditor extends Model
|
||||
# * `position` A {Point} or {Array} of `[row, column]`.
|
||||
# * `options` (optional) See {TextBuffer::markRange}.
|
||||
#
|
||||
# Returns a {TextEditorMarker}.
|
||||
# Returns a {DisplayMarker}.
|
||||
markBufferPosition: (args...) ->
|
||||
@displayBuffer.markBufferPosition(args...)
|
||||
|
||||
@ -1665,11 +1664,11 @@ class TextEditor extends Model
|
||||
# * `position` A {Point} or {Array} of `[row, column]`.
|
||||
# * `options` (optional) See {TextBuffer::markRange}.
|
||||
#
|
||||
# Returns a {TextEditorMarker}.
|
||||
# Returns a {DisplayMarker}.
|
||||
markScreenPosition: (args...) ->
|
||||
@displayBuffer.markScreenPosition(args...)
|
||||
|
||||
# Essential: Find all {TextEditorMarker}s on the default marker layer that
|
||||
# Essential: Find all {DisplayMarker}s on the default marker layer that
|
||||
# match the given properties.
|
||||
#
|
||||
# This method finds markers based on the given properties. Markers can be
|
||||
@ -1692,14 +1691,14 @@ class TextEditor extends Model
|
||||
findMarkers: (properties) ->
|
||||
@displayBuffer.findMarkers(properties)
|
||||
|
||||
# Extended: Get the {TextEditorMarker} on the default layer for the given
|
||||
# Extended: Get the {DisplayMarker} on the default layer for the given
|
||||
# marker id.
|
||||
#
|
||||
# * `id` {Number} id of the marker
|
||||
getMarker: (id) ->
|
||||
@displayBuffer.getMarker(id)
|
||||
|
||||
# Extended: Get all {TextEditorMarker}s on the default marker layer. Consider
|
||||
# Extended: Get all {DisplayMarker}s on the default marker layer. Consider
|
||||
# using {::findMarkers}
|
||||
getMarkers: ->
|
||||
@displayBuffer.getMarkers()
|
||||
@ -1721,11 +1720,11 @@ class TextEditor extends Model
|
||||
#
|
||||
# This API is experimental and subject to change on any release.
|
||||
#
|
||||
# Returns a {TextEditorMarkerLayer}.
|
||||
# Returns a {DisplayMarkerLayer}.
|
||||
addMarkerLayer: (options) ->
|
||||
@displayBuffer.addMarkerLayer(options)
|
||||
|
||||
# Public: *Experimental:* Get a {TextEditorMarkerLayer} by id.
|
||||
# Public: *Experimental:* Get a {DisplayMarkerLayer} by id.
|
||||
#
|
||||
# * `id` The id of the marker layer to retrieve.
|
||||
#
|
||||
@ -1736,14 +1735,14 @@ class TextEditor extends Model
|
||||
getMarkerLayer: (id) ->
|
||||
@displayBuffer.getMarkerLayer(id)
|
||||
|
||||
# Public: *Experimental:* Get the default {TextEditorMarkerLayer}.
|
||||
# Public: *Experimental:* Get the default {DisplayMarkerLayer}.
|
||||
#
|
||||
# All marker APIs not tied to an explicit layer interact with this default
|
||||
# layer.
|
||||
#
|
||||
# This API is experimental and subject to change on any release.
|
||||
#
|
||||
# Returns a {TextEditorMarkerLayer}.
|
||||
# Returns a {DisplayMarkerLayer}.
|
||||
getDefaultMarkerLayer: ->
|
||||
@displayBuffer.getDefaultMarkerLayer()
|
||||
|
||||
@ -1950,7 +1949,7 @@ class TextEditor extends Model
|
||||
getCursorsOrderedByBufferPosition: ->
|
||||
@getCursors().sort (a, b) -> a.compare(b)
|
||||
|
||||
# Add a cursor based on the given {TextEditorMarker}.
|
||||
# Add a cursor based on the given {DisplayMarker}.
|
||||
addCursor: (marker) ->
|
||||
cursor = new Cursor(editor: this, marker: marker, config: @config)
|
||||
@cursors.push(cursor)
|
||||
@ -2299,7 +2298,7 @@ class TextEditor extends Model
|
||||
|
||||
# Extended: Select the range of the given marker if it is valid.
|
||||
#
|
||||
# * `marker` A {TextEditorMarker}
|
||||
# * `marker` A {DisplayMarker}
|
||||
#
|
||||
# Returns the selected {Range} or `undefined` if the marker is invalid.
|
||||
selectMarker: (marker) ->
|
||||
@ -2425,9 +2424,9 @@ class TextEditor extends Model
|
||||
_.reduce(tail, reducer, [head])
|
||||
return result if fn?
|
||||
|
||||
# Add a {Selection} based on the given {TextEditorMarker}.
|
||||
# Add a {Selection} based on the given {DisplayMarker}.
|
||||
#
|
||||
# * `marker` The {TextEditorMarker} to highlight
|
||||
# * `marker` The {DisplayMarker} to highlight
|
||||
# * `options` (optional) An {Object} that pertains to the {Selection} constructor.
|
||||
#
|
||||
# Returns the new {Selection}.
|
||||
|
Loading…
Reference in New Issue
Block a user