1use crate::model::{Cursor, SeqId, Selection, Tree};
4
5pub fn extend(tree: &Tree, sel: Selection, right: bool) -> Selection {
7 if right {
8 if sel.focus < tree.len(sel.seq) {
9 Selection {
10 seq: sel.seq,
11 anchor: sel.anchor,
12 focus: sel.focus + 1,
13 }
14 } else if let Some(parent) = tree.seq_parent(sel.seq) {
15 if let Some((gseq, gi)) = tree.index_in_parent(parent) {
17 Selection {
18 seq: gseq,
19 anchor: gi,
20 focus: gi + 1,
21 }
22 } else {
23 sel
24 }
25 } else {
26 sel }
28 } else if sel.focus > 0 {
29 Selection {
30 seq: sel.seq,
31 anchor: sel.anchor,
32 focus: sel.focus - 1,
33 }
34 } else if let Some(parent) = tree.seq_parent(sel.seq) {
35 if let Some((gseq, gi)) = tree.index_in_parent(parent) {
36 Selection {
37 seq: gseq,
38 anchor: gi + 1,
39 focus: gi,
40 }
41 } else {
42 sel
43 }
44 } else {
45 sel
46 }
47}
48
49pub fn extend_to(tree: &Tree, anchor: Cursor, target: Cursor) -> Selection {
51 if anchor.seq == target.seq {
52 return Selection {
53 seq: anchor.seq,
54 anchor: anchor.index,
55 focus: target.index,
56 };
57 }
58
59 fn seq_chain(tree: &Tree, leaf: SeqId) -> Vec<SeqId> {
61 let mut chain = vec![leaf];
62 let mut seq = leaf;
63 while let Some(node) = tree.seq_parent(seq) {
64 let Some((pseq, _)) = tree.index_in_parent(node) else {
65 break;
66 };
67 chain.push(pseq);
68 seq = pseq;
69 }
70 chain.reverse();
71 chain
72 }
73 let chain_a = seq_chain(tree, anchor.seq);
74 let chain_b = seq_chain(tree, target.seq);
75 let common_depth = chain_a.iter().zip(&chain_b).take_while(|(a, b)| a == b).count();
77 let common_seq = chain_a[common_depth - 1];
78
79 let side = |cur: Cursor, chain: &[SeqId]| -> (usize, usize) {
81 if cur.seq == common_seq {
82 (cur.index, cur.index)
83 } else {
84 let next = chain[common_depth];
85 let node = tree.seq_parent(next).expect("non-root seq has a parent node");
86 let (_, idx) = tree.index_in_parent(node).expect("node is placed in its parent seq");
87 (idx, idx + 1)
88 }
89 };
90 let (lo_a, hi_a) = side(anchor, &chain_a);
91 let (lo_b, hi_b) = side(target, &chain_b);
92 let lo = lo_a.min(lo_b);
93 let hi = hi_a.max(hi_b);
94 let (anchor_idx, focus_idx) = if lo_a <= lo_b { (lo, hi) } else { (hi, lo) };
96 Selection {
97 seq: common_seq,
98 anchor: anchor_idx,
99 focus: focus_idx,
100 }
101}
102
103pub fn select_all(tree: &Tree) -> Selection {
105 let root = tree.root();
106 Selection {
107 seq: root,
108 anchor: 0,
109 focus: tree.len(root),
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::model::{FracStyle, Kind, MathClass, ScriptSlot, Symbol};
117
118 fn atom(c: &str) -> Symbol {
119 Symbol { latex: c.into(), class: MathClass::Ord }
120 }
121
122 fn x_squared_plus_2(t: &mut Tree) -> (SeqId, SeqId) {
124 let root = t.root();
125 t.insert_atom(Cursor { seq: root, index: 0 }, atom("x"));
126 let c = t.attach_script(Cursor { seq: root, index: 1 }, ScriptSlot::Sup);
127 t.insert_atom(c, atom("2"));
128 t.insert_atom(Cursor { seq: root, index: 1 }, atom("+"));
129 t.insert_atom(Cursor { seq: root, index: 2 }, atom("2"));
130 let script = t.items(root)[0];
131 let base = match t.kind(script) {
132 Some(Kind::Script { base, .. }) => *base,
133 _ => panic!("expected a Script"),
134 };
135 (root, base)
136 }
137
138 #[test]
140 fn extend_to_same_seq_is_literal() {
141 let mut t = Tree::new();
142 let root = t.root();
143 t.insert_atom(Cursor { seq: root, index: 0 }, atom("a"));
144 t.insert_atom(Cursor { seq: root, index: 1 }, atom("b"));
145 let sel = extend_to(&t, Cursor { seq: root, index: 0 }, Cursor { seq: root, index: 2 });
146 assert_eq!((sel.seq, sel.anchor, sel.focus), (root, 0, 2));
147 }
148
149 #[test]
151 fn extend_to_from_inside_a_script_base_past_the_end_selects_everything() {
152 let mut t = Tree::new();
153 let (root, base) = x_squared_plus_2(&mut t);
154 let end = t.len(root);
155 let sel = extend_to(&t, Cursor { seq: base, index: 1 }, Cursor { seq: root, index: end });
156 assert_eq!(sel.seq, root);
157 assert_eq!((sel.anchor.min(sel.focus), sel.anchor.max(sel.focus)), (0, end));
158 assert_eq!(sel.focus, end);
160 }
161
162 #[test]
164 fn extend_to_reversed_direction_keeps_the_true_anchor_fixed() {
165 let mut t = Tree::new();
166 let (root, base) = x_squared_plus_2(&mut t);
167 let end = t.len(root);
168 let sel = extend_to(&t, Cursor { seq: root, index: end }, Cursor { seq: base, index: 1 });
169 assert_eq!(sel.seq, root);
170 assert_eq!(sel.anchor, end); assert_eq!(sel.focus, 0); }
173
174 #[test]
176 fn extend_to_between_two_sibling_structures() {
177 let mut t = Tree::new();
178 let root = t.root();
179 let c = t.insert_fraction(Cursor { seq: root, index: 0 }, FracStyle::Bar, None);
180 let num_a = c.seq;
181 let fa = t.items(root)[0];
182 let den_a = t.child_seqs(fa)[1];
183 let c = t.insert_fraction(Cursor { seq: root, index: 1 }, FracStyle::Bar, None);
184 let num_b = c.seq;
185 let _ = (num_a, den_a);
186
187 let sel = extend_to(&t, Cursor { seq: den_a, index: 0 }, Cursor { seq: num_b, index: 0 });
188 assert_eq!((sel.seq, sel.anchor.min(sel.focus), sel.anchor.max(sel.focus)), (root, 0, 2));
189 }
190}