mirror of
https://github.com/atom/atom.git
synced 2026-02-05 12:15:07 -05:00
Conflicts: src/app/buffer-marker.coffee src/app/cursor.coffee src/app/display-buffer-marker.coffee src/app/display-buffer.coffee src/app/edit-session.coffee src/app/fold.coffee src/app/line-map.coffee src/app/range.coffee src/app/selection.coffee src/app/text-buffer.coffee
211 lines
6.4 KiB
CoffeeScript
211 lines
6.4 KiB
CoffeeScript
Point = require 'point'
|
|
_ = require 'underscore'
|
|
|
|
# Public: Indicates a region within the editor.
|
|
#
|
|
# To better visualize how this works, imagine a rectangle.
|
|
# Each quadrant of the rectangle is analogus to a range, as ranges contain a
|
|
# starting row and a starting column, as well as an ending row, and an ending column.
|
|
#
|
|
# Each `Range` is actually constructed of two `Point` objects, labelled `start` and `end`.
|
|
module.exports =
|
|
class Range
|
|
|
|
# Constructs a `Range` from a given object.
|
|
#
|
|
# object - This can be an {Array} (`[startRow, startColumn, endRow, endColumn]`) or an object `{start: Point, end: Point}`
|
|
#
|
|
# Returns the new {Range}.
|
|
@fromObject: (object) ->
|
|
if _.isArray(object)
|
|
new Range(object...)
|
|
else if object instanceof Range
|
|
object
|
|
else
|
|
new Range(object.start, object.end)
|
|
|
|
# Constructs a `Range` from a {Point}, and the delta values beyond that point.
|
|
#
|
|
# point - A {Point} to start with
|
|
# rowDelta - A {Number} indicating how far from the starting {Point} the range's row should be
|
|
# columnDelta - A {Number} indicating how far from the starting {Point} the range's column should be
|
|
#
|
|
# Returns the new {Range}.
|
|
@fromPointWithDelta: (point, rowDelta, columnDelta) ->
|
|
pointA = Point.fromObject(point)
|
|
pointB = new Point(point.row + rowDelta, point.column + columnDelta)
|
|
new Range(pointA, pointB)
|
|
|
|
# Creates a new `Range` object based on two {Point}s.
|
|
#
|
|
# pointA - The first {Point} (default: `0, 0`)
|
|
# pointB - The second {Point} (default: `0, 0`)
|
|
constructor: (pointA = new Point(0, 0), pointB = new Point(0, 0)) ->
|
|
pointA = Point.fromObject(pointA)
|
|
pointB = Point.fromObject(pointB)
|
|
|
|
if pointA.compare(pointB) <= 0
|
|
@start = pointA
|
|
@end = pointB
|
|
else
|
|
@start = pointB
|
|
@end = pointA
|
|
|
|
# Creates an identical copy of the `Range`.
|
|
#
|
|
# Returns a duplicate {Range}.
|
|
copy: ->
|
|
new Range(@start.copy(), @end.copy())
|
|
|
|
# Identifies if two `Range`s are equal.
|
|
#
|
|
# All four points (`start.row`, `start.column`, `end.row`, `end.column`) must be
|
|
# equal for this method to return `true`.
|
|
#
|
|
# other - A different {Range} to check against
|
|
#
|
|
# Returns a {Boolean}.
|
|
isEqual: (other) ->
|
|
if _.isArray(other) and other.length == 2
|
|
other = new Range(other...)
|
|
|
|
other.start.isEqual(@start) and other.end.isEqual(@end)
|
|
|
|
# Returns an integer (-1, 0, 1) indicating whether this range is less than, equal,
|
|
# or greater than the given range when sorting.
|
|
#
|
|
# Ranges that start earlier are considered "less than" ranges that start later.
|
|
# If ranges start at the same location, the larger range sorts before the smaller
|
|
# range.
|
|
#
|
|
# other - A {Range} to compare against.
|
|
#
|
|
# Returns a {Number}, either -1, 0, or 1.
|
|
compare: (other) ->
|
|
other = Range.fromObject(other)
|
|
if value = @start.compare(other.start)
|
|
value
|
|
else
|
|
other.end.compare(@end)
|
|
|
|
# Identifies if the `Range` is on the same line.
|
|
#
|
|
# In other words, if `start.row` is equal to `end.row`.
|
|
#
|
|
# Returns a {Boolean}.
|
|
isSingleLine: ->
|
|
@start.row == @end.row
|
|
|
|
# Identifies if two `Range`s are on the same line.
|
|
#
|
|
# other - A different {Range} to check against
|
|
#
|
|
# Returns a {Boolean}.
|
|
coversSameRows: (other) ->
|
|
@start.row == other.start.row && @end.row == other.end.row
|
|
|
|
# Adds a new point to the `Range`s `start` and `end`.
|
|
#
|
|
# point - A new {Point} to add
|
|
#
|
|
# Returns the new {Range}.
|
|
add: (point) ->
|
|
new Range(@start.add(point), @end.add(point))
|
|
|
|
# Moves a `Range`.
|
|
#
|
|
# In other words, the starting and ending `row` values, and the starting and ending
|
|
# `column` values, are added to each other.
|
|
#
|
|
# startPoint - The {Point} to move the `Range`s `start` by
|
|
# endPoint - The {Point} to move the `Range`s `end` by
|
|
#
|
|
# Returns the new {Range}.
|
|
translate: (startPoint, endPoint=startPoint) ->
|
|
new Range(@start.translate(startPoint), @end.translate(endPoint))
|
|
|
|
# Identifies if two `Range`s intersect each other.
|
|
#
|
|
# otherRange - A different {Range} to check against
|
|
#
|
|
# Returns a {Boolean}.
|
|
intersectsWith: (otherRange) ->
|
|
if @start.isLessThanOrEqual(otherRange.start)
|
|
@end.isGreaterThanOrEqual(otherRange.start)
|
|
else
|
|
otherRange.intersectsWith(this)
|
|
|
|
# Identifies if a second `Range` is contained within a first.
|
|
#
|
|
# otherRange - A different {Range} to check against
|
|
# options - A hash with a single option:
|
|
# exclusive: A {Boolean} which, if `true`, indicates that no {Point}s in the `Range` can be equal
|
|
#
|
|
# Returns a {Boolean}.
|
|
containsRange: (otherRange, {exclusive} = {}) ->
|
|
{ start, end } = Range.fromObject(otherRange)
|
|
@containsPoint(start, {exclusive}) and @containsPoint(end, {exclusive})
|
|
|
|
# Identifies if a `Range` contains a {Point}.
|
|
#
|
|
# point - A {Point} to check against
|
|
# options - A hash with a single option:
|
|
# exclusive: A {Boolean} which, if `true`, indicates that no {Point}s in the `Range` can be equal
|
|
#
|
|
# Returns a {Boolean}.
|
|
containsPoint: (point, {exclusive} = {}) ->
|
|
point = Point.fromObject(point)
|
|
if exclusive
|
|
point.isGreaterThan(@start) and point.isLessThan(@end)
|
|
else
|
|
point.isGreaterThanOrEqual(@start) and point.isLessThanOrEqual(@end)
|
|
|
|
# Identifies if a `Range` contains a row.
|
|
#
|
|
# row - A row {Number} to check against
|
|
# options - A hash with a single option:
|
|
#
|
|
# Returns a {Boolean}.
|
|
containsRow: (row) ->
|
|
@start.row <= row <= @end.row
|
|
|
|
# Constructs a union between two `Range`s.
|
|
#
|
|
# otherRange - A different {Range} to unionize with
|
|
#
|
|
# Returns the new {Range}.
|
|
union: (otherRange) ->
|
|
start = if @start.isLessThan(otherRange.start) then @start else otherRange.start
|
|
end = if @end.isGreaterThan(otherRange.end) then @end else otherRange.end
|
|
new Range(start, end)
|
|
|
|
# Identifies if a `Range` is empty.
|
|
#
|
|
# A `Range` is empty if its start {Point} matches its end.
|
|
#
|
|
# Returns a {Boolean}.
|
|
isEmpty: ->
|
|
@start.isEqual(@end)
|
|
|
|
# Calculates the difference between a `Range`s `start` and `end` points.
|
|
#
|
|
# Returns a {Point}.
|
|
toDelta: ->
|
|
rows = @end.row - @start.row
|
|
if rows == 0
|
|
columns = @end.column - @start.column
|
|
else
|
|
columns = @end.column
|
|
new Point(rows, columns)
|
|
|
|
# Calculates the number of rows a `Range`s contains.
|
|
#
|
|
# Returns a {Number}.
|
|
getRowCount: ->
|
|
@end.row - @start.row + 1
|
|
|
|
### Internal ###
|
|
|
|
inspect: ->
|
|
"[#{@start.inspect()} - #{@end.inspect()}]"
|