selection.min.js (2787B)
1 import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos.js" 2 import { indexOf } from "../util/misc.js" 3 4 // Selection objects are immutable. A new one is created every time 5 // the selection changes. A selection is one or more non-overlapping 6 // (and non-touching) ranges, sorted, and an integer that indicates 7 // which one is the primary selection (the one that's scrolled into 8 // view, that getCursor returns, etc). 9 export class Selection { 10 constructor(ranges, primIndex) { 11 this.ranges = ranges 12 this.primIndex = primIndex 13 } 14 15 primary() { return this.ranges[this.primIndex] } 16 17 equals(other) { 18 if (other == this) return true 19 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false 20 for (let i = 0; i < this.ranges.length; i++) { 21 let here = this.ranges[i], there = other.ranges[i] 22 if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) return false 23 } 24 return true 25 } 26 27 deepCopy() { 28 let out = [] 29 for (let i = 0; i < this.ranges.length; i++) 30 out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)) 31 return new Selection(out, this.primIndex) 32 } 33 34 somethingSelected() { 35 for (let i = 0; i < this.ranges.length; i++) 36 if (!this.ranges[i].empty()) return true 37 return false 38 } 39 40 contains(pos, end) { 41 if (!end) end = pos 42 for (let i = 0; i < this.ranges.length; i++) { 43 let range = this.ranges[i] 44 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) 45 return i 46 } 47 return -1 48 } 49 } 50 51 export class Range { 52 constructor(anchor, head) { 53 this.anchor = anchor; this.head = head 54 } 55 56 from() { return minPos(this.anchor, this.head) } 57 to() { return maxPos(this.anchor, this.head) } 58 empty() { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch } 59 } 60 61 // Take an unsorted, potentially overlapping set of ranges, and 62 // build a selection out of it. 'Consumes' ranges array (modifying 63 // it). 64 export function normalizeSelection(ranges, primIndex) { 65 let prim = ranges[primIndex] 66 ranges.sort((a, b) => cmp(a.from(), b.from())) 67 primIndex = indexOf(ranges, prim) 68 for (let i = 1; i < ranges.length; i++) { 69 let cur = ranges[i], prev = ranges[i - 1] 70 if (cmp(prev.to(), cur.from()) >= 0) { 71 let from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) 72 let inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head 73 if (i <= primIndex) --primIndex 74 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) 75 } 76 } 77 return new Selection(ranges, primIndex) 78 } 79 80 export function simpleSelection(anchor, head) { 81 return new Selection([new Range(anchor, head || anchor)], 0) 82 }