locmess 1.0.0

look at the mess that are your LOC
Documentation
use {
    crate::*,
    anyhow::*,
    git2::Repository,
    std::{
        cmp::Reverse,
        collections::HashMap,
        ffi::OsStr,
        path::PathBuf,
    },
};

pub struct FileFinder {
    root: PathBuf,
}

impl FileFinder {
    pub fn new(
        root: PathBuf,
    ) -> Self {
        Self { root }
    }
    pub fn source_files(self, mandatory_ext: Option<&str>) -> Result<Vec<PathBuf>> {
        if !self.root.is_dir() {
            return Ok(vec![self.root]);
        }
        let mut files = Vec::new();
        let mut dirs = Vec::new();
        let repo = Repository::discover(&self.root)?;
        dirs.push(self.root);
        while let Some(dir) = dirs.pop() {
            for entry in dir.read_dir()? {
                let path = entry?.path();
                if repo.is_path_ignored(&path)? {
                    continue;
                }
                if path.is_dir() {
                    dirs.push(path);
                } else {
                    if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
                        if let Some(mandatory_ext) = mandatory_ext {
                            if ext == mandatory_ext {
                                files.push(path);
                            }
                        } else if !is_known_binary(ext) {
                            files.push(path);
                        }
                    }
                }
            }
        }
        Ok(files)
    }
    pub fn main_type_files(self) -> Result<Vec<PathBuf>> {
        let all_files = self.source_files(None)?;
        let mut map_by_types: HashMap<&OsStr, usize> = HashMap::new();
        for path in &all_files {
            if let Some(ext) = path.extension() {
                *map_by_types.entry(ext).or_default() += 1;
            }
        }
        let mut arr_by_types: Vec<(&OsStr, usize)> = map_by_types
            .drain()
            .collect();
        if arr_by_types.is_empty() {
            bail!("no suitable source file found");
        }
        arr_by_types.sort_by_key(|(_, count)| Reverse(*count));
        let chosen_ext = arr_by_types[0].0;
        print!("Files per type:");
        for e in &arr_by_types {
            print!(" {}:{} ", e.0.to_string_lossy(), e.1);
        }
        println!();
        println!(
            "-> choosing {} (use `-t` to choose another file type)",
            chosen_ext.to_string_lossy(),
        );
        Ok(
            all_files
                .iter()
                .filter(|path| path.extension()==Some(chosen_ext))
                .cloned()
                .collect()
        )
    }
}