Skip to main content

libsurfer/
displayed_item_tree.rs

1use itertools::Itertools;
2use serde::{Deserialize, Serialize};
3use std::ops::Range;
4
5use crate::MoveDir;
6use crate::displayed_item::DisplayedItemRef;
7
8#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
9pub struct Node {
10    pub item_ref: DisplayedItemRef,
11    /// Nesting level of the node.
12    pub level: u8,
13    /// Whether a subtree of this node (if it exists) is shown
14    pub unfolded: bool,
15    pub selected: bool,
16}
17
18#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19pub enum MoveError {
20    InvalidIndex,
21    InvalidLevel,
22    CircularMove,
23    LevelTooDeep,
24}
25
26/// N-th visible item, becomes invalid after any add/remove/move/fold/unfold operation
27#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
28pub struct VisibleItemIndex(pub usize);
29
30/// N-th item, may currently be invisible, becomes invalid after any add/remove/move operation
31#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Deserialize)]
32pub struct ItemIndex(pub usize);
33
34#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
35pub struct TargetPosition {
36    /// before which index to insert, may be in a range of `0..=tree.len()` to allow for appending
37    pub before: ItemIndex,
38    /// at which level to insert, if None the level is derived from the item before
39    pub level: u8, // TODO go back to Option and implement
40}
41
42pub struct VisibleItemIterator<'a> {
43    items: &'a Vec<Node>,
44    next_idx: usize,
45}
46
47impl<'a> Iterator for VisibleItemIterator<'a> {
48    type Item = &'a Node;
49
50    fn next(&mut self) -> Option<Self::Item> {
51        let this_idx = self.next_idx;
52
53        let this_item = self.items.get(this_idx);
54        if this_item.is_some() {
55            self.next_idx = next_visible_item(self.items, this_idx);
56        }
57        this_item
58    }
59}
60
61#[must_use = "iterators are lazy and do nothing unless consumed"]
62pub struct VisibleItemIteratorMut<'a> {
63    items: &'a mut Vec<Node>,
64    /// Index of the next element to return, not guaranteed to be in-bounds
65    next_idx: usize,
66}
67
68impl<'a> Iterator for VisibleItemIteratorMut<'a> {
69    type Item = &'a mut Node;
70
71    fn next(&mut self) -> Option<Self::Item> {
72        let this_idx = self.next_idx;
73
74        if this_idx < self.items.len() {
75            self.next_idx = next_visible_item(self.items, this_idx);
76
77            let ptr = self.items.as_mut_ptr();
78            // access is safe since we
79            // - do access within bounds
80            // - know that we won't generate two equal references (next call, next item)
81            // - know that no second iterator or other access can happen while the references/iterator exist
82            Some(unsafe { &mut *ptr.add(this_idx) })
83        } else {
84            None
85        }
86    }
87}
88
89pub struct Info<'a> {
90    pub node: &'a Node,
91    pub idx: ItemIndex,
92    pub vidx: VisibleItemIndex,
93    pub has_children: bool,
94    pub last: bool,
95}
96
97pub struct VisibleItemIteratorExtraInfo<'a> {
98    items: &'a Vec<Node>,
99    /// Index of the next element to return, not guaranteed to be in-bounds
100    next_idx: usize,
101    next_vidx: usize,
102}
103
104impl<'a> Iterator for VisibleItemIteratorExtraInfo<'a> {
105    type Item = Info<'a>;
106
107    fn next(&mut self) -> Option<Self::Item> {
108        let this_idx = self.next_idx;
109        let this_vidx = self.next_vidx;
110        if this_idx < self.items.len() {
111            self.next_idx = next_visible_item(self.items, this_idx);
112            self.next_vidx += 1;
113
114            let this_level = self.items[this_idx].level;
115            let has_child = self
116                .items
117                .get(this_idx + 1)
118                .is_some_and(|item| item.level > this_level);
119            Some(Info {
120                node: &self.items[this_idx],
121                idx: ItemIndex(this_idx),
122                vidx: VisibleItemIndex(this_vidx),
123                has_children: has_child,
124                last: self.next_idx >= self.items.len(),
125            })
126        } else {
127            None
128        }
129    }
130}
131
132/// Tree if items to be displayed
133///
134/// Items are stored in a flat list, with the level property indicating the nesting level
135/// of the item. The items are stored in-order.
136/// For documentation on the properties of a node, see the [Node] struct.
137///
138/// Note also infos on the [`VisibleItemIndex`] and [`ItemIndex`] types w.r.t. stability of these
139/// index types.
140///
141/// Invariants:
142/// - The nesting levels of the tree must monotonically increase (but may jump levels going down)
143#[derive(Default, Serialize, Deserialize, Debug, Clone)]
144pub struct DisplayedItemTree {
145    items: Vec<Node>,
146}
147
148impl DisplayedItemTree {
149    #[must_use]
150    pub fn new() -> Self {
151        DisplayedItemTree { items: vec![] }
152    }
153
154    #[must_use]
155    pub fn len(&self) -> usize {
156        self.items.len()
157    }
158
159    #[must_use]
160    pub fn is_empty(&self) -> bool {
161        self.items.is_empty()
162    }
163
164    pub fn iter(&self) -> impl Iterator<Item = &Node> + use<'_> {
165        self.items.iter()
166    }
167
168    /// Iterate through all visible items
169    #[must_use]
170    pub fn iter_visible(&self) -> VisibleItemIterator<'_> {
171        VisibleItemIterator {
172            items: &self.items,
173            next_idx: 0,
174        }
175    }
176
177    pub fn iter_visible_mut(&mut self) -> VisibleItemIteratorMut<'_> {
178        VisibleItemIteratorMut {
179            items: &mut self.items,
180            next_idx: 0,
181        }
182    }
183
184    #[must_use]
185    pub fn iter_visible_extra(&self) -> VisibleItemIteratorExtraInfo<'_> {
186        VisibleItemIteratorExtraInfo {
187            items: &self.items,
188            next_idx: 0,
189            next_vidx: 0,
190        }
191    }
192
193    pub fn iter_visible_selected(&self) -> impl Iterator<Item = &Node> + use<'_> {
194        self.iter_visible().filter(|i| i.selected)
195    }
196
197    /// Iterate through items, skipping invisible items, return index of n-th visible item
198    #[must_use]
199    pub fn get_visible(&self, index: VisibleItemIndex) -> Option<&Node> {
200        self.iter_visible().nth(index.0)
201    }
202
203    #[must_use]
204    pub fn get_visible_extra(&self, index: VisibleItemIndex) -> Option<Info<'_>> {
205        self.iter_visible_extra().nth(index.0)
206    }
207
208    #[must_use]
209    pub fn get(&self, index: ItemIndex) -> Option<&Node> {
210        self.items.get(index.0)
211    }
212
213    pub fn get_mut(&mut self, index: ItemIndex) -> Option<&mut Node> {
214        self.items.get_mut(index.0)
215    }
216
217    #[must_use]
218    pub fn to_displayed(&self, index: VisibleItemIndex) -> Option<ItemIndex> {
219        self.get_visible_extra(index)?.idx.into()
220    }
221
222    /// insert item after offset visible items (either in root or in unfolded parent)
223    pub fn insert_item(
224        &mut self,
225        item: DisplayedItemRef,
226        position: TargetPosition,
227    ) -> Result<ItemIndex, MoveError> {
228        check_location(&self.items, position)?;
229
230        self.items.insert(
231            position.before.0,
232            Node {
233                item_ref: item,
234                level: position.level,
235                unfolded: true,
236                selected: false,
237            },
238        );
239
240        Ok(position.before)
241    }
242
243    /// Return the index past the end of the subtree started by `idx`
244    fn subtree_end(&self, start_idx: usize) -> usize {
245        let level = self.items[start_idx].level;
246        self.items
247            .iter()
248            .skip(start_idx + 1)
249            .enumerate()
250            .find_map(|(idx, x)| (x.level <= level).then_some(idx + start_idx + 1))
251            .unwrap_or(self.items.len())
252    }
253
254    pub fn remove_recursive(&mut self, ItemIndex(item): ItemIndex) -> Vec<DisplayedItemRef> {
255        let end = self.subtree_end(item);
256        self.items
257            .drain(item..end)
258            .map(|x| x.item_ref)
259            .collect_vec()
260    }
261
262    pub fn remove_dissolve(&mut self, ItemIndex(item): ItemIndex) -> DisplayedItemRef {
263        let end = self.subtree_end(item);
264        self.items[item + 1..end]
265            .iter_mut()
266            .for_each(|x| x.level -= 1);
267        self.items.remove(item).item_ref
268    }
269
270    pub fn drain_recursive_if<F>(&mut self, f: F) -> Vec<DisplayedItemRef>
271    where
272        F: Fn(&Node) -> bool,
273    {
274        let mut removed = vec![];
275
276        let mut idx = 0;
277        while idx < self.items.len() {
278            if f(self.items.get(idx).unwrap()) {
279                let end = self.subtree_end(idx);
280                removed.extend(self.items.drain(idx..end).map(|x| x.item_ref));
281            } else {
282                idx += 1;
283            }
284        }
285
286        removed
287    }
288
289    /// Find the item before `idx` that is visible, independent of level
290    fn visible_predecessor(&self, mut idx: usize) -> Option<usize> {
291        if idx == 0 || idx > self.items.len() {
292            return None;
293        }
294
295        let start_level = self.items[idx].level;
296        let mut candidate = idx - 1;
297        let mut limit_level = self.items[candidate].level;
298
299        loop {
300            idx -= 1;
301            let looking_item = &self.items[idx];
302            // ignore subtrees deeper than what we found already
303            if looking_item.level < limit_level {
304                limit_level = looking_item.level;
305                // the whole subtree we have been looking at is not visible,
306                // assume for now the current node is
307                if !looking_item.unfolded {
308                    candidate = idx;
309                }
310            }
311            if self.items[idx].level <= start_level || idx == 0 {
312                return Some(candidate);
313            }
314        }
315    }
316
317    /// Move a visible item (and it's subtree) up/down by one visible item
318    ///
319    /// When moving up we move into all visible deeper trees first before skipping up.
320    /// Moving down we move out until we are on the level of the next element.
321    /// This way all indentations possible due to opened subtrees are reachable.
322    ///
323    /// Folded subtrees are skipped.
324    ///
325    /// `f` will be called with a node that might become the parent after move.
326    /// It must return true iff that node is allowed to have child nodes.
327    pub fn move_item<F>(
328        &mut self,
329        vidx: VisibleItemIndex,
330        direction: MoveDir,
331        f: F,
332    ) -> Result<VisibleItemIndex, MoveError>
333    where
334        F: Fn(&Node) -> bool,
335    {
336        let Some(ItemIndex(idx)) = self.to_displayed(vidx) else {
337            return Err(MoveError::InvalidIndex);
338        };
339
340        let this_level = self.items[idx].level;
341        let end = self.subtree_end(idx);
342        let new_index = match direction {
343            MoveDir::Down => match self.items.get(end) {
344                // we are at the end, but maybe still down in the hierarchy -> shift out
345                None => {
346                    shift_subtree_to_level(
347                        &mut self.items[idx..end],
348                        this_level.saturating_sub(1),
349                    )?;
350                    vidx
351                }
352                // the next node is less indented -> shift out, don't move yet
353                Some(Node { level, .. }) if *level < this_level => {
354                    shift_subtree_to_level(&mut self.items[idx..end], this_level - 1)?;
355                    vidx
356                }
357                // the next node must be a sibling, it's unfolded and can have children so move into it
358                Some(
359                    node @ Node {
360                        unfolded: true,
361                        level,
362                        ..
363                    },
364                ) if f(node) => {
365                    self.move_items(
366                        vec![ItemIndex(idx)],
367                        TargetPosition {
368                            before: ItemIndex(end + 1),
369                            level: *level + 1,
370                        },
371                    )?;
372                    VisibleItemIndex(vidx.0 + 1)
373                }
374                // remaining: the next node is either a folded sibling or can't have children, jump over
375                _ => {
376                    self.move_items(
377                        vec![ItemIndex(idx)],
378                        TargetPosition {
379                            before: ItemIndex(self.subtree_end(end)),
380                            level: this_level,
381                        },
382                    )?;
383                    VisibleItemIndex(vidx.0 + 1)
384                }
385            },
386            MoveDir::Up => {
387                match self.visible_predecessor(idx).map(|i| (i, &self.items[i])) {
388                    None => vidx,
389                    // empty, unfolded node deeper/equal in, possibly to move into
390                    // ... or node deeper in, but don't move into
391                    Some((_node_idx, node))
392                        if (node.level >= this_level && f(node) && node.unfolded)
393                            | (node.level > this_level) =>
394                    {
395                        shift_subtree_to_level(&mut self.items[idx..end], this_level + 1)?;
396                        vidx
397                    }
398                    Some((node_idx, node)) => {
399                        self.move_items(
400                            vec![ItemIndex(idx)],
401                            TargetPosition {
402                                before: ItemIndex(node_idx),
403                                level: node.level,
404                            },
405                        )?;
406                        VisibleItemIndex(vidx.0 - 1)
407                    }
408                }
409            }
410        };
411        Ok(new_index)
412    }
413
414    /// Move multiple items to a specified location
415    ///
416    /// Indices may be unsorted and contain duplicates, but must be valid.
417    /// Visibility is ignored for this function.
418    ///
419    /// Deals with any combination of items to move, except the error
420    /// cases below. Rules that are followed:
421    /// - The relative order of element should be the same, before and after the move
422    /// - If the root of a subtree is moved, the whole subtree is moved
423    /// - If a node inside a subtree is moved, then it's moved out of that subtree
424    /// - If both the root and a node of a subtree are moved, the node is moved out
425    ///   of the subtree and ends up after the root node
426    ///
427    /// Possible errors:
428    /// - trying to move an element into itself
429    /// - trying to move an element into another moved element
430    /// - invalid indices
431    /// - level too deep for subtree, level is clipped to level 255
432    pub fn move_items(
433        &mut self,
434        indices: Vec<ItemIndex>,
435        target: TargetPosition,
436    ) -> Result<(), MoveError> {
437        if let Some(idx) = indices.last()
438            && idx.0 >= self.items.len()
439        {
440            return Err(MoveError::InvalidIndex);
441        }
442
443        // sort from back to front
444        // that makes removal easier since we don't have to check whether we have to move some
445        // subtree out, and the indices don't have to be updated - but moving them to the temp
446        // vector needs some shuffling
447        let indices = indices
448            .into_iter()
449            .sorted_by_key(|ii| usize::MAX - ii.0)
450            .dedup()
451            .collect_vec();
452
453        let mut result = self.items.clone();
454        let mut extracted = vec![];
455
456        let mut shifted_target = target.before.0;
457        for ItemIndex(start) in indices {
458            let end = self.subtree_end(start);
459            if ((start + 1)..end).contains(&shifted_target) {
460                return Err(MoveError::CircularMove);
461            }
462
463            // if we remove elements before the target, adapt the index accordingly
464            if start < shifted_target {
465                shifted_target -= end - start;
466            }
467
468            shift_subtree_to_level(&mut result[start..end], target.level)?;
469            extracted.splice(0..0, result.drain(start..end));
470        }
471
472        check_location(
473            &result,
474            TargetPosition {
475                before: ItemIndex(shifted_target),
476                level: target.level,
477            },
478        )?;
479
480        result.splice(shifted_target..shifted_target, extracted);
481
482        assert_eq!(self.items.len(), result.len());
483        self.items = result;
484        Ok(())
485    }
486
487    /// Return the range of valid levels for inserting above `item`, given the visible nodes
488    ///
489    /// `f` will be called with what will become the in-order predecessor node
490    /// after insert. It must return true iff that node is allowed to have child nodes.
491    pub fn valid_levels_visible<F>(&self, item: VisibleItemIndex, f: F) -> Range<u8>
492    where
493        F: Fn(&Node) -> bool,
494    {
495        let Some(split) = item.0.checked_sub(1) else {
496            return 0..1;
497        };
498        match self
499            .iter_visible()
500            .skip(split)
501            .take(2)
502            .collect_vec()
503            .as_slice()
504        {
505            [] => 0..1, // only happens for indices > self.items.len()
506            [last] => {
507                0..last
508                    .level
509                    .saturating_add(1 + u8::from(f(last) && last.unfolded))
510            }
511            [pre, post, ..] => {
512                post.level
513                    ..pre
514                        .level
515                        .saturating_add(1 + u8::from(f(pre) && pre.unfolded))
516            }
517        }
518    }
519
520    pub fn xfold(&mut self, ItemIndex(item): ItemIndex, unfolded: bool) {
521        self.items[item].unfolded = unfolded;
522        if !unfolded {
523            let end = self.subtree_end(item);
524            for x in &mut self.items[item..end] {
525                x.selected = false;
526            }
527        }
528    }
529
530    pub fn xfold_all(&mut self, unfolded: bool) {
531        for x in &mut self.items {
532            x.unfolded = unfolded;
533            if !unfolded && x.level > 0 {
534                x.selected = false;
535            }
536        }
537    }
538
539    pub fn xfold_recursive(&mut self, ItemIndex(item): ItemIndex, unfolded: bool) {
540        let end = self.subtree_end(item);
541        self.items[item].unfolded = unfolded;
542        for x in &mut self.items[item + 1..end] {
543            x.unfolded = unfolded;
544            if !unfolded {
545                x.selected = false;
546            }
547        }
548    }
549
550    pub fn xselect(&mut self, vidx: VisibleItemIndex, selected: bool) {
551        if let Some(idx) = self.to_displayed(vidx) {
552            self.items[idx.0].selected = selected;
553        }
554    }
555
556    /// Select/Deselect all visible items
557    pub fn xselect_all_visible(&mut self, selected: bool) {
558        for x in &mut self.iter_visible_mut() {
559            x.selected = selected;
560        }
561    }
562
563    /// Change selection for visible items, in inclusive range
564    pub fn xselect_visible_range(
565        &mut self,
566        VisibleItemIndex(from): VisibleItemIndex,
567        VisibleItemIndex(to): VisibleItemIndex,
568        selected: bool,
569    ) {
570        let (from, to) = if from < to {
571            (from, to + 1)
572        } else {
573            (to, from + 1)
574        };
575        for node in self.iter_visible_mut().skip(from).take(to - from) {
576            node.selected = selected;
577        }
578    }
579
580    #[must_use]
581    pub fn subtree_contains(
582        &self,
583        ItemIndex(root): ItemIndex,
584        ItemIndex(candidate): ItemIndex,
585    ) -> bool {
586        let end = self.subtree_end(candidate);
587        (root..end).contains(&candidate)
588    }
589}
590
591/// Find the index of the next visible item, or return `items.len()`
592///
593/// Precondition: `this_idx` must be a valid `items` index
594fn next_visible_item(items: &[Node], this_idx: usize) -> usize {
595    let this_level = items[this_idx].level;
596    let mut next_idx = this_idx + 1;
597    if !items[this_idx].unfolded {
598        while next_idx < items.len() && items[next_idx].level > this_level {
599            next_idx += 1;
600        }
601    }
602    next_idx
603}
604
605/// Check whether `target_position` is a valid location for insertion
606///
607/// This means we have to check if the requested indentation level is correct.
608fn check_location(items: &[Node], target_position: TargetPosition) -> Result<(), MoveError> {
609    if target_position.before.0 > items.len() {
610        return Err(MoveError::InvalidIndex);
611    }
612    let before = target_position
613        .before
614        .0
615        .checked_sub(1)
616        .and_then(|i| items.get(i));
617    let after = items.get(target_position.before.0);
618    let valid_range = match (before.map(|n| n.level), after.map(|n| n.level)) {
619        // If we want to be the first element, no indent possible
620        (None, _) => 0..=0,
621        // If we want to be the last element it's allowed to be completely unindent, indent into
622        // the last element, and everything in between
623        (Some(before), None) => 0..=before.saturating_add(1),
624        // if the latter element is indented further then the one before, we must indent
625        // otherwise we'd change the parent of the after subtree
626        (Some(before), Some(after)) if after > before => after..=after,
627        // if before and after are at the same level, we can insert on the same level,
628        // or we may indent one level
629        (Some(before), Some(after)) if after == before => before..=after.saturating_add(1),
630        // if before is the last element of a subtree and after is unindented
631        // then we can insert anywhere between the after element (not further out bec.
632        // that would change parents of the elements after), indent into the before element
633        // or anything in between
634        (Some(before), Some(after)) => after..=before.saturating_add(1),
635    };
636
637    if valid_range.contains(&target_position.level) {
638        Ok(())
639    } else {
640        Err(MoveError::InvalidLevel)
641    }
642}
643
644fn shift_subtree_to_level(nodes: &mut [Node], target_level: u8) -> Result<(), MoveError> {
645    let Some(from_level) = nodes.first().map(|node| node.level) else {
646        return Ok(());
647    };
648    let level_corr = i16::from(target_level) - i16::from(from_level);
649    for elem in nodes.iter_mut() {
650        elem.level = (i16::from(elem.level) + level_corr)
651            .try_into()
652            .map_err(|_| MoveError::InvalidLevel)?;
653    }
654    Ok(())
655}
656
657#[cfg(test)]
658mod tests {
659    use super::*;
660    use itertools::Itertools;
661
662    fn build_tree(nodes: &[(usize, u8, bool, bool)]) -> DisplayedItemTree {
663        let mut tree = DisplayedItemTree::new();
664        for &(item, level, unfolded, selected) in nodes {
665            tree.items.push(Node {
666                item_ref: DisplayedItemRef(item),
667                level,
668                unfolded,
669                selected,
670            });
671        }
672        tree
673    }
674
675    /// common test tree
676    /// ```text
677    ///    0  1  2
678    /// 0: 0
679    /// 1: 1
680    /// 2: 2       < folded
681    /// 3:   20
682    /// 4:     200
683    /// 5: 3
684    /// 6:   30
685    /// 7:   31
686    /// 8: 4
687    /// 9: 5
688    /// ```
689    fn test_tree() -> DisplayedItemTree {
690        build_tree(&[
691            (0, 0, true, false),
692            (1, 0, false, false),
693            (2, 0, false, false),
694            (20, 1, true, false),
695            (200, 2, true, false),
696            (3, 0, true, false),
697            (30, 1, true, false),
698            (31, 1, true, false),
699            (4, 0, true, false),
700            (5, 0, true, false),
701        ])
702    }
703
704    #[test]
705    fn test_iter_visible() {
706        let tree = test_tree();
707        assert_eq!(
708            tree.iter_visible().map(|x| x.item_ref.0).collect_vec(),
709            vec![0, 1, 2, 3, 30, 31, 4, 5]
710        );
711    }
712
713    #[test]
714    fn test_iter_visible_extra() {
715        let tree = test_tree();
716        assert_eq!(
717            tree.iter_visible_extra()
718                .map(|info| (
719                    info.node.item_ref.0,
720                    info.idx.0,
721                    info.vidx.0,
722                    info.has_children,
723                    info.last
724                ))
725                .collect_vec(),
726            vec![
727                (0, 0, 0, false, false),
728                (1, 1, 1, false, false),
729                (2, 2, 2, true, false),
730                (3, 5, 3, true, false),
731                (30, 6, 4, false, false),
732                (31, 7, 5, false, false),
733                (4, 8, 6, false, false),
734                (5, 9, 7, false, true),
735            ]
736        );
737    }
738
739    #[test]
740    fn test_insert_item_before_first() {
741        let mut tree = test_tree();
742        tree.insert_item(
743            DisplayedItemRef(0xff),
744            TargetPosition {
745                before: ItemIndex(0),
746                level: 0,
747            },
748        )
749        .expect("insert_item must succeed");
750        assert_eq!(
751            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
752            vec![0xff, 0, 1, 2, 20, 200, 3, 30, 31, 4, 5]
753        );
754        assert_eq!(tree.items[0].level, 0);
755        assert!(!tree.items[0].selected);
756        assert!(tree.items[0].unfolded);
757    }
758
759    #[test]
760    /// Test that inserting an element "after" the last element of a subtree
761    /// does insert into the subtree, after said element
762    fn test_insert_item_after_into_subtree() {
763        let mut tree = test_tree();
764        tree.insert_item(
765            DisplayedItemRef(0xff),
766            TargetPosition {
767                before: ItemIndex(8),
768                level: 1,
769            },
770        )
771        .expect("insert_item must succeed");
772        assert_eq!(
773            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
774            vec![0, 1, 2, 20, 200, 3, 30, 31, 0xff, 4, 5]
775        );
776        assert_eq!(tree.items[7].level, 1);
777        assert!(!tree.items[7].selected);
778        assert!(tree.items[7].unfolded);
779    }
780
781    #[test]
782    fn test_insert_item_into() {
783        let mut tree = test_tree();
784        tree.insert_item(
785            DisplayedItemRef(0xff),
786            TargetPosition {
787                before: ItemIndex(7),
788                level: 2,
789            },
790        )
791        .expect("insert_item must succeed");
792        assert_eq!(
793            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
794            vec![0, 1, 2, 20, 200, 3, 30, 0xff, 31, 4, 5]
795        );
796        assert_eq!(tree.items[7].level, 2);
797        assert!(!tree.items[7].selected);
798        assert!(tree.items[7].unfolded);
799    }
800
801    #[test]
802    fn test_insert_item_end() {
803        let mut tree = test_tree();
804        tree.insert_item(
805            DisplayedItemRef(0xff),
806            TargetPosition {
807                before: ItemIndex(10),
808                level: 0,
809            },
810        )
811        .expect("insert_item must succeed");
812        assert_eq!(
813            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
814            vec![0, 1, 2, 20, 200, 3, 30, 31, 4, 5, 0xff]
815        );
816        assert_eq!(tree.items[10].level, 0);
817    }
818
819    #[test]
820    fn test_remove_recursive_no_children() {
821        let mut tree = test_tree();
822        let removed = tree.remove_recursive(ItemIndex(0));
823        assert_eq!(removed, vec![DisplayedItemRef(0)]);
824        assert_eq!(
825            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
826            vec![1, 2, 20, 200, 3, 30, 31, 4, 5]
827        );
828    }
829
830    #[test]
831    fn test_remove_recursive_with_children() {
832        let mut tree = test_tree();
833        let removed = tree.remove_recursive(ItemIndex(2));
834        assert_eq!(
835            removed,
836            vec![
837                DisplayedItemRef(2),
838                DisplayedItemRef(20),
839                DisplayedItemRef(200)
840            ]
841        );
842        assert_eq!(
843            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
844            vec![0, 1, 3, 30, 31, 4, 5]
845        );
846    }
847
848    #[test]
849    fn test_remove_dissolve_with_children() {
850        let mut tree = test_tree();
851        let removed = tree.remove_dissolve(ItemIndex(5));
852        assert_eq!(removed, DisplayedItemRef(3));
853        assert_eq!(
854            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
855            vec![0, 1, 2, 20, 200, 30, 31, 4, 5]
856        );
857        assert_eq!(tree.items[5].level, 0);
858        assert_eq!(tree.items[6].level, 0);
859    }
860
861    #[test]
862    fn test_move_item_up_unfolded_group() {
863        let mut tree = build_tree(&[
864            (0, 0, true, false),
865            (1, 0, true, false),
866            (10, 1, true, false),
867            (2, 0, true, false),
868            (3, 0, true, false),
869        ]);
870        let new_idx = tree
871            .move_item(VisibleItemIndex(3), MoveDir::Up, |node| {
872                node.item_ref.0 == 1
873            })
874            .expect("move must succeed");
875        assert_eq!(new_idx.0, 3);
876        assert_eq!(tree.items[3].level, 1);
877        assert_eq!(
878            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
879            vec![0, 1, 10, 2, 3]
880        );
881
882        let new_idx = tree
883            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
884            .expect("move must succeed");
885        assert_eq!(new_idx.0, 2);
886        assert_eq!(tree.items[2].level, 1);
887        assert_eq!(
888            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
889            vec![0, 1, 2, 10, 3]
890        );
891
892        let new_idx = tree
893            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
894            .expect("move must succeed");
895        assert_eq!(new_idx.0, 1);
896        assert_eq!(tree.items[1].level, 0);
897        assert_eq!(
898            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
899            vec![0, 2, 1, 10, 3]
900        );
901
902        let new_idx = tree
903            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
904            .expect("move must succeed");
905        assert_eq!(new_idx.0, 0);
906        assert_eq!(tree.items[0].level, 0);
907        assert_eq!(
908            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
909            vec![2, 0, 1, 10, 3]
910        );
911
912        let new_idx = tree
913            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
914            .expect("move must succeed");
915        assert_eq!(new_idx.0, 0);
916        assert_eq!(tree.items[0].level, 0);
917        assert_eq!(
918            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
919            vec![2, 0, 1, 10, 3]
920        );
921    }
922
923    #[test]
924    fn test_move_item_up_folded_group() {
925        let mut tree = build_tree(&[
926            (0, 0, true, false),
927            (1, 0, false, false),
928            (10, 1, true, false),
929            (11, 1, true, false),
930            (2, 0, true, false),
931            (3, 0, true, false),
932        ]);
933        let new_idx = tree
934            .move_item(VisibleItemIndex(2), MoveDir::Up, |node| {
935                node.item_ref.0 == 1
936            })
937            .expect("move must succeed");
938        assert_eq!(new_idx.0, 1);
939        assert_eq!(tree.items[1].level, 0);
940        assert_eq!(
941            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
942            vec![0, 2, 1, 10, 11, 3]
943        );
944
945        let new_idx = tree
946            .move_item(new_idx, MoveDir::Up, |node| node.item_ref.0 == 1)
947            .expect("move must succeed");
948        assert_eq!(new_idx.0, 0);
949        assert_eq!(tree.items[0].level, 0);
950        assert_eq!(
951            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
952            vec![2, 0, 1, 10, 11, 3]
953        );
954    }
955
956    #[test]
957    fn test_move_item_down_unfolded_group() {
958        let mut tree = build_tree(&[
959            (0, 0, true, false),
960            (1, 0, true, false),
961            (2, 0, true, false),
962            (20, 1, true, false),
963            (3, 0, true, false),
964        ]);
965        let new_idx = tree
966            .move_item(VisibleItemIndex(1), MoveDir::Down, |node| {
967                node.item_ref.0 == 2
968            })
969            .expect("move must succeed");
970        println!("{:?}", tree.items);
971        assert_eq!(new_idx.0, 2);
972        assert_eq!(tree.items[3].level, 1);
973        assert_eq!(
974            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
975            vec![0, 2, 1, 20, 3]
976        );
977
978        let new_idx = tree
979            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
980            .expect("move must succeed");
981        println!("{:?}", tree.items);
982        assert_eq!(new_idx.0, 3);
983        assert_eq!(tree.items[3].level, 1);
984        assert_eq!(
985            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
986            vec![0, 2, 20, 1, 3]
987        );
988
989        let new_idx = tree
990            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
991            .expect("move must succeed");
992        println!("{:?}", tree.items);
993        assert_eq!(new_idx.0, 3);
994        assert_eq!(tree.items[3].level, 0);
995        assert_eq!(
996            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
997            vec![0, 2, 20, 1, 3]
998        );
999
1000        let new_idx = tree
1001            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
1002            .expect("move must succeed");
1003        println!("{:?}", tree.items);
1004        assert_eq!(new_idx.0, 4);
1005        assert_eq!(tree.items[3].level, 0);
1006        assert_eq!(
1007            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1008            vec![0, 2, 20, 3, 1]
1009        );
1010
1011        let new_idx = tree
1012            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
1013            .expect("move must succeed");
1014        println!("{:?}", tree.items);
1015        assert_eq!(new_idx.0, 4);
1016        assert_eq!(tree.items[3].level, 0);
1017        assert_eq!(
1018            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1019            vec![0, 2, 20, 3, 1]
1020        );
1021    }
1022
1023    #[test]
1024    fn test_move_item_down_folded_group() {
1025        let mut tree = build_tree(&[
1026            (0, 0, true, false),
1027            (1, 0, true, false),
1028            (2, 0, false, false),
1029            (20, 1, true, false),
1030            (3, 0, true, false),
1031        ]);
1032        let new_idx = tree
1033            .move_item(VisibleItemIndex(1), MoveDir::Down, |node| {
1034                node.item_ref.0 == 2
1035            })
1036            .expect("move must succeed");
1037        println!("{:?}", tree.items);
1038        assert_eq!(new_idx.0, 2);
1039        assert_eq!(tree.items[3].level, 0);
1040        assert_eq!(
1041            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1042            vec![0, 2, 20, 1, 3]
1043        );
1044
1045        let new_idx = tree
1046            .move_item(new_idx, MoveDir::Down, |node| node.item_ref.0 == 2)
1047            .expect("move must succeed");
1048        println!("{:?}", tree.items);
1049        assert_eq!(new_idx.0, 3);
1050        assert_eq!(tree.items[3].level, 0);
1051        assert_eq!(
1052            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1053            vec![0, 2, 20, 3, 1]
1054        );
1055    }
1056
1057    #[test]
1058    fn test_move_items_single_to_start() {
1059        let mut tree = test_tree();
1060        tree.move_items(
1061            vec![ItemIndex(8)],
1062            TargetPosition {
1063                before: ItemIndex(0),
1064                level: 0,
1065            },
1066        )
1067        .expect("move_items must succeed");
1068        assert_eq!(
1069            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1070            vec![4, 0, 1, 2, 20, 200, 3, 30, 31, 5]
1071        );
1072        assert_eq!(tree.items[0].level, 0);
1073    }
1074
1075    #[test]
1076    fn test_move_items_single_to_end() {
1077        let mut tree = test_tree();
1078        tree.move_items(
1079            vec![ItemIndex(4)],
1080            TargetPosition {
1081                before: ItemIndex(10),
1082                level: 0,
1083            },
1084        )
1085        .expect("move_items must succeed");
1086        assert_eq!(
1087            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1088            vec![0, 1, 2, 20, 3, 30, 31, 4, 5, 200]
1089        );
1090        assert_eq!(tree.items[9].level, 0);
1091    }
1092
1093    #[test]
1094    fn test_move_items_multiple_connected() {
1095        let mut tree = test_tree();
1096        tree.move_items(
1097            vec![ItemIndex(8), ItemIndex(9)],
1098            TargetPosition {
1099                before: ItemIndex(1),
1100                level: 0,
1101            },
1102        )
1103        .expect("move_items must succeed");
1104        assert_eq!(
1105            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1106            vec![0, 4, 5, 1, 2, 20, 200, 3, 30, 31]
1107        );
1108        assert_eq!(tree.items[1].level, 0);
1109        assert_eq!(tree.items[2].level, 0);
1110    }
1111
1112    #[test]
1113    fn test_move_items_multiple_different_levels() {
1114        let mut tree = test_tree();
1115        tree.move_items(
1116            vec![ItemIndex(7), ItemIndex(8)],
1117            TargetPosition {
1118                before: ItemIndex(1),
1119                level: 0,
1120            },
1121        )
1122        .expect("move_items must succeed");
1123        assert_eq!(
1124            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1125            vec![0, 31, 4, 1, 2, 20, 200, 3, 30, 5]
1126        );
1127        assert_eq!(tree.items[1].level, 0);
1128        assert_eq!(tree.items[2].level, 0);
1129    }
1130
1131    #[test]
1132    fn test_move_items_multiple_unconnected() {
1133        let mut tree = test_tree();
1134        tree.move_items(
1135            vec![ItemIndex(1), ItemIndex(8)],
1136            TargetPosition {
1137                before: ItemIndex(5),
1138                level: 1,
1139            },
1140        )
1141        .expect("move_items must succeed");
1142        assert_eq!(
1143            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1144            vec![0, 2, 20, 200, 1, 4, 3, 30, 31, 5]
1145        );
1146        assert_eq!(tree.items[4].level, 1);
1147        assert_eq!(tree.items[5].level, 1);
1148    }
1149
1150    #[test]
1151    fn test_move_items_multiple_into() {
1152        let mut tree = test_tree();
1153        tree.move_items(
1154            vec![ItemIndex(1), ItemIndex(8)],
1155            TargetPosition {
1156                before: ItemIndex(4),
1157                level: 2,
1158            },
1159        )
1160        .expect("move_items must succeed");
1161        assert_eq!(
1162            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1163            vec![0, 2, 20, 1, 4, 200, 3, 30, 31, 5]
1164        );
1165        assert_eq!(tree.items[4].level, 2);
1166        assert_eq!(tree.items[5].level, 2);
1167    }
1168
1169    #[test]
1170    fn test_move_single_to_end() {
1171        let mut tree = build_tree(&[
1172            (0, 0, false, false),
1173            (1, 0, false, false),
1174            (2, 0, false, false),
1175        ]);
1176        tree.move_items(
1177            vec![ItemIndex(1)],
1178            TargetPosition {
1179                before: ItemIndex(3),
1180                level: 0,
1181            },
1182        )
1183        .expect("move_items must succeed");
1184        assert_eq!(
1185            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1186            vec![0, 2, 1]
1187        );
1188    }
1189
1190    #[test]
1191    fn test_move_items_before_self_same_depth_single() {
1192        let ref_tree = build_tree(&[
1193            (0, 0, false, false),
1194            (1, 0, false, false),
1195            (2, 0, false, false),
1196        ]);
1197        let mut tree = ref_tree.clone();
1198        tree.move_items(
1199            vec![ItemIndex(1)],
1200            TargetPosition {
1201                before: ItemIndex(1),
1202                level: 0,
1203            },
1204        )
1205        .expect("move_items must succeed");
1206        assert_eq!(tree.items, ref_tree.items);
1207    }
1208
1209    #[test]
1210    fn test_move_items_after_self_same_depth_single() {
1211        let ref_tree = build_tree(&[
1212            (0, 0, false, false),
1213            (1, 0, false, false),
1214            (2, 0, false, false),
1215        ]);
1216        let mut tree = ref_tree.clone();
1217        tree.move_items(
1218            vec![ItemIndex(1)],
1219            TargetPosition {
1220                before: ItemIndex(2),
1221                level: 0,
1222            },
1223        )
1224        .expect("move_items must succeed");
1225        assert_eq!(tree.items, ref_tree.items);
1226    }
1227    #[test]
1228    fn test_move_items_in_between_selected_same_depth() {
1229        let ref_tree = build_tree(&[
1230            (0, 0, false, false),
1231            (1, 0, false, false),
1232            (2, 0, false, false),
1233            (3, 0, false, false),
1234            (4, 0, false, false),
1235        ]);
1236        let mut tree = ref_tree.clone();
1237        tree.move_items(
1238            vec![ItemIndex(1), ItemIndex(2)],
1239            TargetPosition {
1240                before: ItemIndex(2),
1241                level: 0,
1242            },
1243        )
1244        .expect("move_items must succeed");
1245        assert_eq!(tree.items, ref_tree.items);
1246    }
1247
1248    #[test]
1249    /// Moving "after" a node w/o children moves nodes to the same level,
1250    /// so it's fine and natural that the node itself can be included in the selection
1251    fn test_move_items_before_self_same_depth() {
1252        let mut tree = test_tree();
1253        tree.move_items(
1254            vec![ItemIndex(0), ItemIndex(4), ItemIndex(9)],
1255            TargetPosition {
1256                before: ItemIndex(4),
1257                level: 2,
1258            },
1259        )
1260        .expect("move_items must succeed");
1261        assert_eq!(
1262            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1263            vec![1, 2, 20, 0, 200, 5, 3, 30, 31, 4]
1264        );
1265        assert_eq!(tree.items[3].level, 2);
1266        assert_eq!(tree.items[4].level, 2);
1267        assert_eq!(tree.items[5].level, 2);
1268    }
1269
1270    #[test]
1271    /// Moving "after" a node w/o children moves nodes to the same level,
1272    /// so it's fine and natural that the node itself can be included in the selection
1273    fn test_move_items_before_self_shallower() {
1274        let mut tree = test_tree();
1275        tree.move_items(
1276            vec![ItemIndex(0), ItemIndex(4), ItemIndex(9)],
1277            TargetPosition {
1278                before: ItemIndex(4),
1279                level: 1,
1280            },
1281        )
1282        .expect("move_items must succeed");
1283        assert_eq!(
1284            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1285            vec![1, 2, 20, 0, 200, 5, 3, 30, 31, 4]
1286        );
1287        assert_eq!(tree.items[3].level, 1);
1288        assert_eq!(tree.items[4].level, 1);
1289        assert_eq!(tree.items[5].level, 1);
1290    }
1291
1292    #[test]
1293    fn test_move_items_empty_list() {
1294        let mut tree = test_tree();
1295        tree.move_items(
1296            vec![],
1297            TargetPosition {
1298                before: ItemIndex(5),
1299                level: 0,
1300            },
1301        )
1302        .expect("move_items must succeed");
1303        assert_eq!(
1304            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1305            vec![0, 1, 2, 20, 200, 3, 30, 31, 4, 5]
1306        );
1307        assert_eq!(tree.items, test_tree().items);
1308    }
1309
1310    #[test]
1311    fn test_move_items_shared_subtree_no_overlap() {
1312        let mut tree = build_tree(&[
1313            (0, 0, true, false),
1314            (10, 1, false, false),
1315            (11, 1, false, false),
1316            (12, 1, false, false),
1317            (13, 1, false, false),
1318        ]);
1319        tree.move_items(
1320            vec![ItemIndex(2), ItemIndex(4)],
1321            TargetPosition {
1322                before: ItemIndex(4),
1323                level: 2,
1324            },
1325        )
1326        .expect("move_items must succeed");
1327        assert_eq!(
1328            tree.items.iter().map(|x| x.item_ref.0).collect_vec(),
1329            vec![0, 10, 12, 11, 13]
1330        );
1331    }
1332
1333    #[test]
1334    /// An element can't be the sub-element of itself, so we must catch that
1335    fn test_move_items_reject_into_self() {
1336        let mut tree = test_tree();
1337        let result = tree.move_items(
1338            vec![ItemIndex(2)],
1339            TargetPosition {
1340                before: ItemIndex(3),
1341                level: 1,
1342            },
1343        );
1344        assert_eq!(result, Err(MoveError::CircularMove));
1345        assert_eq!(tree.items, test_tree().items);
1346    }
1347
1348    #[test]
1349    /// An element can't be the sub-element of itself, even not as the
1350    /// last element
1351    fn test_move_items_reject_after_self_into_subtree() {
1352        let mut tree = test_tree();
1353        let result = tree.move_items(
1354            vec![ItemIndex(0), ItemIndex(3), ItemIndex(9)],
1355            TargetPosition {
1356                before: ItemIndex(4),
1357                level: 2,
1358            },
1359        );
1360        assert_eq!(result, Err(MoveError::CircularMove));
1361        assert_eq!(tree.items, test_tree().items);
1362    }
1363
1364    #[test]
1365    /// Test that the subtree check before moving is done correctly.
1366    /// The valid subtree element 100 also being moved prevents simpler
1367    /// checks (like checking only the first pre-index) from passing incorrectly.
1368    fn test_move_items_reject_into_subtree_distant() {
1369        let reference = build_tree(&[
1370            (1, 0, true, false),
1371            (10, 1, true, false),
1372            (100, 2, true, false),
1373            (11, 3, true, false),
1374        ]);
1375        let mut tree = reference.clone();
1376        let result = tree.move_items(
1377            vec![ItemIndex(1), ItemIndex(2)],
1378            TargetPosition {
1379                before: ItemIndex(4),
1380                level: 2,
1381            },
1382        );
1383        assert_eq!(result, Err(MoveError::CircularMove));
1384        assert_eq!(tree.items, reference.items);
1385    }
1386
1387    #[test]
1388    fn test_valid_levels() {
1389        let tree = build_tree(&[
1390            /* vidx */
1391            /* 0 */ (0, 0, true, false),
1392            /* 1 */ (1, 0, true, false),
1393            /* 2 */ (2, 0, false, false),
1394            /* - */ (20, 1, true, false),
1395            /* 3 */ (3, 0, true, false),
1396            /* 4 */ (30, 1, true, false),
1397            /* 5 */ (300, 2, true, false),
1398            /* 6 */ (4, 0, true, false),
1399            /* 7 */ (40, 1, true, false),
1400            /* 8 */ (400, 2, true, false),
1401            /* 9 */ (41, 1, true, false),
1402            /* 10 */ (410, 2, true, false),
1403        ]);
1404
1405        // To insert before the first element we can't indent,
1406        // regardless of what comes after
1407        assert_eq!(
1408            tree.valid_levels_visible(VisibleItemIndex(0), |_| false),
1409            0..1
1410        );
1411        assert_eq!(
1412            tree.valid_levels_visible(VisibleItemIndex(0), |_| true),
1413            0..1
1414        );
1415
1416        // if flat we don't allow indent, except if the app logic allows it
1417        assert_eq!(
1418            tree.valid_levels_visible(VisibleItemIndex(1), |_| false),
1419            0..1
1420        );
1421        assert_eq!(
1422            tree.valid_levels_visible(VisibleItemIndex(1), |_| true),
1423            0..2
1424        );
1425
1426        // invisible item must be ignored, do not move into (and not "loose" signal)
1427        assert_eq!(
1428            tree.valid_levels_visible(VisibleItemIndex(3), |_| false),
1429            0..1
1430        );
1431        assert_eq!(
1432            tree.valid_levels_visible(VisibleItemIndex(3), |_| true),
1433            0..1
1434        );
1435
1436        // if we are past a full "cliff" allow to insert all along to the root
1437        assert_eq!(
1438            tree.valid_levels_visible(VisibleItemIndex(6), |_| false),
1439            0..3
1440        );
1441        assert_eq!(
1442            tree.valid_levels_visible(VisibleItemIndex(6), |_| true),
1443            0..4
1444        );
1445
1446        // if the next item is indented then we don't allow to go to the root
1447        // otherwise the moved element would become the new root of some subtree
1448        assert_eq!(
1449            tree.valid_levels_visible(VisibleItemIndex(9), |_| false),
1450            1..3
1451        );
1452        assert_eq!(
1453            tree.valid_levels_visible(VisibleItemIndex(9), |_| true),
1454            1..4
1455        );
1456
1457        // past the end we can go back to the root
1458        assert_eq!(
1459            tree.valid_levels_visible(VisibleItemIndex(11), |_| false),
1460            0..3
1461        );
1462        assert_eq!(
1463            tree.valid_levels_visible(VisibleItemIndex(11), |_| true),
1464            0..4
1465        );
1466    }
1467}