1use crate::{
2 databasetreeitems::DatabaseTreeItems, error::Result, item::DatabaseTreeItemKind,
3 tree_iter::TreeIterator,
4};
5use crate::{Database, Table};
6use std::{collections::BTreeSet, usize};
7
8#[derive(Copy, Clone, Debug)]
10pub enum MoveSelection {
11 Up,
12 Down,
13 MultipleUp,
14 MultipleDown,
15 Left,
16 Right,
17 Top,
18 End,
19 Enter,
20}
21
22#[derive(Debug, Clone, Copy)]
23pub struct VisualSelection {
24 pub count: usize,
25 pub index: usize,
26}
27
28#[derive(Default)]
30pub struct DatabaseTree {
31 items: DatabaseTreeItems,
32 pub selection: Option<usize>,
33 visual_selection: Option<VisualSelection>,
34}
35
36impl DatabaseTree {
37 pub fn new(list: &[crate::Database], collapsed: &BTreeSet<&String>) -> Result<Self> {
38 let mut new_self = Self {
39 items: DatabaseTreeItems::new(list, collapsed)?,
40 selection: if list.is_empty() { None } else { Some(0) },
41 visual_selection: None,
42 };
43 new_self.visual_selection = new_self.calc_visual_selection();
44
45 Ok(new_self)
46 }
47
48 pub fn filter(&self, filter_text: String) -> Self {
49 let mut new_self = Self {
50 items: self.items.filter(filter_text),
51 selection: Some(0),
52 visual_selection: None,
53 };
54 new_self.visual_selection = new_self.calc_visual_selection();
55 new_self
56 }
57
58 pub fn collapse_but_root(&mut self) {
59 self.items.collapse(0, true);
60 self.items.expand(0, false);
61 }
62
63 pub fn iterate(&self, start_index_visual: usize, max_amount: usize) -> TreeIterator<'_> {
65 let start = self
66 .visual_index_to_absolute(start_index_visual)
67 .unwrap_or_default();
68 TreeIterator::new(self.items.iterate(start, max_amount), self.selection)
69 }
70
71 pub const fn visual_selection(&self) -> Option<&VisualSelection> {
72 self.visual_selection.as_ref()
73 }
74
75 pub fn selected_item(&self) -> Option<&crate::DatabaseTreeItem> {
76 self.selection
77 .and_then(|index| self.items.tree_items.get(index))
78 }
79
80 pub fn selected_table(&self) -> Option<(Database, Table)> {
81 self.selection.and_then(|index| {
82 let item = &self.items.tree_items[index];
83 match item.kind() {
84 DatabaseTreeItemKind::Database { .. } => None,
85 DatabaseTreeItemKind::Table { table, database } => {
86 Some((database.clone(), table.clone()))
87 }
88 DatabaseTreeItemKind::Schema { .. } => None,
89 }
90 })
91 }
92
93 pub fn collapse_recursive(&mut self) {
94 if let Some(selection) = self.selection {
95 self.items.collapse(selection, true);
96 }
97 }
98
99 pub fn expand_recursive(&mut self) {
100 if let Some(selection) = self.selection {
101 self.items.expand(selection, true);
102 }
103 }
104
105 pub fn move_selection(&mut self, dir: MoveSelection) -> bool {
106 self.selection.map_or(false, |selection| {
107 let new_index = match dir {
108 MoveSelection::Up => self.selection_up(selection, 1),
109 MoveSelection::Down => self.selection_down(selection, 1),
110 MoveSelection::MultipleUp => self.selection_up(selection, 10),
111 MoveSelection::MultipleDown => self.selection_down(selection, 10),
112 MoveSelection::Left => self.selection_left(selection),
113 MoveSelection::Right => self.selection_right(selection),
114 MoveSelection::Top => Self::selection_start(selection),
115 MoveSelection::End => self.selection_end(selection),
116 MoveSelection::Enter => self.expand(selection),
117 };
118
119 let changed_index = new_index.map(|i| i != selection).unwrap_or_default();
120
121 if changed_index {
122 self.selection = new_index;
123 self.visual_selection = self.calc_visual_selection();
124 }
125
126 changed_index || new_index.is_some()
127 })
128 }
129
130 fn visual_index_to_absolute(&self, visual_index: usize) -> Option<usize> {
131 self.items
132 .iterate(0, self.items.len())
133 .enumerate()
134 .find_map(
135 |(i, (abs, _))| {
136 if i == visual_index {
137 Some(abs)
138 } else {
139 None
140 }
141 },
142 )
143 }
144
145 fn calc_visual_selection(&self) -> Option<VisualSelection> {
146 self.selection.map(|selection_absolute| {
147 let mut count = 0;
148 let mut visual_index = 0;
149 for (index, _item) in self.items.iterate(0, self.items.len()) {
150 if selection_absolute == index {
151 visual_index = count;
152 }
153
154 count += 1;
155 }
156
157 VisualSelection {
158 index: visual_index,
159 count,
160 }
161 })
162 }
163
164 const fn selection_start(current_index: usize) -> Option<usize> {
165 if current_index == 0 {
166 None
167 } else {
168 Some(0)
169 }
170 }
171
172 fn selection_end(&self, current_index: usize) -> Option<usize> {
173 let items_max = self.items.len().saturating_sub(1);
174
175 let mut new_index = items_max;
176
177 loop {
178 if self.is_visible_index(new_index) {
179 break;
180 }
181
182 if new_index == 0 {
183 break;
184 }
185
186 new_index = new_index.saturating_sub(1);
187 new_index = std::cmp::min(new_index, items_max);
188 }
189
190 if new_index == current_index {
191 None
192 } else {
193 Some(new_index)
194 }
195 }
196
197 fn selection_up(&self, current_index: usize, lines: usize) -> Option<usize> {
198 let mut index = current_index;
199
200 'a: for _ in 0..lines {
201 loop {
202 if index == 0 {
203 break 'a;
204 }
205
206 index = index.saturating_sub(1);
207
208 if self.is_visible_index(index) {
209 break;
210 }
211 }
212 }
213
214 if index == current_index {
215 None
216 } else {
217 Some(index)
218 }
219 }
220
221 fn selection_down(&self, current_index: usize, lines: usize) -> Option<usize> {
222 let mut index = current_index;
223 let last_visible_item_index = self
224 .items
225 .tree_items
226 .iter()
227 .rposition(|x| x.info().is_visible())?;
228
229 'a: for _ in 0..lines {
230 loop {
231 if index >= last_visible_item_index {
232 break 'a;
233 }
234
235 index = index.saturating_add(1);
236
237 if self.is_visible_index(index) {
238 break;
239 }
240 }
241 }
242
243 if index == current_index {
244 None
245 } else {
246 Some(index)
247 }
248 }
249
250 fn selection_updown(&self, current_index: usize, up: bool) -> Option<usize> {
251 let mut index = current_index;
252
253 loop {
254 index = {
255 let new_index = if up {
256 index.saturating_sub(1)
257 } else {
258 index.saturating_add(1)
259 };
260
261 if new_index == index {
262 break;
263 }
264
265 if new_index >= self.items.len() {
266 break;
267 }
268
269 new_index
270 };
271
272 if self.is_visible_index(index) {
273 break;
274 }
275 }
276
277 if index == current_index {
278 None
279 } else {
280 Some(index)
281 }
282 }
283
284 fn select_parent(&mut self, current_index: usize) -> Option<usize> {
285 let indent = self.items.tree_items.get(current_index)?.info().indent();
286
287 let mut index = current_index;
288
289 while let Some(selection) = self.selection_updown(index, true) {
290 index = selection;
291
292 if self.items.tree_items[index].info().indent() < indent {
293 break;
294 }
295 }
296
297 if index == current_index {
298 None
299 } else {
300 Some(index)
301 }
302 }
303
304 fn selection_left(&mut self, current_index: usize) -> Option<usize> {
305 let item = &mut self.items.tree_items.get(current_index)?;
306
307 if item.kind().is_database() && !item.kind().is_database_collapsed() {
308 self.items.collapse(current_index, false);
309 return Some(current_index);
310 }
311
312 if item.kind().is_schema() && !item.kind().is_schema_collapsed() {
313 self.items.collapse(current_index, false);
314 return Some(current_index);
315 }
316
317 self.select_parent(current_index)
318 }
319
320 fn expand(&mut self, current_selection: usize) -> Option<usize> {
321 let item = &mut self.items.tree_items.get(current_selection)?;
322
323 if item.kind().is_database() && item.kind().is_database_collapsed() {
324 self.items.expand(current_selection, false);
325 return Some(current_selection);
326 }
327
328 if item.kind().is_schema() && item.kind().is_schema_collapsed() {
329 self.items.expand(current_selection, false);
330 return Some(current_selection);
331 }
332
333 None
334 }
335
336 fn selection_right(&mut self, current_selection: usize) -> Option<usize> {
337 let item = &mut self.items.tree_items.get(current_selection)?;
338
339 if item.kind().is_database() {
340 if item.kind().is_database_collapsed() {
341 self.items.expand(current_selection, false);
342 return Some(current_selection);
343 }
344 return self.selection_updown(current_selection, false);
345 }
346
347 if item.kind().is_schema() {
348 if item.kind().is_schema_collapsed() {
349 self.items.expand(current_selection, false);
350 return Some(current_selection);
351 }
352 return self.selection_updown(current_selection, false);
353 }
354
355 None
356 }
357
358 fn is_visible_index(&self, index: usize) -> bool {
359 self.items
360 .tree_items
361 .get(index)
362 .map(|item| item.info().is_visible())
363 .unwrap_or_default()
364 }
365}
366
367#[cfg(test)]
368mod test {
369 use crate::{Database, DatabaseTree, MoveSelection, Schema, Table};
370 use std::collections::BTreeSet;
371
372 impl Table {
373 fn new(name: String) -> Self {
374 Table {
375 name,
376 create_time: None,
377 update_time: None,
378 engine: None,
379 schema: None,
380 }
381 }
382
383 fn new_with_schema(name: String, schema: String) -> Self {
384 Table {
385 name,
386 create_time: None,
387 update_time: None,
388 engine: None,
389 schema: Some(schema),
390 }
391 }
392 }
393
394 #[test]
395 fn test_selection() {
396 let items = vec![Database::new(
397 "a".to_string(),
398 vec![Table::new("b".to_string()).into()],
399 )];
400
401 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
405
406 assert!(tree.move_selection(MoveSelection::Right));
407 assert_eq!(tree.selection, Some(0));
408 assert!(tree.move_selection(MoveSelection::Down));
409 assert_eq!(tree.selection, Some(1));
410
411 let items = vec![Database::new(
412 "a".to_string(),
413 vec![Schema {
414 name: "b".to_string(),
415 tables: vec![Table::new("c".to_string()).into()],
416 }
417 .into()],
418 )];
419
420 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
425
426 assert!(tree.move_selection(MoveSelection::Right));
427 assert_eq!(tree.selection, Some(0));
428 assert!(tree.move_selection(MoveSelection::Down));
429 assert_eq!(tree.selection, Some(1));
430 assert!(tree.move_selection(MoveSelection::Right));
431 assert_eq!(tree.selection, Some(1));
432 assert!(tree.move_selection(MoveSelection::Down));
433 assert_eq!(tree.selection, Some(2));
434 }
435
436 #[test]
437 fn test_expand() {
438 let items = vec![Database::new(
439 "a".to_string(),
440 vec![Table::new("b".to_string()).into()],
441 )];
442
443 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
447
448 assert!(tree.move_selection(MoveSelection::Enter));
449 assert!(!tree.items.tree_items[0].kind().is_database_collapsed());
450 assert_eq!(tree.selection, Some(0));
451
452 assert!(tree.move_selection(MoveSelection::Down));
453 assert_eq!(tree.selection, Some(1));
454
455 assert!(!tree.move_selection(MoveSelection::Enter));
456 assert_eq!(tree.selection, Some(1));
457
458 let items = vec![Database::new(
459 "a".to_string(),
460 vec![Schema {
461 name: "b".to_string(),
462 tables: vec![Table::new("c".to_string()).into()],
463 }
464 .into()],
465 )];
466
467 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
472
473 assert!(tree.move_selection(MoveSelection::Enter));
474 assert!(!tree.items.tree_items[0].kind().is_database_collapsed());
475 assert!(tree.items.tree_items[1].kind().is_schema_collapsed());
476 assert_eq!(tree.selection, Some(0));
477
478 assert!(tree.move_selection(MoveSelection::Down));
479 assert_eq!(tree.selection, Some(1));
480
481 assert!(tree.move_selection(MoveSelection::Enter));
482 assert!(!tree.items.tree_items[1].kind().is_database_collapsed());
483 assert_eq!(tree.selection, Some(1));
484
485 assert!(tree.move_selection(MoveSelection::Down));
486 assert_eq!(tree.selection, Some(2));
487
488 assert!(!tree.move_selection(MoveSelection::Enter));
489 assert_eq!(tree.selection, Some(2));
490 }
491
492 #[test]
493 fn test_selection_multiple_up_down() {
494 let items = vec![Database::new(
495 "a".to_string(),
496 vec!["b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
497 .iter()
498 .map(|x| Table::new(x.to_string()).into())
499 .collect(),
500 )];
501
502 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
508
509 assert!(tree.move_selection(MoveSelection::Right));
510 assert_eq!(tree.selection, Some(0));
511 assert!(tree.move_selection(MoveSelection::MultipleDown));
512 assert_eq!(tree.selection, Some(10));
513
514 tree.selection = Some(11);
515 assert!(tree.move_selection(MoveSelection::MultipleUp));
516 assert_eq!(tree.selection, Some(1));
517
518 let items = vec![Database::new(
519 "a".to_string(),
520 vec![Schema {
521 name: "b".to_string(),
522 tables: vec!["c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]
523 .iter()
524 .map(|x| Table::new(x.to_string()).into())
525 .collect(),
526 }
527 .into()],
528 )];
529
530 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
537
538 assert!(tree.move_selection(MoveSelection::Right));
539 assert_eq!(tree.selection, Some(0));
540 assert!(tree.move_selection(MoveSelection::MultipleDown));
541 assert_eq!(tree.selection, Some(10));
542
543 tree.selection = Some(11);
544 assert!(tree.move_selection(MoveSelection::MultipleUp));
545 assert_eq!(tree.selection, Some(1));
546 }
547
548 #[test]
549 fn test_selection_skips_collapsed() {
550 let items = vec![
551 Database::new(
552 "a".to_string(),
553 vec![
554 Table::new("b".to_string()).into(),
555 Table::new("c".to_string()).into(),
556 ],
557 ),
558 Database::new("d".to_string(), vec![Table::new("e".to_string()).into()]),
559 ];
560
561 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
568 tree.selection = Some(1);
569
570 assert!(tree.move_selection(MoveSelection::Down));
571 assert_eq!(tree.selection, Some(3));
572
573 let items = vec![
574 Database::new(
575 "a".to_string(),
576 vec![Schema {
577 name: "b".to_string(),
578 tables: vec![Table::new("c".to_string()).into()],
579 }
580 .into()],
581 ),
582 Database::new(
583 "d".to_string(),
584 vec![Schema {
585 name: "e".to_string(),
586 tables: vec![Table::new("f".to_string()).into()],
587 }
588 .into()],
589 ),
590 ];
591
592 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
600 tree.selection = Some(1);
601
602 assert!(tree.move_selection(MoveSelection::Down));
603 assert_eq!(tree.selection, Some(3));
604 }
605
606 #[test]
607 fn test_selection_left_collapse() {
608 let items = vec![Database::new(
609 "a".to_string(),
610 vec![
611 Table::new("b".to_string()).into(),
612 Table::new("c".to_string()).into(),
613 ],
614 )];
615
616 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
621 tree.selection = Some(0);
622 tree.items.expand(0, false);
623
624 assert!(tree.move_selection(MoveSelection::Left));
625 assert_eq!(tree.selection, Some(0));
626 assert!(tree.items.tree_items[0].kind().is_database_collapsed());
627 assert!(!tree.items.tree_items[1].info().is_visible());
628 assert!(!tree.items.tree_items[2].info().is_visible());
629
630 let items = vec![
631 Database::new(
632 "a".to_string(),
633 vec![Schema {
634 name: "b".to_string(),
635 tables: vec![Table::new("c".to_string()).into()],
636 }
637 .into()],
638 ),
639 Database::new(
640 "d".to_string(),
641 vec![Schema {
642 name: "e".to_string(),
643 tables: vec![Table::new("f".to_string()).into()],
644 }
645 .into()],
646 ),
647 ];
648
649 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
657 tree.selection = Some(0);
658 tree.items.expand(0, false);
659
660 assert!(tree.move_selection(MoveSelection::Left));
661 assert_eq!(tree.selection, Some(0));
662 assert!(tree.items.tree_items[0].kind().is_database_collapsed());
663 assert!(!tree.items.tree_items[1].info().is_visible());
664 assert!(!tree.items.tree_items[2].info().is_visible());
665 }
666
667 #[test]
668 fn test_selection_left_parent() {
669 let items = vec![Database::new(
670 "a".to_string(),
671 vec![
672 Table::new("b".to_string()).into(),
673 Table::new("c".to_string()).into(),
674 ],
675 )];
676
677 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
682 tree.selection = Some(2);
683 tree.items.expand(0, false);
684
685 assert!(tree.move_selection(MoveSelection::Left));
686 assert_eq!(tree.selection, Some(0));
687
688 let items = vec![Database::new(
689 "a".to_string(),
690 vec![Schema {
691 name: "b".to_string(),
692 tables: vec![Table::new_with_schema("c".to_string(), "a".to_string()).into()],
693 }
694 .into()],
695 )];
696
697 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
702
703 tree.selection = Some(2);
704 tree.items.expand(0, false);
705 tree.items.expand(1, false);
706 assert!(tree.move_selection(MoveSelection::Left));
707 assert_eq!(tree.selection, Some(1));
708
709 assert!(tree.move_selection(MoveSelection::Left));
710 assert_eq!(tree.selection, Some(1));
711
712 assert!(tree.move_selection(MoveSelection::Left));
713 assert_eq!(tree.selection, Some(0));
714 }
715
716 #[test]
717 fn test_selection_right_expand() {
718 let items = vec![Database::new(
719 "a".to_string(),
720 vec![
721 Table::new("b".to_string()).into(),
722 Table::new("c".to_string()).into(),
723 ],
724 )];
725
726 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
731 tree.selection = Some(0);
732
733 assert!(tree.move_selection(MoveSelection::Right));
734 assert_eq!(tree.selection, Some(0));
735 assert!(!tree.items.tree_items[0].kind().is_database_collapsed());
736
737 assert!(tree.move_selection(MoveSelection::Right));
738 assert_eq!(tree.selection, Some(1));
739
740 let items = vec![Database::new(
741 "a".to_string(),
742 vec![Schema {
743 name: "b".to_string(),
744 tables: vec![Table::new_with_schema("c".to_string(), "a".to_string()).into()],
745 }
746 .into()],
747 )];
748
749 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
754 tree.selection = Some(0);
755
756 assert!(tree.move_selection(MoveSelection::Right));
757 assert_eq!(tree.selection, Some(0));
758 assert!(!tree.items.tree_items[0].kind().is_database_collapsed());
759
760 assert!(tree.move_selection(MoveSelection::Right));
761 assert_eq!(tree.selection, Some(1));
762
763 assert!(tree.move_selection(MoveSelection::Right));
764 assert_eq!(tree.selection, Some(1));
765 assert!(!tree.items.tree_items[0].kind().is_schema_collapsed());
766 }
767
768 #[test]
769 fn test_visible_selection() {
770 let items = vec![
771 Database::new(
772 "a".to_string(),
773 vec![
774 Table::new("b".to_string()).into(),
775 Table::new("c".to_string()).into(),
776 ],
777 ),
778 Database::new("d".to_string(), vec![Table::new("e".to_string()).into()]),
779 ];
780
781 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
788 tree.items.expand(0, false);
789 tree.items.expand(3, false);
790
791 tree.selection = Some(0);
792 assert!(tree.move_selection(MoveSelection::Left));
793 assert!(tree.move_selection(MoveSelection::Down));
794 assert_eq!(tree.selection, Some(3));
795 let s = tree.visual_selection().unwrap();
796
797 assert_eq!(s.count, 3);
798 assert_eq!(s.index, 1);
799
800 let items = vec![
801 Database::new(
802 "a".to_string(),
803 vec![Schema {
804 name: "b".to_string(),
805 tables: vec![Table::new_with_schema("c".to_string(), "a".to_string()).into()],
806 }
807 .into()],
808 ),
809 Database::new(
810 "d".to_string(),
811 vec![Schema {
812 name: "e".to_string(),
813 tables: vec![Table::new_with_schema("f".to_string(), "d".to_string()).into()],
814 }
815 .into()],
816 ),
817 ];
818
819 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
827 tree.items.expand(0, false);
828 tree.items.expand(1, false);
829 tree.items.expand(3, false);
830 tree.selection = Some(0);
831
832 assert!(tree.move_selection(MoveSelection::Left));
833 assert!(tree.move_selection(MoveSelection::Down));
834 assert_eq!(tree.selection, Some(3));
835 let s = tree.visual_selection().unwrap();
836
837 assert_eq!(s.count, 4);
838 assert_eq!(s.index, 1);
839 }
840
841 #[test]
842 fn test_selection_top() {
843 let items = vec![Database::new(
844 "a".to_string(),
845 vec![
846 Table::new("b".to_string()).into(),
847 Table::new("c".to_string()).into(),
848 Table::new("d".to_string()).into(),
849 ],
850 )];
851
852 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
858 tree.selection = Some(3);
859 tree.items.expand(0, false);
860
861 assert!(tree.move_selection(MoveSelection::Top));
862 assert_eq!(tree.selection, Some(0));
863
864 let items = vec![Database::new(
865 "a".to_string(),
866 vec![Schema {
867 name: "b".to_string(),
868 tables: vec![
869 Table::new("c".to_string()).into(),
870 Table::new("d".to_string()).into(),
871 ],
872 }
873 .into()],
874 )];
875
876 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
882 tree.selection = Some(3);
883 tree.items.expand(0, false);
884 tree.items.expand(1, false);
885
886 assert!(tree.move_selection(MoveSelection::Top));
887 assert_eq!(tree.selection, Some(0));
888 }
889
890 #[test]
891 fn test_selection_bottom() {
892 let items = vec![Database::new(
893 "a".to_string(),
894 vec![
895 Table::new("b".to_string()).into(),
896 Table::new("c".to_string()).into(),
897 Table::new("d".to_string()).into(),
898 ],
899 )];
900
901 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
907 tree.selection = Some(0);
908 tree.items.expand(0, false);
909
910 assert!(tree.move_selection(MoveSelection::End));
911 assert_eq!(tree.selection, Some(3));
912
913 let items = vec![Database::new(
914 "a".to_string(),
915 vec![Schema {
916 name: "b".to_string(),
917 tables: vec![
918 Table::new("c".to_string()).into(),
919 Table::new("d".to_string()).into(),
920 ],
921 }
922 .into()],
923 )];
924
925 let mut tree = DatabaseTree::new(&items, &BTreeSet::new()).unwrap();
931 tree.selection = Some(0);
932 tree.items.expand(0, false);
933 tree.items.expand(1, false);
934
935 assert!(tree.move_selection(MoveSelection::End));
936 assert_eq!(tree.selection, Some(3));
937 }
938}