fm/modes/display/
tree.rs

1use std::borrow::Borrow;
2use std::cmp::min;
3use std::collections::HashMap;
4use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use anyhow::{Context, Result};
8
9use crate::common::{filename_from_path, has_last_modification_happened_less_than};
10use crate::impl_index_to_index;
11use crate::modes::{
12    files_collection, ContentWindow, FileInfo, FilterKind, Flagged, Icon, SortKind, ToPath, Users,
13};
14
15/// An element of a tree.
16/// It's a file/directory, some optional children.
17/// A Node knows if it's folded or selected.
18#[derive(Debug, Clone)]
19pub struct Node {
20    path: Arc<Path>,
21    prev: Arc<Path>,
22    next: Arc<Path>,
23    index: usize,
24    children: Option<Vec<Arc<Path>>>,
25    folded: bool,
26    selected: bool,
27    reachable: bool,
28}
29
30impl Node {
31    /// Creates a new Node from a path and its children.
32    /// By default it's not selected nor folded.
33    fn new(path: &Path, children: Option<Vec<Arc<Path>>>, prev: &Path, index: usize) -> Self {
34        Self {
35            path: Arc::from(path),
36            prev: Arc::from(prev),
37            next: Arc::from(Path::new("")),
38            index,
39            children,
40            folded: false,
41            selected: false,
42            reachable: true,
43        }
44    }
45
46    fn fold(&mut self) {
47        self.folded = true
48    }
49
50    fn unfold(&mut self) {
51        self.folded = false
52    }
53
54    fn select(&mut self) {
55        self.selected = true
56    }
57
58    fn unselect(&mut self) {
59        self.selected = false
60    }
61
62    /// Is the node selected ?
63    pub fn selected(&self) -> bool {
64        self.selected
65    }
66
67    /// The index of the node in displayed tree
68    pub fn index(&self) -> usize {
69        self.index
70    }
71
72    /// Path of this node
73    pub fn path(&self) -> &Path {
74        &self.path
75    }
76
77    #[inline]
78    fn have_children(self: &Node) -> bool {
79        !self.folded && self.children.is_some()
80    }
81}
82
83/// Describe a movement in a navigable structure
84pub trait Go {
85    fn go(&mut self, to: To);
86}
87
88/// Describes a direction for the next selected tree element.
89pub enum To<'a> {
90    Next,
91    Prev,
92    Root,
93    Last,
94    Parent,
95    NextSibling,
96    PreviousSibling,
97    Path(&'a Path),
98}
99
100impl Go for Tree {
101    /// Select another element from a tree.
102    fn go(&mut self, to: To) {
103        if self.is_empty() {
104            return;
105        }
106        match to {
107            To::Next => self.select_next(),
108            To::Prev => self.select_prev(),
109            To::Root => self.select_root(),
110            To::Last => self.select_last(),
111            To::Parent => self.select_parent(),
112            To::NextSibling => self.select_next_sibling(),
113            To::PreviousSibling => self.select_previous_sibling(),
114            To::Path(path) => self.select_path(path),
115        }
116    }
117}
118
119/// Trait allowing to measure the depth of something.
120trait Depth {
121    fn depth(&self) -> usize;
122}
123
124impl Depth for Arc<Path> {
125    /// Measure the number of components of a [`std::path::Path`].
126    /// For absolute paths, it's the number of folders plus one for / and one for the file itself.
127    #[inline]
128    fn depth(&self) -> usize {
129        self.components().collect::<Vec<_>>().len()
130    }
131}
132
133pub struct TreeBuilder<'a> {
134    root_path: Arc<Path>,
135    users: &'a Users,
136    filter_kind: &'a FilterKind,
137    max_depth: usize,
138    show_hidden: bool,
139    sort_kind: SortKind,
140}
141
142impl<'a> TreeBuilder<'a> {
143    const DEFAULT_DEPTH: usize = 5;
144    const DEFAULT_FILTER: FilterKind = FilterKind::All;
145    const DEFAULT_HIDDEN: bool = false;
146    const DEFAULT_SORT: SortKind = SortKind::tree_default();
147
148    pub fn new(root_path: Arc<Path>, users: &'a Users) -> Self {
149        let filter_kind = &Self::DEFAULT_FILTER;
150        let max_depth = Self::DEFAULT_DEPTH;
151        let show_hidden = Self::DEFAULT_HIDDEN;
152        let sort_kind = Self::DEFAULT_SORT;
153        Self {
154            root_path,
155            users,
156            filter_kind,
157            max_depth,
158            show_hidden,
159            sort_kind,
160        }
161    }
162
163    pub fn with_filter_kind(mut self, filter_kind: &'a FilterKind) -> Self {
164        self.filter_kind = filter_kind;
165        self
166    }
167
168    pub fn with_max_depth(mut self, max_depth: usize) -> Self {
169        self.max_depth = max_depth;
170        self
171    }
172
173    pub fn with_hidden(mut self, show_hidden: bool) -> Self {
174        self.show_hidden = show_hidden;
175        self
176    }
177
178    pub fn with_sort_kind(mut self, sort_kind: SortKind) -> Self {
179        self.sort_kind = sort_kind;
180        self
181    }
182
183    pub fn build(self) -> Tree {
184        let nodes = NodesBuilder::new(
185            &self.root_path,
186            self.max_depth,
187            self.sort_kind,
188            self.users,
189            self.show_hidden,
190            self.filter_kind,
191        )
192        .build();
193        let displayable_lines = TreeLinesBuilder::new(&nodes, &self.root_path).build();
194
195        Tree {
196            selected: self.root_path.clone(),
197            root_path: self.root_path,
198            nodes,
199            displayable_lines,
200        }
201    }
202}
203
204/// A builder of [`Tree`] nodes.
205pub struct NodesBuilder<'a> {
206    root_path: &'a Arc<Path>,
207    max_depth: usize,
208    sort_kind: SortKind,
209    users: &'a Users,
210    show_hidden: bool,
211    filter_kind: &'a FilterKind,
212    root_depth: usize,
213}
214
215impl<'a> NodesBuilder<'a> {
216    fn new(
217        root_path: &'a Arc<Path>,
218        max_depth: usize,
219        sort_kind: SortKind,
220        users: &'a Users,
221        show_hidden: bool,
222        filter_kind: &'a FilterKind,
223    ) -> Self {
224        let root_depth = root_path.depth();
225        Self {
226            root_path,
227            max_depth,
228            sort_kind,
229            users,
230            show_hidden,
231            filter_kind,
232            root_depth,
233        }
234    }
235
236    #[inline]
237    fn build(self) -> HashMap<Arc<Path>, Node> {
238        let mut stack = vec![self.root_path.to_owned()];
239        let mut nodes = HashMap::new();
240        let mut last_path = self.root_path.to_owned();
241        let mut index = 0;
242
243        while let Some(current_path) = stack.pop() {
244            let current_depth = current_path.depth();
245            if self.current_is_too_deep(current_depth) {
246                continue;
247            }
248            let children = if self.node_may_have_children(current_depth, &current_path) {
249                self.create_children(&mut stack, &current_path)
250            } else {
251                None
252            };
253            let current_node = Node::new(&current_path, children, &last_path, index);
254            self.set_next_for_last(&mut nodes, &current_path, &last_path);
255            last_path = current_path.clone();
256            nodes.insert(current_path.clone(), current_node);
257            index += 1;
258        }
259        self.set_prev_for_root(&mut nodes, last_path);
260        nodes
261    }
262
263    fn current_is_too_deep(&self, current_depth: usize) -> bool {
264        current_depth >= self.max_depth + self.root_depth
265    }
266
267    fn node_may_have_children(&self, current_depth: usize, current_path: &Path) -> bool {
268        self.is_not_too_deep_for_children(current_depth)
269            && current_path.is_dir()
270            && !current_path.is_symlink()
271    }
272
273    fn is_not_too_deep_for_children(&self, current_depth: usize) -> bool {
274        self.root_depth + self.max_depth > 1 + current_depth
275    }
276
277    #[inline]
278    fn set_prev_for_root(&self, nodes: &mut HashMap<Arc<Path>, Node>, last_path: Arc<Path>) {
279        let Some(root_node) = nodes.get_mut(self.root_path) else {
280            unreachable!("root_path should be in nodes");
281        };
282        root_node.prev = last_path;
283        root_node.select();
284    }
285
286    #[inline]
287    fn set_next_for_last(
288        &self,
289        nodes: &mut HashMap<Arc<Path>, Node>,
290        current_path: &Path,
291        last_path: &Path,
292    ) {
293        if let Some(last_node) = nodes.get_mut(last_path) {
294            last_node.next = Arc::from(current_path);
295        };
296    }
297
298    #[inline]
299    fn create_children(
300        &self,
301        stack: &mut Vec<Arc<Path>>,
302        current_path: &Path,
303    ) -> Option<Vec<Arc<Path>>> {
304        if let Some(mut files) = files_collection(
305            current_path,
306            self.users,
307            self.show_hidden,
308            self.filter_kind,
309            true,
310        ) {
311            self.sort_kind.sort(&mut files);
312            let children = Self::make_children_and_stack_them(stack, &files);
313            if !children.is_empty() {
314                return Some(children);
315            }
316        }
317        None
318    }
319
320    #[inline]
321    fn make_children_and_stack_them(
322        stack: &mut Vec<Arc<Path>>,
323        files: &[FileInfo],
324    ) -> Vec<Arc<Path>> {
325        files
326            .iter()
327            .map(|fileinfo| fileinfo.path.clone())
328            .inspect(|path| stack.push(path.clone()))
329            .collect()
330    }
331}
332
333#[inline]
334fn first_prefix(prefix: &str) -> String {
335    let mut prefix = prefix.to_string();
336    prefix.push(' ');
337    prefix = prefix.replace("└──", "  ");
338    prefix = prefix.replace("├──", "│ ");
339    prefix.push_str("└──");
340    prefix
341}
342
343#[inline]
344fn other_prefix(prefix: &str) -> String {
345    let mut prefix = prefix.to_string();
346    prefix.push(' ');
347    prefix = prefix.replace("└──", "  ");
348    prefix = prefix.replace("├──", "│ ");
349    prefix.push_str("├──");
350    prefix
351}
352
353#[inline]
354fn filename_format(current_path: &Path, folded: bool, with_icon: bool) -> String {
355    let icon = if with_icon { current_path.icon() } else { "" };
356    let filename = filename_from_path(current_path).unwrap_or_default();
357    if current_path.is_dir() && !current_path.is_symlink() {
358        let fold_symbol = if folded { "▸" } else { "▾" };
359        format!("{fold_symbol} {icon}{filename}")
360    } else {
361        format!("{icon}{filename}")
362    }
363}
364
365struct TreeLinesBuilder<'a> {
366    nodes: &'a HashMap<Arc<Path>, Node>,
367    root_path: &'a Arc<Path>,
368}
369
370impl<'a> TreeLinesBuilder<'a> {
371    fn new(nodes: &'a HashMap<Arc<Path>, Node>, root_path: &'a Arc<Path>) -> Self {
372        Self { nodes, root_path }
373    }
374
375    /// Create a displayable content from the tree.
376    /// Returns 2 informations :
377    /// - the index of the selected node into this content.
378    ///      It's usefull to know where the user clicked
379    /// - a vector of `TreeLineMaker` which holds every information
380    ///     needed to display the tree.
381    ///     We try to keep as much reference as possible and generate
382    ///     the information lazyly, avoiding as much useless calcuations
383    ///     as possible.
384    ///     The metadata information (permissions, modified time etc.) must be
385    ///     calculated immediatly, therefore for every node, since it requires
386    ///     an access to the user list.
387    ///     The prefix (straight lines displaying targets) must also be calcuated immediatly.
388    ///     Name format is calculated on the fly.
389    fn build(self) -> TreeLines {
390        let mut stack = vec![("".to_owned(), self.root_path.clone())];
391        let mut lines = vec![];
392        let mut index = 0;
393
394        while let Some((prefix, path)) = stack.pop() {
395            let Some(node) = self.nodes.get(&path) else {
396                continue;
397            };
398
399            if node.selected {
400                index = lines.len();
401            }
402
403            lines.push(TLine::new(&prefix, node, &path));
404
405            if node.have_children() {
406                Self::stack_children(&mut stack, prefix, node);
407            }
408        }
409        TreeLines::new(lines, index)
410    }
411
412    #[inline]
413    fn stack_children(stack: &mut Vec<(String, Arc<Path>)>, prefix: String, current_node: &Node) {
414        let first_prefix = first_prefix(&prefix);
415        let other_prefix = other_prefix(&prefix);
416
417        let Some(children) = &current_node.children else {
418            return;
419        };
420        let mut children = children.iter();
421        let Some(first_leaf) = children.next() else {
422            return;
423        };
424        stack.push((first_prefix, first_leaf.clone()));
425
426        for leaf in children {
427            stack.push((other_prefix.clone(), leaf.clone()));
428        }
429    }
430}
431
432/// A vector of displayable lines used to draw a tree content.
433/// We use the index to follow the user movements in the tree.
434#[derive(Clone, Debug, Default)]
435pub struct TreeLines {
436    pub content: Vec<TLine>,
437    index: usize,
438}
439
440impl TreeLines {
441    fn new(content: Vec<TLine>, index: usize) -> Self {
442        Self { content, index }
443    }
444
445    pub fn content(&self) -> &Vec<TLine> {
446        &self.content
447    }
448
449    /// Index of the currently selected file.
450    pub fn index(&self) -> usize {
451        self.index
452    }
453
454    /// A reference to the displayable lines.
455    pub fn lines(&self) -> &Vec<TLine> {
456        &self.content
457    }
458
459    fn find_by_path(&self, path: &Path) -> Option<usize> {
460        self.content.iter().position(|tlm| tlm.path() == path)
461    }
462
463    fn unselect(&mut self) {
464        if !self.content.is_empty() {
465            self.content[self.index].unselect()
466        }
467    }
468
469    fn select(&mut self, index: usize) {
470        if !self.content.is_empty() {
471            self.index = index;
472            self.content[self.index].select()
473        }
474    }
475
476    fn selected_is_last(&self) -> bool {
477        self.index + 1 == self.content.len()
478    }
479}
480
481impl_index_to_index!(TLine, TreeLines);
482
483/// Holds a few references used to display a tree line
484/// Only the metadata info is hold.
485#[derive(Clone, Debug)]
486pub struct TLine {
487    folded: bool,
488    prefix: Arc<str>,
489    pub path: Arc<Path>,
490    pub is_selected: bool,
491}
492
493impl TLine {
494    /// Uses references to fileinfo, prefix, node & path to create an instance.
495    fn new(prefix: &str, node: &Node, path: &Path) -> Self {
496        // required for some edge cases when opening the tree while "." is the selected file
497        let is_selected = node.selected();
498        let prefix = Arc::from(prefix);
499        let path = Arc::from(path);
500        let folded = node.folded;
501
502        Self {
503            folded,
504            prefix,
505            path,
506            is_selected,
507        }
508    }
509
510    /// Formated filename
511    pub fn filename(&self, with_icon: bool) -> String {
512        filename_format(&self.path, self.folded, with_icon)
513    }
514
515    /// Vertical bar displayed before the filename to show
516    /// the adress of the file
517    pub fn prefix(&self) -> &str {
518        self.prefix.borrow()
519    }
520
521    /// Path of the file
522    pub fn path(&self) -> &Path {
523        self.path.borrow()
524    }
525
526    /// Change the current effect to Empty, displaying
527    /// the file as not selected
528    pub fn unselect(&mut self) {
529        self.is_selected = false;
530    }
531
532    /// Change the current effect to `REVERSED`, displaying
533    /// the file as selected.
534    pub fn select(&mut self) {
535        self.is_selected = true;
536    }
537}
538
539impl ToPath for TLine {
540    fn to_path(&self) -> &Path {
541        &self.path
542    }
543}
544
545/// A FileSystem tree of nodes.
546/// Internally it's a wrapper around an `std::collections::HashMap<PathBuf, Node>`
547/// It also holds informations about the required height of the tree.
548#[derive(Debug, Clone)]
549pub struct Tree {
550    root_path: Arc<Path>,
551    selected: Arc<Path>,
552    nodes: HashMap<Arc<Path>, Node>,
553    displayable_lines: TreeLines,
554}
555
556impl Default for Tree {
557    fn default() -> Self {
558        Self {
559            root_path: Arc::from(Path::new("")),
560            selected: Arc::from(Path::new("")),
561            nodes: HashMap::new(),
562            displayable_lines: TreeLines::default(),
563        }
564    }
565}
566
567impl Tree {
568    /// Root path of the tree.
569    pub fn root_path(&self) -> &Path {
570        self.root_path.borrow()
571    }
572
573    /// Selected path
574    pub fn selected_path(&self) -> &Path {
575        self.selected.borrow()
576    }
577
578    pub fn selected_node_or_parent(&self) -> Result<&Node> {
579        if let Some(node) = self.selected_node() {
580            if node.path().exists() {
581                return Ok(node);
582            }
583            while let Some(parent_path) = node.path().parent() {
584                if let Some(parent_node) = self.nodes.get(parent_path) {
585                    if parent_node.path().exists() {
586                        return Ok(parent_node);
587                    }
588                }
589            }
590        };
591        self.nodes
592            .get(&self.root_path)
593            .context("root path should have a node")
594    }
595
596    /// Selected node
597    pub fn selected_node(&self) -> Option<&Node> {
598        self.nodes.get(&self.selected)
599    }
600
601    /// The folder containing the selected node.
602    /// Itself if selected is a directory.
603    pub fn directory_of_selected(&self) -> Option<&Path> {
604        if self.selected.is_dir() && !self.selected.is_symlink() {
605            Some(self.selected.borrow())
606        } else {
607            self.selected.parent()
608        }
609    }
610
611    /// Relative path of selected from rootpath.
612    pub fn selected_path_relative_to_root(&self) -> Result<&Path> {
613        Ok(self.selected.strip_prefix(&self.root_path)?)
614    }
615
616    /// Number of nodes
617    pub fn len(&self) -> usize {
618        self.nodes.len()
619    }
620
621    pub fn display_len(&self) -> usize {
622        self.displayable().lines().len()
623    }
624
625    /// True if there's no node.
626    pub fn is_empty(&self) -> bool {
627        self.nodes.is_empty()
628    }
629
630    /// True if selected is root.
631    pub fn is_on_root(&self) -> bool {
632        self.selected == self.root_path
633    }
634
635    /// True if selected is the last file
636    fn is_on_last(&self) -> bool {
637        self.find_next_path() == self.root_path
638    }
639
640    /// True if the node has a parent which is in `self.nodes` and is folded.
641    /// This hacky and inefficient solution is necessary to know if we can select
642    /// this node in `select_prev` `select_next`.
643    /// It will construct all parent path from `/` to `node.path` except for the last one.
644    fn node_has_parent_folded(&self, node: &Node) -> bool {
645        let node_path = node.path();
646        let mut current_path = PathBuf::from("/");
647        for part in node_path.components() {
648            current_path = current_path.join(part.as_os_str());
649            if current_path == node_path {
650                continue;
651            }
652            if let Some(current_node) = self.nodes.get(current_path.as_path()) {
653                if current_node.folded {
654                    return true;
655                }
656            }
657        }
658        false
659    }
660
661    /// Select next sibling or the next sibling of the parent
662    fn select_next(&mut self) {
663        let next_path = self.find_next_path();
664        self.select_path(&next_path);
665        drop(next_path);
666    }
667
668    fn find_next_path(&self) -> Arc<Path> {
669        let mut current_path: Arc<Path> = self.selected.clone();
670        loop {
671            if let Some(current_node) = self.nodes.get(&current_path) {
672                let next_path = &current_node.next;
673                let Some(next_node) = self.nodes.get(next_path) else {
674                    return self.root_path.clone();
675                };
676                if next_node.reachable && !self.node_has_parent_folded(next_node) {
677                    return next_path.to_owned();
678                }
679                current_path = next_path.clone();
680            }
681        }
682    }
683
684    /// Select previous sibling or the parent
685    fn select_prev(&mut self) {
686        let previous_path = self.find_prev_path();
687        self.select_path(&previous_path);
688    }
689
690    fn find_prev_path(&self) -> Arc<Path> {
691        let mut current_path = self.selected.to_owned();
692        loop {
693            if let Some(current_node) = self.nodes.get(&current_path) {
694                let prev_path = &current_node.prev;
695                let Some(prev_node) = self.nodes.get(prev_path) else {
696                    unreachable!("");
697                };
698                if prev_node.reachable && !self.node_has_parent_folded(prev_node) {
699                    return prev_path.to_owned();
700                }
701                current_path = prev_path.to_owned();
702            }
703        }
704    }
705
706    pub fn page_up(&mut self) {
707        for _ in 1..10 {
708            if self.is_on_root() {
709                break;
710            }
711            self.go(To::Prev);
712        }
713    }
714
715    pub fn page_down(&mut self) {
716        for _ in 1..10 {
717            if self.is_on_last() {
718                break;
719            }
720            self.go(To::Next);
721        }
722    }
723
724    fn select_root(&mut self) {
725        let root_path = self.root_path.to_owned();
726        self.select_path(&root_path);
727    }
728
729    fn select_last(&mut self) {
730        self.select_root();
731        self.select_prev();
732    }
733
734    fn select_parent(&mut self) {
735        if let Some(parent_path) = self.selected.parent() {
736            self.select_path(parent_path.to_owned().as_path());
737        }
738    }
739
740    fn find_siblings(&self) -> &Option<Vec<Arc<Path>>> {
741        let Some(parent_path) = self.selected.parent() else {
742            return &None;
743        };
744        let Some(parent_node) = self.nodes.get(parent_path) else {
745            return &None;
746        };
747        &parent_node.children
748    }
749
750    fn select_next_sibling(&mut self) {
751        let Some(children) = self.find_siblings() else {
752            self.select_next();
753            return;
754        };
755        let Some(curr_index) = children.iter().position(|p| p == &self.selected) else {
756            return;
757        };
758        let next_index = if curr_index > 0 {
759            curr_index - 1
760        } else {
761            children.len().checked_sub(1).unwrap_or_default()
762        };
763        let sibling_path = children[next_index].clone();
764        self.select_path(&sibling_path);
765    }
766
767    fn select_previous_sibling(&mut self) {
768        let Some(children) = self.find_siblings() else {
769            self.select_prev();
770            return;
771        };
772        let Some(curr_index) = children.iter().position(|p| p == &self.selected) else {
773            return;
774        };
775        let next_index = (curr_index + 1) % children.len();
776        let sibling_path = children[next_index].clone();
777        self.select_path(&sibling_path);
778    }
779
780    fn select_path(&mut self, dest_path: &Path) {
781        if Arc::from(dest_path) == self.selected {
782            return;
783        }
784        let Some(dest_node) = self.nodes.get_mut(dest_path) else {
785            return;
786        };
787        dest_node.select();
788        let Some(selected_node) = self.nodes.get_mut(&self.selected) else {
789            unreachable!("current_node should be in nodes");
790        };
791        selected_node.unselect();
792        self.selected = Arc::from(dest_path);
793        self.displayable_lines.unselect();
794        if let Some(index) = self.displayable_lines.find_by_path(dest_path) {
795            self.displayable_lines.select(index);
796        }
797    }
798
799    /// Fold selected node
800    pub fn toggle_fold(&mut self) {
801        if let Some(node) = self.nodes.get_mut(&self.selected) {
802            if node.folded {
803                node.unfold();
804                self.make_children_reachable()
805            } else {
806                node.fold();
807                self.make_children_unreachable()
808            }
809        }
810        self.remake_displayable();
811    }
812    fn children_of_selected(&self) -> Option<&Vec<Arc<Path>>> {
813        self.nodes.get(&self.selected)?.children.as_ref()
814    }
815
816    fn make_children_reachable(&mut self) {
817        self.set_children_reachable(true)
818    }
819
820    fn make_children_unreachable(&mut self) {
821        self.set_children_reachable(false)
822    }
823
824    fn set_children_reachable(&mut self, reachable: bool) {
825        let Some(children) = self.children_of_selected() else {
826            return;
827        };
828        for child_path in children.to_owned().iter() {
829            let Some(child_node) = self.nodes.get_mut(child_path) else {
830                continue;
831            };
832            child_node.reachable = reachable;
833        }
834    }
835
836    /// Fold all node from root to end
837    pub fn fold_all(&mut self) {
838        for (_, node) in self.nodes.iter_mut() {
839            node.fold()
840        }
841        self.select_root();
842        self.remake_displayable();
843    }
844
845    /// Unfold all node from root to end
846    pub fn unfold_all(&mut self) {
847        for (_, node) in self.nodes.iter_mut() {
848            node.unfold()
849        }
850        self.remake_displayable();
851    }
852
853    fn remake_displayable(&mut self) {
854        self.displayable_lines = TreeLinesBuilder::new(&self.nodes, &self.root_path).build();
855    }
856
857    pub fn displayable(&self) -> &TreeLines {
858        &self.displayable_lines
859    }
860
861    /// Vector of `Path` of nodes.
862    pub fn paths(&self) -> Vec<&Path> {
863        self.nodes.keys().map(|p| p.borrow()).collect()
864    }
865
866    pub fn flag_all(&self, flagged: &mut Flagged) {
867        self.nodes
868            .keys()
869            .for_each(|p| flagged.push(p.to_path_buf()))
870    }
871
872    /// True if any directory (not symlink to a directory)
873    /// has been modified less than 10 seconds ago.
874    #[inline]
875    pub fn has_modified_dirs(&self) -> bool {
876        self.nodes
877            .keys()
878            .filter(|path| path.is_dir() && !path.is_symlink())
879            .any(|path| has_last_modification_happened_less_than(path, 10).unwrap_or(false))
880    }
881
882    pub fn selected_is_last(&self) -> bool {
883        self.displayable_lines.selected_is_last()
884    }
885
886    pub fn path_from_index(&self, index: usize) -> Result<PathBuf> {
887        let displayable = self.displayable();
888        Ok(displayable
889            .lines()
890            .get(index)
891            .context("tree: no selected file")?
892            .path()
893            .to_owned())
894    }
895
896    pub fn lines_enum_skip_take(
897        &self,
898        window: &ContentWindow,
899    ) -> Take<Skip<Enumerate<Iter<TLine>>>> {
900        let lines = self.displayable().lines();
901        let length = lines.len();
902        lines
903            .iter()
904            .enumerate()
905            .skip(window.top)
906            .take(min(length, window.bottom + 1))
907    }
908}
909
910impl IndexToIndex<TLine> for Tree {
911    /// Iterate over line from current index to bottom then from top to current index.
912    ///
913    /// Useful when going to next match in search results
914    fn index_to_index(&self) -> Chain<Skip<Iter<TLine>>, Take<Iter<TLine>>> {
915        self.displayable().index_to_index()
916    }
917}