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}