Spaces:
Sleeping
Sleeping
| import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos" | |
| import { indexOf } from "../util/misc" | |
| // Selection objects are immutable. A new one is created every time | |
| // the selection changes. A selection is one or more non-overlapping | |
| // (and non-touching) ranges, sorted, and an integer that indicates | |
| // which one is the primary selection (the one that's scrolled into | |
| // view, that getCursor returns, etc). | |
| export class Selection { | |
| constructor(ranges, primIndex) { | |
| this.ranges = ranges | |
| this.primIndex = primIndex | |
| } | |
| primary() { return this.ranges[this.primIndex] } | |
| equals(other) { | |
| if (other == this) return true | |
| if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false | |
| for (let i = 0; i < this.ranges.length; i++) { | |
| let here = this.ranges[i], there = other.ranges[i] | |
| if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) return false | |
| } | |
| return true | |
| } | |
| deepCopy() { | |
| let out = [] | |
| for (let i = 0; i < this.ranges.length; i++) | |
| out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)) | |
| return new Selection(out, this.primIndex) | |
| } | |
| somethingSelected() { | |
| for (let i = 0; i < this.ranges.length; i++) | |
| if (!this.ranges[i].empty()) return true | |
| return false | |
| } | |
| contains(pos, end) { | |
| if (!end) end = pos | |
| for (let i = 0; i < this.ranges.length; i++) { | |
| let range = this.ranges[i] | |
| if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) | |
| return i | |
| } | |
| return -1 | |
| } | |
| } | |
| export class Range { | |
| constructor(anchor, head) { | |
| this.anchor = anchor; this.head = head | |
| } | |
| from() { return minPos(this.anchor, this.head) } | |
| to() { return maxPos(this.anchor, this.head) } | |
| empty() { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch } | |
| } | |
| // Take an unsorted, potentially overlapping set of ranges, and | |
| // build a selection out of it. 'Consumes' ranges array (modifying | |
| // it). | |
| export function normalizeSelection(ranges, primIndex) { | |
| let prim = ranges[primIndex] | |
| ranges.sort((a, b) => cmp(a.from(), b.from())) | |
| primIndex = indexOf(ranges, prim) | |
| for (let i = 1; i < ranges.length; i++) { | |
| let cur = ranges[i], prev = ranges[i - 1] | |
| if (cmp(prev.to(), cur.from()) >= 0) { | |
| let from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) | |
| let inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head | |
| if (i <= primIndex) --primIndex | |
| ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) | |
| } | |
| } | |
| return new Selection(ranges, primIndex) | |
| } | |
| export function simpleSelection(anchor, head) { | |
| return new Selection([new Range(anchor, head || anchor)], 0) | |
| } | |