broot/tree/
tree_options.rs

1use {
2    super::Sort,
3    crate::{
4        cli::Args,
5        conf::Conf,
6        display::{
7            Cols,
8            DEFAULT_COLS,
9        },
10        errors::ConfError,
11        pattern::*,
12    },
13    clap::Parser,
14    lazy_regex::regex_is_match,
15    std::convert::TryFrom,
16};
17
18/// Options defining how the tree should be build and|or displayed
19#[derive(Debug, Clone)]
20pub struct TreeOptions {
21    pub show_selection_mark: bool, // whether to have a triangle left of selected line
22    pub show_hidden: bool,         // whether files whose name starts with a dot should be shown
23    pub only_folders: bool,        // whether to hide normal files and links
24    pub show_counts: bool,         // whether to show the number of files (> 1 only for dirs)
25    pub show_dates: bool,          // whether to show the last modified date
26    pub show_sizes: bool,          // whether to show sizes of files and dirs
27    pub max_depth: Option<u16>,    // the maximum directory depth to recurse to
28    pub show_git_file_info: bool,
29    pub show_device_id: bool,
30    pub show_root_fs: bool, // show information relative to the fs of the root
31    pub trim_root: bool,    // whether to cut out direct children of root
32    pub show_permissions: bool, // show classic rwx unix permissions (only on unix)
33    pub respect_git_ignore: bool, // hide files as requested by .gitignore ?
34    pub filter_by_git_status: bool, // only show files whose git status is not nul
35    pub pattern: InputPattern, // an optional filtering/scoring pattern
36    pub date_time_format: &'static str,
37    pub sort: Sort,
38    pub show_tree: bool,  // whether to show the tree
39    pub cols_order: Cols, // order of columns
40    pub show_matching_characters_on_path_searches: bool,
41}
42
43impl TreeOptions {
44    /// clone self but without the pattern (if any)
45    pub fn without_pattern(&self) -> Self {
46        TreeOptions {
47            show_selection_mark: self.show_selection_mark,
48            show_hidden: self.show_hidden,
49            only_folders: self.only_folders,
50            max_depth: self.max_depth,
51            show_counts: self.show_counts,
52            show_dates: self.show_dates,
53            show_sizes: self.show_sizes,
54            show_permissions: self.show_permissions,
55            respect_git_ignore: self.respect_git_ignore,
56            filter_by_git_status: self.filter_by_git_status,
57            show_git_file_info: self.show_git_file_info,
58            show_device_id: self.show_device_id,
59            show_root_fs: self.show_root_fs,
60            trim_root: self.trim_root,
61            pattern: InputPattern::none(),
62            date_time_format: self.date_time_format,
63            sort: self.sort,
64            show_tree: self.show_tree,
65            cols_order: self.cols_order,
66            show_matching_characters_on_path_searches: self
67                .show_matching_characters_on_path_searches,
68        }
69    }
70    /// counts must be computed, either for sorting or just for display
71    pub fn needs_counts(&self) -> bool {
72        self.show_counts || self.sort == Sort::Count
73    }
74    /// dates must be computed, either for sorting or just for display
75    pub fn needs_dates(&self) -> bool {
76        self.show_dates || self.sort == Sort::Date
77    }
78    /// sizes must be computed, either for sorting or just for display
79    pub fn needs_sizes(&self) -> bool {
80        self.show_sizes || self.sort == Sort::Size
81    }
82    pub fn needs_sum(&self) -> bool {
83        self.needs_counts() || self.needs_dates() || self.needs_sizes()
84    }
85    /// this method does not exist, you saw nothing
86    /// (at least don't call it other than with the config, once)
87    pub fn set_date_time_format(
88        &mut self,
89        format: String,
90    ) {
91        self.date_time_format = Box::leak(format.into_boxed_str());
92    }
93    /// change tree options according to configuration
94    /// (but not the default_flags part, which is handled separately)
95    pub fn apply_config(
96        &mut self,
97        config: &Conf,
98    ) -> Result<(), ConfError> {
99        if let Some(b) = config.show_selection_mark {
100            self.show_selection_mark = b;
101        }
102        if let Some(format) = &config.date_time_format {
103            self.set_date_time_format(format.clone());
104        }
105        if let Some(b) = config.show_matching_characters_on_path_searches {
106            self.show_matching_characters_on_path_searches = b;
107        }
108        self.cols_order = config
109            .cols_order
110            .as_ref()
111            .map(Cols::try_from)
112            .transpose()?
113            .unwrap_or(DEFAULT_COLS);
114        Ok(())
115    }
116    /// apply flags like "sdp"
117    pub fn apply_flags(
118        &mut self,
119        flags: &str,
120    ) -> Result<(), &'static str> {
121        if !regex_is_match!("^[a-zA-Z]+$", flags) {
122            return Err("Flags must be a sequence of letters");
123        }
124        let prefixed = format!("-{flags}");
125        let tokens = vec!["broot", &prefixed];
126        let args = Args::try_parse_from(tokens).map_err(|_| {
127            warn!("invalid flags: {:?}", flags);
128            "invalid flag (valid flags are -dDfFgGhHiIpPsSwWtT)"
129        })?;
130        self.apply_launch_args(&args);
131        Ok(())
132    }
133    /// change tree options according to broot launch arguments
134    pub fn apply_launch_args(
135        &mut self,
136        cli_args: &Args,
137    ) {
138        if cli_args.sizes {
139            self.show_sizes = true;
140            self.show_root_fs = true;
141        } else if cli_args.no_sizes {
142            self.show_sizes = false;
143        }
144        if cli_args.whale_spotting {
145            self.show_hidden = true;
146            self.respect_git_ignore = false;
147            self.sort = Sort::Size;
148            self.show_sizes = true;
149            self.show_root_fs = true;
150        }
151        if cli_args.no_whale_spotting {
152            self.show_hidden = false;
153            self.respect_git_ignore = true;
154            self.sort = Sort::None;
155            self.show_sizes = false;
156            self.show_root_fs = false;
157        }
158        if cli_args.only_folders {
159            self.only_folders = true;
160        } else if cli_args.no_only_folders {
161            self.only_folders = false;
162        }
163        if let Some(max_depth) = cli_args.max_depth {
164            self.max_depth = Some(max_depth);
165        }
166        if cli_args.git_status {
167            self.filter_by_git_status = true;
168            self.show_hidden = true;
169        }
170        if cli_args.hidden {
171            self.show_hidden = true;
172        } else if cli_args.no_hidden {
173            self.show_hidden = false;
174        }
175        if cli_args.dates {
176            self.show_dates = true;
177        } else if cli_args.no_dates {
178            self.show_dates = false;
179        }
180        if cli_args.permissions {
181            self.show_permissions = true;
182        } else if cli_args.no_permissions {
183            self.show_permissions = false;
184        }
185        if cli_args.show_root_fs {
186            self.show_root_fs = true;
187        }
188        if cli_args.git_ignored {
189            self.respect_git_ignore = false;
190        } else if cli_args.no_git_ignored {
191            self.respect_git_ignore = true;
192        }
193        if cli_args.show_git_info {
194            self.show_git_file_info = true;
195        } else if cli_args.no_show_git_info {
196            self.show_git_file_info = false;
197        }
198        if cli_args.sort_by_count {
199            self.sort = Sort::Count;
200            self.show_counts = true;
201        }
202        if cli_args.sort_by_date {
203            self.sort = Sort::Date;
204            self.show_dates = true;
205        }
206        if cli_args.sort_by_size {
207            self.sort = Sort::Size;
208            self.show_sizes = true;
209        }
210        if cli_args.tree {
211            self.show_tree = true;
212        } else if cli_args.no_tree {
213            self.show_tree = false;
214        }
215        if cli_args.sort_by_type_dirs_first || cli_args.sort_by_type {
216            self.sort = Sort::TypeDirsFirst;
217        }
218        if cli_args.sort_by_type_dirs_last {
219            self.sort = Sort::TypeDirsLast;
220        }
221        if cli_args.no_sort {
222            self.sort = Sort::None;
223        }
224        if cli_args.trim_root {
225            self.trim_root = true;
226        } else if cli_args.no_trim_root {
227            self.trim_root = false;
228        }
229    }
230}
231
232impl Default for TreeOptions {
233    fn default() -> Self {
234        Self {
235            show_selection_mark: false,
236            show_hidden: false,
237            only_folders: false,
238            max_depth: None,
239            show_counts: false,
240            show_dates: false,
241            show_sizes: false,
242            show_git_file_info: false,
243            show_device_id: false,
244            show_root_fs: false,
245            trim_root: false,
246            show_permissions: false,
247            respect_git_ignore: true,
248            filter_by_git_status: false,
249            pattern: InputPattern::none(),
250            date_time_format: "%Y/%m/%d %R",
251            sort: Sort::None,
252            show_tree: true,
253            cols_order: DEFAULT_COLS,
254            show_matching_characters_on_path_searches: true,
255        }
256    }
257}