1use anyhow::bail;
2use prodash::Progress;
3use std::ffi::OsString;
4use std::path::{Path, PathBuf};
5use std::sync::atomic::{AtomicBool, Ordering};
6
7pub mod render;
8pub use render::function::render;
9
10const FILENAME_LINE_COUNT: u32 = 1;
13
14pub struct DirContents {
15 pub parent_dir: PathBuf,
16 pub children_content: Vec<(PathBuf, String)>,
17}
18
19pub fn unicode_content(
20 search_path: &Path,
21 ignore_extensions: &[OsString],
22 mut progress: impl Progress,
23 should_interrupt: &AtomicBool,
24) -> anyhow::Result<(DirContents, usize)> {
25 let start = std::time::Instant::now();
26 progress.init(None, Some(prodash::unit::label("files")));
27 let mut content_progress = progress.add_child("content");
28 content_progress.init(
29 None,
30 Some(prodash::unit::dynamic_and_mode(
31 prodash::unit::Bytes,
32 prodash::unit::display::Mode::with_throughput(),
33 )),
34 );
35
36 let mut paths = Vec::new();
37 let mut ignored = 0;
38 for entry in ignore::Walk::new(search_path) {
39 if should_interrupt.load(Ordering::Relaxed) {
40 bail!("Cancelled by user")
41 }
42 progress.inc();
43 let entry = entry?;
44 let path = entry.path();
45 if !ignore_extensions.is_empty()
46 && path.extension().map_or(false, |ext| {
47 ignore_extensions.iter().any(|extension| ext == extension)
48 })
49 {
50 ignored += 1;
51 continue;
52 }
53 if let Ok(content) = std::fs::read_to_string(path) {
54 content_progress.inc_by(content.len());
55 paths.push((path.to_owned(), content));
56 }
57 }
58
59 progress.show_throughput(start);
60 content_progress.show_throughput(start);
61 Ok((
62 DirContents {
63 parent_dir: search_path.to_path_buf(),
64 children_content: paths,
65 },
66 ignored,
67 ))
68}