1use std::{error::Error, fs};
2
3use comfy_table::{
4 modifiers::{UTF8_ROUND_CORNERS, UTF8_SOLID_INNER_BORDERS},
5 presets::UTF8_FULL,
6 Attribute, Cell, CellAlignment, ContentArrangement, Table,
7};
8
9pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
10 let contents = fs::read_to_string(&config.file_path)?;
11
12 let line_count = count_lines(&contents);
13 let word_count = count_words(&contents);
14 let byte_count = count_bytes(&contents);
15 let char_count = count_chars(&contents);
16
17 let mut table = Table::new();
18 table
19 .load_preset(UTF8_FULL)
20 .apply_modifier(UTF8_SOLID_INNER_BORDERS)
21 .apply_modifier(UTF8_ROUND_CORNERS)
22 .set_content_arrangement(ContentArrangement::Dynamic)
23 .set_header(vec![
24 Cell::new("Lines")
25 .add_attribute(Attribute::Bold)
26 .set_alignment(CellAlignment::Left),
27 Cell::new("Words")
28 .add_attribute(Attribute::Bold)
29 .set_alignment(CellAlignment::Left),
30 Cell::new("Bytes")
31 .add_attribute(Attribute::Bold)
32 .set_alignment(CellAlignment::Left),
33 Cell::new("Chars")
34 .add_attribute(Attribute::Bold)
35 .set_alignment(CellAlignment::Left),
36 Cell::new("File")
37 .add_attribute(Attribute::Bold)
38 .set_alignment(CellAlignment::Left),
39 ])
40 .add_row(vec![
41 Cell::new(line_count.to_string()).set_alignment(CellAlignment::Left),
42 Cell::new(word_count.to_string()).set_alignment(CellAlignment::Left),
43 Cell::new(byte_count.to_string()).set_alignment(CellAlignment::Left),
44 Cell::new(char_count.to_string()).set_alignment(CellAlignment::Left),
45 Cell::new(config.file_path).set_alignment(CellAlignment::Left),
46 ]);
47 println!("{table}");
48
49 Ok(())
50}
51
52pub fn count_lines<'a>(contents: &'a str) -> usize {
53 contents.lines().count()
54}
55
56pub fn count_bytes<'a>(contents: &'a str) -> usize {
57 contents.bytes().count()
58}
59
60pub fn count_words<'a>(contents: &'a str) -> usize {
61 contents.split_whitespace().count()
62}
63
64pub fn count_chars<'a>(contents: &'a str) -> usize {
65 contents.chars().count()
66}
67
68pub struct Config {
69 pub file_path: String,
70}
71
72impl Config {
73 pub fn build(args: &[String]) -> Result<Config, &'static str> {
74 let file_path = args[1].clone();
75
76 Ok(Config { file_path })
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn count_lines_test() {
86 let contents = "\
87 The quick brown fox
88 jumped over the lazy dog.
89 If the dog moved,
90 was it really lazy ?";
91
92 assert_eq!(count_lines(contents), 4);
93 }
94
95 #[test]
96 fn count_bytes_test() {
97 let contents = "The quick brown fox jumped over the lazy dog.";
98 assert_eq!(count_bytes(contents), 45);
99 }
100
101 #[test]
102 fn count_words_test() {
103 let contents = "The quick brown fox jumped over the lazy dog.";
104 assert_eq!(count_words(contents), 9);
105 }
106
107 #[test]
108 fn count_chars_test() {
109 let contents = "The quick brown fox jumped over the lazy dog.";
110 assert_eq!(count_words(contents), 9);
111 }
112
113}