Skip to main content

tui_file_explorer/explorer/
builder.rs

1use super::*;
2
3// ── FileExplorerBuilder ───────────────────────────────────────────────────────
4
5/// Builder for [`FileExplorer`].
6///
7/// Obtain one via [`FileExplorer::builder`].
8///
9/// # Example
10///
11/// ```
12/// use tui_file_explorer::{FileExplorer, SortMode};
13///
14/// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
15///     .allow_extension("iso")
16///     .allow_extension("img")
17///     .show_hidden(false)
18///     .sort_mode(SortMode::SizeDesc)
19///     .build();
20/// ```
21#[derive(Debug)]
22pub struct FileExplorerBuilder {
23    initial_dir: PathBuf,
24    filesystem: crate::SharedFileSystem,
25    extension_filter: Vec<String>,
26    show_hidden: bool,
27    sort_mode: SortMode,
28    page_size: usize,
29    selection_mode: SelectionMode,
30    show_sizes: bool,
31    show_dir_sizes: bool,
32    keymap: Keymap,
33    show_git: bool,
34    async_loading: bool,
35}
36
37impl FileExplorerBuilder {
38    /// Create a builder rooted at `initial_dir`.
39    #[must_use]
40    pub fn new(initial_dir: PathBuf) -> Self {
41        Self {
42            initial_dir,
43            filesystem: crate::std_filesystem(),
44            extension_filter: Vec::new(),
45            show_hidden: false,
46            sort_mode: SortMode::default(),
47            page_size: PAGE_SIZE,
48            selection_mode: SelectionMode::default(),
49            show_sizes: true,
50            show_dir_sizes: true,
51            keymap: Keymap::default(),
52            show_git: false,
53            async_loading: false,
54        }
55    }
56
57    /// Use a custom filesystem backend.
58    #[must_use]
59    pub fn filesystem(mut self, filesystem: crate::SharedFileSystem) -> Self {
60        self.filesystem = filesystem;
61        self
62    }
63
64    /// Set the full extension filter list at once.
65    ///
66    /// Replaces any extensions added with [`allow_extension`](Self::allow_extension).
67    ///
68    /// ```
69    /// use tui_file_explorer::FileExplorer;
70    ///
71    /// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
72    ///     .extension_filter(vec!["iso".into(), "img".into()])
73    ///     .build();
74    /// ```
75    #[must_use]
76    pub fn extension_filter(mut self, filter: Vec<String>) -> Self {
77        self.extension_filter = filter;
78        self
79    }
80
81    /// Append a single allowed extension.
82    ///
83    /// Call multiple times to build up the filter:
84    ///
85    /// ```
86    /// use tui_file_explorer::FileExplorer;
87    ///
88    /// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
89    ///     .allow_extension("iso")
90    ///     .allow_extension("img")
91    ///     .build();
92    /// ```
93    #[must_use]
94    pub fn allow_extension(mut self, ext: impl Into<String>) -> Self {
95        self.extension_filter.push(ext.into());
96        self
97    }
98
99    /// Set whether hidden (dot-file) entries are shown on startup.
100    ///
101    /// ```
102    /// use tui_file_explorer::FileExplorer;
103    ///
104    /// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
105    ///     .show_hidden(true)
106    ///     .build();
107    /// ```
108    #[must_use]
109    pub fn show_hidden(mut self, show: bool) -> Self {
110        self.show_hidden = show;
111        self
112    }
113
114    /// Set whether file/folder sizes are shown on startup.
115    ///
116    /// Defaults to `true`. Set to `false` for the snappiest possible
117    /// browsing of huge directory trees, since it skips the recursive
118    /// directory-size walk entirely.
119    ///
120    /// ```
121    /// use tui_file_explorer::FileExplorer;
122    ///
123    /// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
124    ///     .show_sizes(false)
125    ///     .build();
126    /// ```
127    #[must_use]
128    pub fn show_sizes(mut self, show: bool) -> Self {
129        self.show_sizes = show;
130        self
131    }
132
133    /// Set whether directories show their recursive byte size on startup.
134    ///
135    /// Defaults to `true`. With `false`, files still show their size but
136    /// directories show a shallow item count and the (potentially slow)
137    /// recursive walk is skipped. Has no effect when
138    /// [`show_sizes`](Self::show_sizes) is `false`.
139    ///
140    /// ```
141    /// use tui_file_explorer::FileExplorer;
142    ///
143    /// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
144    ///     .show_dir_sizes(false)
145    ///     .build();
146    /// ```
147    #[must_use]
148    pub fn show_dir_sizes(mut self, show: bool) -> Self {
149        self.show_dir_sizes = show;
150        self
151    }
152
153    /// Read directories on a background thread (see
154    /// [`FileExplorer::async_loading`]). Off by default.
155    #[must_use]
156    pub fn async_loading(mut self, enabled: bool) -> Self {
157        self.async_loading = enabled;
158        self
159    }
160
161    /// Show a git change marker (`M`, `A`, `?`, …) next to changed entries.
162    ///
163    /// Off by default; runs `git status` on a background thread.
164    #[must_use]
165    pub fn show_git(mut self, show: bool) -> Self {
166        self.show_git = show;
167        self
168    }
169
170    /// Replace the key bindings (defaults to [`Keymap::default`]).
171    #[must_use]
172    pub fn keymap(mut self, keymap: Keymap) -> Self {
173        self.keymap = keymap;
174        self
175    }
176
177    /// Set the initial sort mode.
178    ///
179    /// ```
180    /// use tui_file_explorer::{FileExplorer, SortMode};
181    ///
182    /// let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
183    ///     .sort_mode(SortMode::SizeDesc)
184    ///     .build();
185    /// ```
186    #[must_use]
187    pub fn sort_mode(mut self, mode: SortMode) -> Self {
188        self.sort_mode = mode;
189        self
190    }
191
192    /// Configure which entry kinds can be confirmed as selections.
193    #[must_use]
194    pub fn selection_mode(mut self, mode: SelectionMode) -> Self {
195        self.selection_mode = mode;
196        self
197    }
198
199    /// Set the number of entries scrolled by Page Up / Page Down.
200    ///
201    /// Defaults to 10.
202    #[must_use]
203    pub fn page_size(mut self, size: usize) -> Self {
204        self.page_size = size;
205        self
206    }
207
208    /// Consume the builder and return a fully initialised [`FileExplorer`].
209    ///
210    /// Filesystem errors are retained as explorer status for backwards
211    /// compatibility. Use [`Self::try_build`] when the host needs typed errors.
212    #[must_use]
213    pub fn build(self) -> FileExplorer {
214        let mut explorer = self.build_unloaded();
215        explorer.reload();
216        explorer
217    }
218
219    /// Build an explorer and return an error when its initial directory cannot
220    /// be read.
221    pub fn try_build(self) -> Result<FileExplorer, ExplorerError> {
222        let mut explorer = self.build_unloaded();
223        explorer.try_reload()?;
224        Ok(explorer)
225    }
226
227    fn build_unloaded(self) -> FileExplorer {
228        FileExplorer {
229            current_dir: self.initial_dir,
230            filesystem: self.filesystem,
231            entries: Vec::new(),
232            cursor: 0,
233            scroll_offset: 0,
234            extension_filter: self.extension_filter,
235            show_hidden: self.show_hidden,
236            status: String::new(),
237            sort_mode: self.sort_mode,
238            page_size: self.page_size,
239            selection_mode: self.selection_mode,
240            search_query: String::new(),
241            search_active: false,
242            marked: HashSet::new(),
243            prompt: None,
244            keymap: self.keymap,
245            theme_name: String::new(),
246            editor_name: String::new(),
247            disk_usage: None,
248            bg: Default::default(),
249            show_git: self.show_git,
250            async_loading: self.async_loading,
251            git: None,
252            link_cache: std::collections::HashMap::new(),
253            dir_size_cache: std::collections::HashMap::new(),
254            show_sizes: self.show_sizes,
255            show_dir_sizes: self.show_dir_sizes,
256        }
257    }
258}