ls_tiny/lib.rs
1//! **ls-tiny** is a less functional `ls` command
2//! it is somewhat richer than when no argument to the ls command is specified. (Because it's a little colored.)
3
4#[macro_use]
5extern crate clap;
6use clap::{Arg, App};
7use colored::Colorize;
8use std::path::{Path, PathBuf};
9
10/// The Config structure has four fields
11/// * the path of the directory you want to look up
12/// * the number of directories
13/// * the number of files
14/// * the total number of them.
15pub struct Config {
16 /// directory name given by the first argument
17 search_dir: PathBuf,
18 /// Number of directories
19 dirs: u64,
20 /// Number of files
21 files: u64,
22 /// total entries
23 entries: u64
24}
25
26/// Define the initial value of the Config structure.
27impl Default for Config {
28 fn default() -> Self {
29 Self {
30 search_dir: PathBuf::new(),
31 dirs: 0,
32 files: 0,
33 entries: 0
34 }
35 }
36}
37
38
39impl Config {
40 /// parse the arguments.
41 /// If you want more information, such as methods, check out the following links
42 /// clap https://crates.io/crates/clap
43 fn parse_arguments<'a>() -> clap::ArgMatches<'a> {
44 App::new(crate_name!())
45 .version(crate_version!())
46 .author(crate_authors!())
47 .about(crate_description!())
48 .arg(Arg::with_name("PATH")
49 .help("Sets the directory")
50 .required(true)
51 .index(1)
52 )
53 .get_matches()
54 }
55
56 /// If an existing directory is specified, the Ok-wrapped Config structure is returned.
57 /// Assign the directory specified by the first argument to the search_dir field of the Config structure.
58 /// All other fields are assigned a 0.(call the default method)
59 ///
60 /// # Panics
61 /// An error is returned when the first argument is a file or a non-existent directory is specified.
62 pub fn new() -> Result<Config, String> {
63 let matches = Self::parse_arguments();
64 let mut search_dir = PathBuf::new();
65
66 if let Some(path) = matches.value_of("PATH") {
67 search_dir.push(path);
68 }
69
70 if search_dir.is_file() {
71 return Err(format!("error: sets the directory"));
72 }
73
74 if !search_dir.exists() {
75 return Err(format!("error: {} cannot find", search_dir.display()));
76 }
77
78 Ok( Config { search_dir, ..Config::default() } )
79 }
80
81 /// check the entries in the directory specified by the first argument.
82 /// If you want to know more about specifying colors, see the following links:
83 /// [colored](https://crates.io/crates/colored)
84 pub fn run(&mut self) {
85 for dir_entry in self.search_dir.read_dir().expect("cannot read dir") {
86
87 self.entries += 1;
88
89 if let Ok(entry) = dir_entry {
90 let entry_type = if entry.path().is_file() {
91 self.files += 1;
92 "file".green()
93 } else {
94 self.dirs += 1;
95 "dir ".cyan()
96 };
97
98 println!("{}: {} - {}", self.entries , entry_type , get_name(&entry.path()));
99 }
100 }
101
102 // let dir_name = get_name(self.search_dir.as_path()).magenta();
103 let dir_name = self.search_dir.as_path().to_str().unwrap().magenta();
104 let entries = self.entries.to_string().magenta();
105
106 println!("\ndir: {}, file: {}", self.dirs.to_string().cyan(), self.files.to_string().green());
107 println!("{} directory has {} entries.", dir_name, entries);
108 }
109}
110
111/// extracts only the name from the path
112fn get_name(path: &Path) -> &str {
113 path.file_name().unwrap().to_str().unwrap()
114}