mirror of
https://github.com/atom/atom.git
synced 2026-02-16 09:35:54 -05:00
Merge branch 'master' into mb-synchronous-scroll-position
Conflicts: src/text-editor-presenter.coffee src/text-editor.coffee
This commit is contained in:
@@ -72,6 +72,7 @@ class TextEditor extends Model
|
||||
throw error
|
||||
|
||||
state.displayBuffer = displayBuffer
|
||||
state.selectionsMarkerLayer = displayBuffer.getMarkerLayer(state.selectionsMarkerLayerId)
|
||||
state.config = atomEnvironment.config
|
||||
state.notificationManager = atomEnvironment.notifications
|
||||
state.packageManager = atomEnvironment.packages
|
||||
@@ -87,10 +88,11 @@ class TextEditor extends Model
|
||||
super
|
||||
|
||||
{
|
||||
@softTabs, @firstVisibleScreenRow, @firstVisibleScreenColumn, initialLine, initialColumn, tabLength,
|
||||
softWrapped, @displayBuffer, buffer, suppressCursorCreation, @mini, @placeholderText,
|
||||
lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager,
|
||||
@clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate
|
||||
@softTabs, @firstVisibleScreenRow, @firstVisibleScreenColumn, initialLine,initialColumn, tabLength,
|
||||
softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation,
|
||||
@mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config,
|
||||
@notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry,
|
||||
@project, @assert, @applicationDelegate
|
||||
} = params
|
||||
|
||||
throw new Error("Must pass a config parameter when constructing TextEditors") unless @config?
|
||||
@@ -115,8 +117,9 @@ class TextEditor extends Model
|
||||
@config, @assert, @grammarRegistry, @packageManager
|
||||
})
|
||||
@buffer = @displayBuffer.buffer
|
||||
@selectionsMarkerLayer ?= @addMarkerLayer(maintainHistory: true)
|
||||
|
||||
for marker in @findMarkers(@getSelectionMarkerAttributes())
|
||||
for marker in @selectionsMarkerLayer.getMarkers()
|
||||
marker.setProperties(preserveFolds: true)
|
||||
@addSelection(marker)
|
||||
|
||||
@@ -146,6 +149,7 @@ class TextEditor extends Model
|
||||
firstVisibleScreenRow: @getFirstVisibleScreenRow()
|
||||
firstVisibleScreenColumn: @getFirstVisibleScreenColumn()
|
||||
displayBuffer: @displayBuffer.serialize()
|
||||
selectionsMarkerLayerId: @selectionsMarkerLayer.id
|
||||
|
||||
subscribeToBuffer: ->
|
||||
@buffer.retain()
|
||||
@@ -161,9 +165,9 @@ class TextEditor extends Model
|
||||
@preserveCursorPositionOnBufferReload()
|
||||
|
||||
subscribeToDisplayBuffer: ->
|
||||
@disposables.add @displayBuffer.onDidCreateMarker @handleMarkerCreated
|
||||
@disposables.add @displayBuffer.onDidChangeGrammar => @handleGrammarChange()
|
||||
@disposables.add @displayBuffer.onDidTokenize => @handleTokenization()
|
||||
@disposables.add @selectionsMarkerLayer.onDidCreateMarker @addSelection.bind(this)
|
||||
@disposables.add @displayBuffer.onDidChangeGrammar @handleGrammarChange.bind(this)
|
||||
@disposables.add @displayBuffer.onDidTokenize @handleTokenization.bind(this)
|
||||
@disposables.add @displayBuffer.onDidChange (e) =>
|
||||
@mergeIntersectingSelections()
|
||||
@emitter.emit 'did-change', e
|
||||
@@ -177,6 +181,7 @@ class TextEditor extends Model
|
||||
@disposables.dispose()
|
||||
@tabTypeSubscription.dispose()
|
||||
selection.destroy() for selection in @selections.slice()
|
||||
@selectionsMarkerLayer.destroy()
|
||||
@buffer.release()
|
||||
@displayBuffer.destroy()
|
||||
@languageMode.destroy()
|
||||
@@ -471,6 +476,9 @@ class TextEditor extends Model
|
||||
onDidUpdateMarkers: (callback) ->
|
||||
@displayBuffer.onDidUpdateMarkers(callback)
|
||||
|
||||
onDidUpdateDecorations: (callback) ->
|
||||
@displayBuffer.onDidUpdateDecorations(callback)
|
||||
|
||||
# Essential: Retrieves the current {TextBuffer}.
|
||||
getBuffer: -> @buffer
|
||||
|
||||
@@ -480,14 +488,13 @@ class TextEditor extends Model
|
||||
# Create an {TextEditor} with its initial state based on this object
|
||||
copy: ->
|
||||
displayBuffer = @displayBuffer.copy()
|
||||
selectionsMarkerLayer = displayBuffer.getMarkerLayer(@buffer.getMarkerLayer(@selectionsMarkerLayer.id).copy().id)
|
||||
softTabs = @getSoftTabs()
|
||||
newEditor = new TextEditor({
|
||||
@buffer, displayBuffer, @tabLength, softTabs, suppressCursorCreation: true,
|
||||
@config, @notificationManager, @packageManager, @clipboard, @viewRegistry,
|
||||
@grammarRegistry, @project, @assert, @applicationDelegate
|
||||
@buffer, displayBuffer, selectionsMarkerLayer, @tabLength, softTabs,
|
||||
suppressCursorCreation: true, @config, @notificationManager, @packageManager,
|
||||
@clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate
|
||||
})
|
||||
for marker in @findMarkers(editorId: @id)
|
||||
marker.copy(editorId: newEditor.id, preserveFolds: true)
|
||||
newEditor
|
||||
|
||||
# Controls visibility based on the given {Boolean}.
|
||||
@@ -502,6 +509,9 @@ class TextEditor extends Model
|
||||
|
||||
isMini: -> @mini
|
||||
|
||||
setUpdatedSynchronously: (updatedSynchronously) ->
|
||||
@displayBuffer.setUpdatedSynchronously(updatedSynchronously)
|
||||
|
||||
onDidChangeMini: (callback) ->
|
||||
@emitter.on 'did-change-mini', callback
|
||||
|
||||
@@ -869,116 +879,177 @@ class TextEditor extends Model
|
||||
@transact groupingInterval, =>
|
||||
fn(selection, index) for selection, index in @getSelectionsOrderedByBufferPosition()
|
||||
|
||||
# Move lines intersection the most recent selection up by one row in screen
|
||||
# coordinates.
|
||||
# Move lines intersecting the most recent selection or multiple selections
|
||||
# up by one row in screen coordinates.
|
||||
moveLineUp: ->
|
||||
selection = @getSelectedBufferRange()
|
||||
return if selection.start.row is 0
|
||||
lastRow = @buffer.getLastRow()
|
||||
return if selection.isEmpty() and selection.start.row is lastRow and @buffer.getLastLine() is ''
|
||||
selections = @getSelectedBufferRanges()
|
||||
selections.sort (a, b) -> a.compare(b)
|
||||
|
||||
if selections[0].start.row is 0
|
||||
return
|
||||
|
||||
if selections[selections.length - 1].start.row is @getLastBufferRow() and @buffer.getLastLine() is ''
|
||||
return
|
||||
|
||||
@transact =>
|
||||
foldedRows = []
|
||||
rows = [selection.start.row..selection.end.row]
|
||||
if selection.start.row isnt selection.end.row and selection.end.column is 0
|
||||
rows.pop() unless @isFoldedAtBufferRow(selection.end.row)
|
||||
newSelectionRanges = []
|
||||
|
||||
# Move line around the fold that is directly above the selection
|
||||
precedingScreenRow = @screenPositionForBufferPosition([selection.start.row]).translate([-1])
|
||||
precedingBufferRow = @bufferPositionForScreenPosition(precedingScreenRow).row
|
||||
if fold = @largestFoldContainingBufferRow(precedingBufferRow)
|
||||
insertDelta = fold.getBufferRange().getRowCount()
|
||||
else
|
||||
insertDelta = 1
|
||||
while selections.length > 0
|
||||
# Find selections spanning a contiguous set of lines
|
||||
selection = selections.shift()
|
||||
selectionsToMove = [selection]
|
||||
|
||||
for row in rows
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
|
||||
bufferRange = fold.getBufferRange()
|
||||
startRow = bufferRange.start.row
|
||||
endRow = bufferRange.end.row
|
||||
foldedRows.push(startRow - insertDelta)
|
||||
while selection.end.row is selections[0]?.start.row
|
||||
selectionsToMove.push(selections[0])
|
||||
selection.end.row = selections[0].end.row
|
||||
selections.shift()
|
||||
|
||||
# Compute the range spanned by all these selections...
|
||||
linesRangeStart = [selection.start.row, 0]
|
||||
if selection.end.row > selection.start.row and selection.end.column is 0
|
||||
# Don't move the last line of a multi-line selection if the selection ends at column 0
|
||||
linesRange = new Range(linesRangeStart, selection.end)
|
||||
else
|
||||
startRow = row
|
||||
endRow = row
|
||||
linesRange = new Range(linesRangeStart, [selection.end.row + 1, 0])
|
||||
|
||||
insertPosition = Point.fromObject([startRow - insertDelta])
|
||||
endPosition = Point.min([endRow + 1], @buffer.getEndPosition())
|
||||
lines = @buffer.getTextInRange([[startRow], endPosition])
|
||||
if endPosition.row is lastRow and endPosition.column > 0 and not @buffer.lineEndingForRow(endPosition.row)
|
||||
lines = "#{lines}\n"
|
||||
# If there's a fold containing either the starting row or the end row
|
||||
# of the selection then the whole fold needs to be moved and restored.
|
||||
# The initial fold range is stored and will be translated once the
|
||||
# insert delta is know.
|
||||
selectionFoldRanges = []
|
||||
foldAtSelectionStart =
|
||||
@displayBuffer.largestFoldContainingBufferRow(selection.start.row)
|
||||
foldAtSelectionEnd =
|
||||
@displayBuffer.largestFoldContainingBufferRow(selection.end.row)
|
||||
if fold = foldAtSelectionStart ? foldAtSelectionEnd
|
||||
selectionFoldRanges.push range = fold.getBufferRange()
|
||||
newEndRow = range.end.row + 1
|
||||
linesRange.end.row = newEndRow if newEndRow > linesRange.end.row
|
||||
fold.destroy()
|
||||
|
||||
@buffer.deleteRows(startRow, endRow)
|
||||
# If selected line range is preceded by a fold, one line above on screen
|
||||
# could be multiple lines in the buffer.
|
||||
precedingScreenRow = @screenRowForBufferRow(linesRange.start.row) - 1
|
||||
precedingBufferRow = @bufferRowForScreenRow(precedingScreenRow)
|
||||
insertDelta = linesRange.start.row - precedingBufferRow
|
||||
|
||||
# Any folds in the text that is moved will need to be re-created.
|
||||
# It includes the folds that were intersecting with the selection.
|
||||
rangesToRefold = selectionFoldRanges.concat(
|
||||
@outermostFoldsInBufferRowRange(linesRange.start.row, linesRange.end.row).map (fold) ->
|
||||
range = fold.getBufferRange()
|
||||
fold.destroy()
|
||||
range
|
||||
).map (range) -> range.translate([-insertDelta, 0])
|
||||
|
||||
# Make sure the inserted text doesn't go into an existing fold
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(insertPosition.row)
|
||||
@unfoldBufferRow(insertPosition.row)
|
||||
foldedRows.push(insertPosition.row + endRow - startRow + fold.getBufferRange().getRowCount())
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(precedingBufferRow)
|
||||
rangesToRefold.push(fold.getBufferRange().translate([linesRange.getRowCount() - 1, 0]))
|
||||
fold.destroy()
|
||||
|
||||
@buffer.insert(insertPosition, lines)
|
||||
# Delete lines spanned by selection and insert them on the preceding buffer row
|
||||
lines = @buffer.getTextInRange(linesRange)
|
||||
lines += @buffer.lineEndingForRow(linesRange.end.row - 1) unless lines[lines.length - 1] is '\n'
|
||||
@buffer.delete(linesRange)
|
||||
@buffer.insert([precedingBufferRow, 0], lines)
|
||||
|
||||
# Restore folds that existed before the lines were moved
|
||||
for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
|
||||
@foldBufferRow(foldedRow)
|
||||
# Restore folds that existed before the lines were moved
|
||||
for rangeToRefold in rangesToRefold
|
||||
@displayBuffer.createFold(rangeToRefold.start.row, rangeToRefold.end.row)
|
||||
|
||||
@setSelectedBufferRange(selection.translate([-insertDelta]), preserveFolds: true, autoscroll: true)
|
||||
for selection in selectionsToMove
|
||||
newSelectionRanges.push(selection.translate([-insertDelta, 0]))
|
||||
|
||||
@setSelectedBufferRanges(newSelectionRanges, {autoscroll: false, preserveFolds: true})
|
||||
@autoIndentSelectedRows() if @shouldAutoIndent()
|
||||
@scrollToBufferPosition([newSelectionRanges[0].start.row, 0])
|
||||
|
||||
# Move lines intersecting the most recent selection down by one row in screen
|
||||
# coordinates.
|
||||
# Move lines intersecting the most recent selection or muiltiple selections
|
||||
# down by one row in screen coordinates.
|
||||
moveLineDown: ->
|
||||
selection = @getSelectedBufferRange()
|
||||
lastRow = @buffer.getLastRow()
|
||||
return if selection.end.row is lastRow
|
||||
return if selection.end.row is lastRow - 1 and @buffer.getLastLine() is ''
|
||||
selections = @getSelectedBufferRanges()
|
||||
selections.sort (a, b) -> a.compare(b)
|
||||
selections = selections.reverse()
|
||||
|
||||
@transact =>
|
||||
foldedRows = []
|
||||
rows = [selection.end.row..selection.start.row]
|
||||
if selection.start.row isnt selection.end.row and selection.end.column is 0
|
||||
rows.shift() unless @isFoldedAtBufferRow(selection.end.row)
|
||||
@consolidateSelections()
|
||||
newSelectionRanges = []
|
||||
|
||||
# Move line around the fold that is directly below the selection
|
||||
followingScreenRow = @screenPositionForBufferPosition([selection.end.row]).translate([1])
|
||||
followingBufferRow = @bufferPositionForScreenPosition(followingScreenRow).row
|
||||
if fold = @largestFoldContainingBufferRow(followingBufferRow)
|
||||
insertDelta = fold.getBufferRange().getRowCount()
|
||||
else
|
||||
insertDelta = 1
|
||||
while selections.length > 0
|
||||
# Find selections spanning a contiguous set of lines
|
||||
selection = selections.shift()
|
||||
selectionsToMove = [selection]
|
||||
|
||||
for row in rows
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(row)
|
||||
bufferRange = fold.getBufferRange()
|
||||
startRow = bufferRange.start.row
|
||||
endRow = bufferRange.end.row
|
||||
foldedRows.push(endRow + insertDelta)
|
||||
# if the current selection start row matches the next selections' end row - make them one selection
|
||||
while selection.start.row is selections[0]?.end.row
|
||||
selectionsToMove.push(selections[0])
|
||||
selection.start.row = selections[0].start.row
|
||||
selections.shift()
|
||||
|
||||
# Compute the range spanned by all these selections...
|
||||
linesRangeStart = [selection.start.row, 0]
|
||||
if selection.end.row > selection.start.row and selection.end.column is 0
|
||||
# Don't move the last line of a multi-line selection if the selection ends at column 0
|
||||
linesRange = new Range(linesRangeStart, selection.end)
|
||||
else
|
||||
startRow = row
|
||||
endRow = row
|
||||
linesRange = new Range(linesRangeStart, [selection.end.row + 1, 0])
|
||||
|
||||
if endRow + 1 is lastRow
|
||||
endPosition = [endRow, @buffer.lineLengthForRow(endRow)]
|
||||
else
|
||||
endPosition = [endRow + 1]
|
||||
lines = @buffer.getTextInRange([[startRow], endPosition])
|
||||
@buffer.deleteRows(startRow, endRow)
|
||||
# If there's a fold containing either the starting row or the end row
|
||||
# of the selection then the whole fold needs to be moved and restored.
|
||||
# The initial fold range is stored and will be translated once the
|
||||
# insert delta is know.
|
||||
selectionFoldRanges = []
|
||||
foldAtSelectionStart =
|
||||
@displayBuffer.largestFoldContainingBufferRow(selection.start.row)
|
||||
foldAtSelectionEnd =
|
||||
@displayBuffer.largestFoldContainingBufferRow(selection.end.row)
|
||||
if fold = foldAtSelectionStart ? foldAtSelectionEnd
|
||||
selectionFoldRanges.push range = fold.getBufferRange()
|
||||
newEndRow = range.end.row + 1
|
||||
linesRange.end.row = newEndRow if newEndRow > linesRange.end.row
|
||||
fold.destroy()
|
||||
|
||||
insertPosition = Point.min([startRow + insertDelta], @buffer.getEndPosition())
|
||||
if insertPosition.row is @buffer.getLastRow() and insertPosition.column > 0
|
||||
# If selected line range is followed by a fold, one line below on screen
|
||||
# could be multiple lines in the buffer. But at the same time, if the
|
||||
# next buffer row is wrapped, one line in the buffer can represent many
|
||||
# screen rows.
|
||||
followingScreenRow = @displayBuffer.lastScreenRowForBufferRow(linesRange.end.row) + 1
|
||||
followingBufferRow = @bufferRowForScreenRow(followingScreenRow)
|
||||
insertDelta = followingBufferRow - linesRange.end.row
|
||||
|
||||
# Any folds in the text that is moved will need to be re-created.
|
||||
# It includes the folds that were intersecting with the selection.
|
||||
rangesToRefold = selectionFoldRanges.concat(
|
||||
@outermostFoldsInBufferRowRange(linesRange.start.row, linesRange.end.row).map (fold) ->
|
||||
range = fold.getBufferRange()
|
||||
fold.destroy()
|
||||
range
|
||||
).map (range) -> range.translate([insertDelta, 0])
|
||||
|
||||
# Make sure the inserted text doesn't go into an existing fold
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(followingBufferRow)
|
||||
rangesToRefold.push(fold.getBufferRange().translate([insertDelta - 1, 0]))
|
||||
fold.destroy()
|
||||
|
||||
# Delete lines spanned by selection and insert them on the following correct buffer row
|
||||
insertPosition = new Point(selection.translate([insertDelta, 0]).start.row, 0)
|
||||
lines = @buffer.getTextInRange(linesRange)
|
||||
if linesRange.end.row is @buffer.getLastRow()
|
||||
lines = "\n#{lines}"
|
||||
|
||||
# Make sure the inserted text doesn't go into an existing fold
|
||||
if fold = @displayBuffer.largestFoldStartingAtBufferRow(insertPosition.row)
|
||||
@unfoldBufferRow(insertPosition.row)
|
||||
foldedRows.push(insertPosition.row + fold.getBufferRange().getRowCount())
|
||||
|
||||
@buffer.delete(linesRange)
|
||||
@buffer.insert(insertPosition, lines)
|
||||
|
||||
# Restore folds that existed before the lines were moved
|
||||
for foldedRow in foldedRows when 0 <= foldedRow <= @getLastBufferRow()
|
||||
@foldBufferRow(foldedRow)
|
||||
# Restore folds that existed before the lines were moved
|
||||
for rangeToRefold in rangesToRefold
|
||||
@displayBuffer.createFold(rangeToRefold.start.row, rangeToRefold.end.row)
|
||||
|
||||
@setSelectedBufferRange(selection.translate([insertDelta]), preserveFolds: true, autoscroll: true)
|
||||
for selection in selectionsToMove
|
||||
newSelectionRanges.push(selection.translate([insertDelta, 0]))
|
||||
|
||||
@setSelectedBufferRanges(newSelectionRanges, {autoscroll: false, preserveFolds: true})
|
||||
@autoIndentSelectedRows() if @shouldAutoIndent()
|
||||
@scrollToBufferPosition([newSelectionRanges[0].start.row - 1, 0])
|
||||
|
||||
# Duplicate the most recent cursor's current line.
|
||||
duplicateLines: ->
|
||||
@@ -1335,9 +1406,9 @@ class TextEditor extends Model
|
||||
Section: Decorations
|
||||
###
|
||||
|
||||
# Essential: Adds a decoration that tracks a {Marker}. When the marker moves,
|
||||
# is invalidated, or is destroyed, the decoration will be updated to reflect
|
||||
# the marker's state.
|
||||
# Essential: Add a decoration that tracks a {TextEditorMarker}. When the
|
||||
# marker moves, is invalidated, or is destroyed, the decoration will be
|
||||
# updated to reflect the marker's state.
|
||||
#
|
||||
# The following are the supported decorations types:
|
||||
#
|
||||
@@ -1356,28 +1427,28 @@ class TextEditor extends Model
|
||||
# </div>
|
||||
# ```
|
||||
# * __overlay__: Positions the view associated with the given item at the head
|
||||
# or tail of the given `Marker`.
|
||||
# * __gutter__: A decoration that tracks a {Marker} in a {Gutter}. Gutter
|
||||
# or tail of the given `TextEditorMarker`.
|
||||
# * __gutter__: A decoration that tracks a {TextEditorMarker} in a {Gutter}. Gutter
|
||||
# decorations are created by calling {Gutter::decorateMarker} on the
|
||||
# desired `Gutter` instance.
|
||||
#
|
||||
# ## Arguments
|
||||
#
|
||||
# * `marker` A {Marker} you want this decoration to follow.
|
||||
# * `marker` A {TextEditorMarker} 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 `Marker`.
|
||||
# spanned by the `TextEditorMarker`.
|
||||
# * `line-number` Adds the given `class` to the line numbers overlapping
|
||||
# the rows spanned by the `Marker`.
|
||||
# the rows spanned by the `TextEditorMarker`.
|
||||
# * `highlight` Creates a `.highlight` div with the nested class with up
|
||||
# to 3 nested regions that fill the area spanned by the `Marker`.
|
||||
# to 3 nested regions that fill the area spanned by the `TextEditorMarker`.
|
||||
# * `overlay` Positions the view associated with the given item at the
|
||||
# head or tail of the given `Marker`, depending on the `position`
|
||||
# head or tail of the given `TextEditorMarker`, depending on the `position`
|
||||
# property.
|
||||
# * `gutter` Tracks a {Marker} in a {Gutter}. Created by calling
|
||||
# * `gutter` Tracks a {TextEditorMarker} 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.
|
||||
@@ -1385,35 +1456,53 @@ 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 `Marker`. Only applicable to the `line` and
|
||||
# the head of the `TextEditorMarker`. Only applicable to the `line` and
|
||||
# `line-number` types.
|
||||
# * `onlyEmpty` (optional) If `true`, the decoration will only be applied if
|
||||
# the associated `Marker` is empty. Only applicable to the `gutter`,
|
||||
# the associated `TextEditorMarker` 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 `Marker` is non-empty. Only applicable to the
|
||||
# if the associated `TextEditorMarker` 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 `Marker`.
|
||||
# controls where the overlay view is positioned relative to the `TextEditorMarker`.
|
||||
# Values can be `'head'` (the default), or `'tail'`.
|
||||
#
|
||||
# Returns a {Decoration} object
|
||||
decorateMarker: (marker, decorationParams) ->
|
||||
@displayBuffer.decorateMarker(marker, decorationParams)
|
||||
|
||||
# Essential: Get all the decorations within a screen row range.
|
||||
# Essential: *Experimental:* Add a decoration to every marker in the given
|
||||
# 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.
|
||||
# * `decorationParams` The same parameters that are passed to
|
||||
# {decorateMarker}, except the `type` cannot be `overlay` or `gutter`.
|
||||
#
|
||||
# This API is experimental and subject to change on any release.
|
||||
#
|
||||
# Returns a {LayerDecoration}.
|
||||
decorateMarkerLayer: (markerLayer, decorationParams) ->
|
||||
@displayBuffer.decorateMarkerLayer(markerLayer, decorationParams)
|
||||
|
||||
# Deprecated: Get all the decorations within a screen row range on the default
|
||||
# layer.
|
||||
#
|
||||
# * `startScreenRow` the {Number} beginning screen row
|
||||
# * `endScreenRow` the {Number} end screen row (inclusive)
|
||||
#
|
||||
# Returns an {Object} of decorations in the form
|
||||
# `{1: [{id: 10, type: 'line-number', class: 'someclass'}], 2: ...}`
|
||||
# where the keys are {Marker} IDs, and the values are an array of decoration
|
||||
# where the keys are {TextEditorMarker} 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) ->
|
||||
@displayBuffer.decorationsForScreenRowRange(startScreenRow, endScreenRow)
|
||||
|
||||
decorationsStateForScreenRowRange: (startScreenRow, endScreenRow) ->
|
||||
@displayBuffer.decorationsStateForScreenRowRange(startScreenRow, endScreenRow)
|
||||
|
||||
# Extended: Get all decorations.
|
||||
#
|
||||
# * `propertyFilter` (optional) An {Object} containing key value pairs that
|
||||
@@ -1469,10 +1558,10 @@ class TextEditor extends Model
|
||||
Section: Markers
|
||||
###
|
||||
|
||||
# Essential: Create a marker with the given range in buffer coordinates. This
|
||||
# marker will maintain its logical location as the buffer is changed, so if
|
||||
# you mark a particular word, the marker will remain over that word even if
|
||||
# the word's location in the buffer changes.
|
||||
# Essential: Create a marker on the default marker layer with the given range
|
||||
# in buffer coordinates. This marker will maintain its logical location as the
|
||||
# buffer is changed, so if you mark a particular word, the marker will remain
|
||||
# over that word even if the word's location in the buffer changes.
|
||||
#
|
||||
# * `range` A {Range} or range-compatible {Array}
|
||||
# * `properties` A hash of key-value pairs to associate with the marker. There
|
||||
@@ -1500,14 +1589,14 @@ 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 {Marker}.
|
||||
# Returns a {TextEditorMarker}.
|
||||
markBufferRange: (args...) ->
|
||||
@displayBuffer.markBufferRange(args...)
|
||||
|
||||
# Essential: Create a marker with the given range in screen coordinates. This
|
||||
# marker will maintain its logical location as the buffer is changed, so if
|
||||
# you mark a particular word, the marker will remain over that word even if
|
||||
# the word's location in the buffer changes.
|
||||
# Essential: Create a marker on the default marker layer with the given range
|
||||
# in screen coordinates. This marker will maintain its logical location as the
|
||||
# buffer is changed, so if you mark a particular word, the marker will remain
|
||||
# over that word even if the word's location in the buffer changes.
|
||||
#
|
||||
# * `range` A {Range} or range-compatible {Array}
|
||||
# * `properties` A hash of key-value pairs to associate with the marker. There
|
||||
@@ -1535,29 +1624,32 @@ 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 {Marker}.
|
||||
# Returns a {TextEditorMarker}.
|
||||
markScreenRange: (args...) ->
|
||||
@displayBuffer.markScreenRange(args...)
|
||||
|
||||
# Essential: Mark the given position in buffer coordinates.
|
||||
# Essential: Mark the given position in buffer coordinates on the default
|
||||
# marker layer.
|
||||
#
|
||||
# * `position` A {Point} or {Array} of `[row, column]`.
|
||||
# * `options` (optional) See {TextBuffer::markRange}.
|
||||
#
|
||||
# Returns a {Marker}.
|
||||
# Returns a {TextEditorMarker}.
|
||||
markBufferPosition: (args...) ->
|
||||
@displayBuffer.markBufferPosition(args...)
|
||||
|
||||
# Essential: Mark the given position in screen coordinates.
|
||||
# Essential: Mark the given position in screen coordinates on the default
|
||||
# marker layer.
|
||||
#
|
||||
# * `position` A {Point} or {Array} of `[row, column]`.
|
||||
# * `options` (optional) See {TextBuffer::markRange}.
|
||||
#
|
||||
# Returns a {Marker}.
|
||||
# Returns a {TextEditorMarker}.
|
||||
markScreenPosition: (args...) ->
|
||||
@displayBuffer.markScreenPosition(args...)
|
||||
|
||||
# Essential: Find all {Marker}s that match the given properties.
|
||||
# Essential: Find all {TextEditorMarker}s on the default marker layer that
|
||||
# match the given properties.
|
||||
#
|
||||
# This method finds markers based on the given properties. Markers can be
|
||||
# associated with custom properties that will be compared with basic equality.
|
||||
@@ -1579,44 +1671,60 @@ 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.
|
||||
# Extended: Get the {TextEditorMarker} on the default layer for the given
|
||||
# marker id.
|
||||
#
|
||||
# * `id` {Number} id of the marker
|
||||
getMarker: (id) ->
|
||||
@displayBuffer.getMarker(id)
|
||||
|
||||
# Extended: Get all {Marker}s. Consider using {::findMarkers}
|
||||
# Extended: Get all {TextEditorMarker}s on the default marker layer. Consider
|
||||
# using {::findMarkers}
|
||||
getMarkers: ->
|
||||
@displayBuffer.getMarkers()
|
||||
|
||||
# Extended: Get the number of markers in this editor's buffer.
|
||||
# Extended: Get the number of markers in the default marker layer.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getMarkerCount: ->
|
||||
@buffer.getMarkerCount()
|
||||
|
||||
# {Delegates to: DisplayBuffer.destroyMarker}
|
||||
destroyMarker: (args...) ->
|
||||
@displayBuffer.destroyMarker(args...)
|
||||
destroyMarker: (id) ->
|
||||
@getMarker(id)?.destroy()
|
||||
|
||||
# Extended: *Experimental:* Create a marker layer to group related markers.
|
||||
#
|
||||
# * `options` An {Object} containing the following keys:
|
||||
# * `maintainHistory` A {Boolean} indicating whether marker state should be
|
||||
# restored on undo/redo. Defaults to `false`.
|
||||
#
|
||||
# This API is experimental and subject to change on any release.
|
||||
#
|
||||
# Returns a {TextEditorMarkerLayer}.
|
||||
addMarkerLayer: (options) ->
|
||||
@displayBuffer.addMarkerLayer(options)
|
||||
|
||||
# Public: *Experimental:* Get a {TextEditorMarkerLayer} by id.
|
||||
#
|
||||
# * `id` The id of the marker layer to retrieve.
|
||||
#
|
||||
# This API is experimental and subject to change on any release.
|
||||
#
|
||||
# Returns a {MarkerLayer} or `undefined` if no layer exists with the given
|
||||
# id.
|
||||
getMarkerLayer: (id) ->
|
||||
@displayBuffer.getMarkerLayer(id)
|
||||
|
||||
# Public: *Experimental:* Get the default {TextEditorMarkerLayer}.
|
||||
#
|
||||
# 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}.
|
||||
getDefaultMarkerLayer: ->
|
||||
@displayBuffer.getDefaultMarkerLayer()
|
||||
|
||||
###
|
||||
Section: Cursors
|
||||
@@ -1686,7 +1794,7 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns a {Cursor}.
|
||||
addCursorAtBufferPosition: (bufferPosition, options) ->
|
||||
@markBufferPosition(bufferPosition, @getSelectionMarkerAttributes())
|
||||
@selectionsMarkerLayer.markBufferPosition(bufferPosition, @getSelectionMarkerAttributes())
|
||||
@getLastSelection().cursor.autoscroll() unless options?.autoscroll is false
|
||||
@getLastSelection().cursor
|
||||
|
||||
@@ -1696,7 +1804,7 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns a {Cursor}.
|
||||
addCursorAtScreenPosition: (screenPosition, options) ->
|
||||
@markScreenPosition(screenPosition, @getSelectionMarkerAttributes())
|
||||
@selectionsMarkerLayer.markScreenPosition(screenPosition, @getSelectionMarkerAttributes())
|
||||
@getLastSelection().cursor.autoscroll() unless options?.autoscroll is false
|
||||
@getLastSelection().cursor
|
||||
|
||||
@@ -1821,7 +1929,7 @@ class TextEditor extends Model
|
||||
getCursorsOrderedByBufferPosition: ->
|
||||
@getCursors().sort (a, b) -> a.compare(b)
|
||||
|
||||
# Add a cursor based on the given {Marker}.
|
||||
# Add a cursor based on the given {TextEditorMarker}.
|
||||
addCursor: (marker) ->
|
||||
cursor = new Cursor(editor: this, marker: marker, config: @config)
|
||||
@cursors.push(cursor)
|
||||
@@ -1974,7 +2082,7 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns the added {Selection}.
|
||||
addSelectionForBufferRange: (bufferRange, options={}) ->
|
||||
@markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
@selectionsMarkerLayer.markBufferRange(bufferRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
@getLastSelection().autoscroll() unless options.autoscroll is false
|
||||
@getLastSelection()
|
||||
|
||||
@@ -1987,7 +2095,7 @@ class TextEditor extends Model
|
||||
#
|
||||
# Returns the added {Selection}.
|
||||
addSelectionForScreenRange: (screenRange, options={}) ->
|
||||
@markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
@selectionsMarkerLayer.markScreenRange(screenRange, _.defaults(@getSelectionMarkerAttributes(), options))
|
||||
@getLastSelection().autoscroll() unless options.autoscroll is false
|
||||
@getLastSelection()
|
||||
|
||||
@@ -2170,7 +2278,7 @@ class TextEditor extends Model
|
||||
|
||||
# Extended: Select the range of the given marker if it is valid.
|
||||
#
|
||||
# * `marker` A {Marker}
|
||||
# * `marker` A {TextEditorMarker}
|
||||
#
|
||||
# Returns the selected {Range} or `undefined` if the marker is invalid.
|
||||
selectMarker: (marker) ->
|
||||
@@ -2296,9 +2404,9 @@ class TextEditor extends Model
|
||||
_.reduce(tail, reducer, [head])
|
||||
return result if fn?
|
||||
|
||||
# Add a {Selection} based on the given {Marker}.
|
||||
# Add a {Selection} based on the given {TextEditorMarker}.
|
||||
#
|
||||
# * `marker` The {Marker} to highlight
|
||||
# * `marker` The {TextEditorMarker} to highlight
|
||||
# * `options` (optional) An {Object} that pertains to the {Selection} constructor.
|
||||
#
|
||||
# Returns the new {Selection}.
|
||||
@@ -3006,10 +3114,6 @@ class TextEditor extends Model
|
||||
@subscribeToTabTypeConfig()
|
||||
@emitter.emit 'did-change-grammar', @getGrammar()
|
||||
|
||||
handleMarkerCreated: (marker) =>
|
||||
if marker.matchesProperties(@getSelectionMarkerAttributes())
|
||||
@addSelection(marker)
|
||||
|
||||
###
|
||||
Section: TextEditor Rendering
|
||||
###
|
||||
@@ -3038,7 +3142,7 @@ class TextEditor extends Model
|
||||
@viewRegistry.getView(this).pixelPositionForScreenPosition(screenPosition)
|
||||
|
||||
getSelectionMarkerAttributes: ->
|
||||
{type: 'selection', editorId: @id, invalidate: 'never', maintainHistory: true}
|
||||
{type: 'selection', invalidate: 'never'}
|
||||
|
||||
getVerticalScrollMargin: -> @displayBuffer.getVerticalScrollMargin()
|
||||
setVerticalScrollMargin: (verticalScrollMargin) -> @displayBuffer.setVerticalScrollMargin(verticalScrollMargin)
|
||||
|
||||
Reference in New Issue
Block a user