UNPKG

2.9 kBJavaScriptView Raw
1import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos.js"
2import { 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).
9export 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
51export 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).
64export function normalizeSelection(cm, ranges, primIndex) {
65 let mayTouch = cm && cm.options.selectionsMayTouch
66 let prim = ranges[primIndex]
67 ranges.sort((a, b) => cmp(a.from(), b.from()))
68 primIndex = indexOf(ranges, prim)
69 for (let i = 1; i < ranges.length; i++) {
70 let cur = ranges[i], prev = ranges[i - 1]
71 let diff = cmp(prev.to(), cur.from())
72 if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {
73 let from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to())
74 let inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head
75 if (i <= primIndex) --primIndex
76 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to))
77 }
78 }
79 return new Selection(ranges, primIndex)
80}
81
82export function simpleSelection(anchor, head) {
83 return new Selection([new Range(anchor, head || anchor)], 0)
84}