Mercurial
comparison .cms/lib/codemirror/src/model/selection.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
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(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 | |
82 export function simpleSelection(anchor, head) { | |
83 return new Selection([new Range(anchor, head || anchor)], 0) | |
84 } |