Skip to content

Commit fdf435d

Browse files
authored
Refactoring of info/langs/mod.rs (o2sh#948)
* refacto langs module * rename var * add documentation to clarify the terminology
1 parent a1c2ae3 commit fdf435d

File tree

5 files changed

+90
-68
lines changed

5 files changed

+90
-68
lines changed

.github/CODEOWNERS

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/.github/ @spenserblack @o2sh
22
/image/src/ @CephalonRho @yoichi
3-
/src/info/git.rs @Byron
4-
/src/info/repo/ @o2sh
3+
/src/info/utils/git.rs @Byron
4+
/src/info/ @o2sh
55
/languages.yaml @spenserblack @o2sh
66
/src/info/langs/language.tera @spenserblack
77
/src/cli.rs @spenserblack @o2sh

src/info/langs/language.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,24 @@ pub struct LanguagesInfo {
2727

2828
impl LanguagesInfo {
2929
pub fn new(
30-
languages: Vec<(Language, f64)>,
30+
loc_by_language: &[(Language, usize)],
3131
true_color: bool,
3232
number_of_languages: usize,
3333
info_color: DynColors,
3434
) -> Self {
35-
let languages_with_percentage = languages
35+
let total: usize = loc_by_language.iter().map(|(_, v)| v).sum();
36+
37+
let weight_by_language: Vec<(Language, f64)> = loc_by_language
38+
.iter()
39+
.map(|(k, v)| {
40+
let mut val = *v as f64;
41+
val /= total as f64;
42+
val *= 100_f64;
43+
(*k, val)
44+
})
45+
.collect();
46+
47+
let languages_with_percentage = weight_by_language
3648
.into_iter()
3749
.map(|(language, percentage)| LanguageWithPercentage {
3850
language,

src/info/langs/mod.rs

+64-57
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,37 @@ use strum::IntoEnumIterator;
88

99
pub mod language;
1010

11-
pub fn get_dominant_language(languages_stat_vec: &[(Language, f64)]) -> Language {
12-
languages_stat_vec[0].0
11+
pub fn get_main_language(loc_by_language: &[(Language, usize)]) -> Language {
12+
loc_by_language[0].0
1313
}
1414

15-
pub fn get_language_statistics(
15+
/// Returns a vector of tuples containing all the languages detected inside the repository.
16+
/// Each tuple is composed of the language and its corresponding loc (lines of code).
17+
/// The vector is sorted by loc in descending order.
18+
pub fn get_loc_by_language_sorted(
1619
dir: &Path,
1720
ignored_directories: &[PathBuf],
1821
language_types: &[LanguageType],
1922
include_hidden: bool,
20-
) -> Result<(Vec<(Language, f64)>, usize)> {
23+
) -> Result<Vec<(Language, usize)>> {
2124
let stats = get_statistics(dir, ignored_directories, language_types, include_hidden);
22-
let language_distribution = get_language_distribution(&stats)
23-
.context("Could not find any source code in this repository")?;
24-
let mut language_distribution_vec: Vec<(_, _)> = language_distribution.into_iter().collect();
25-
language_distribution_vec.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
26-
let loc = get_total_loc(&stats);
27-
Ok((language_distribution_vec, loc))
25+
26+
let loc_by_language =
27+
get_loc_by_language(&stats).context("Could not find any source code in this repository")?;
28+
29+
let loc_by_language_sorted = sort_by_loc(loc_by_language);
30+
31+
Ok(loc_by_language_sorted)
32+
}
33+
34+
fn sort_by_loc(map: HashMap<Language, usize>) -> Vec<(Language, usize)> {
35+
let mut vec: Vec<(Language, usize)> = map.into_iter().collect();
36+
vec.sort_by(|a, b| b.1.cmp(&a.1));
37+
vec
2838
}
2939

30-
fn get_language_distribution(languages: &tokei::Languages) -> Option<HashMap<Language, f64>> {
31-
let mut language_distribution = HashMap::new();
40+
fn get_loc_by_language(languages: &tokei::Languages) -> Option<HashMap<Language, usize>> {
41+
let mut loc_by_language = HashMap::new();
3242

3343
for (language_name, language) in languages.iter() {
3444
let loc = language::loc(language_name, language);
@@ -37,27 +47,20 @@ fn get_language_distribution(languages: &tokei::Languages) -> Option<HashMap<Lan
3747
continue;
3848
}
3949

40-
language_distribution.insert(Language::from(*language_name), loc as f64);
50+
loc_by_language.insert(Language::from(*language_name), loc);
4151
}
4252

43-
let total: f64 = language_distribution.values().sum();
44-
45-
if total.abs() < f64::EPSILON {
53+
let total_loc: usize = loc_by_language.values().sum();
54+
if total_loc == 0 {
4655
None
4756
} else {
48-
for (_, val) in language_distribution.iter_mut() {
49-
*val /= total;
50-
*val *= 100_f64;
51-
}
52-
53-
Some(language_distribution)
57+
Some(loc_by_language)
5458
}
5559
}
5660

57-
fn get_total_loc(languages: &tokei::Languages) -> usize {
58-
languages.iter().fold(0, |sum, (lang_type, lang)| {
59-
sum + language::loc(lang_type, lang)
60-
})
61+
pub fn get_total_loc(loc_by_language: &[(Language, usize)]) -> usize {
62+
let total_loc: usize = loc_by_language.iter().map(|(_, v)| v).sum();
63+
total_loc
6164
}
6265

6366
fn get_statistics(
@@ -110,7 +113,7 @@ mod test {
110113
use tokei;
111114

112115
#[test]
113-
fn get_language_distribution_counts_md_comments() {
116+
fn get_loc_by_language_counts_md_comments() {
114117
let js = tokei::Language {
115118
blanks: 25,
116119
comments: 50,
@@ -131,36 +134,11 @@ mod test {
131134
languages.insert(js_type, js);
132135
languages.insert(md_type, md);
133136

134-
let language_distribution = get_language_distribution(&languages).unwrap();
135-
136-
// NOTE: JS is 25% with 100 lines of code, MD is 75% with 300 lines of code + comments
137-
assert_eq!(language_distribution[&Language::JavaScript], 25_f64);
138-
assert_eq!(language_distribution[&Language::Markdown], 75_f64);
139-
}
140-
141-
#[test]
142-
fn get_total_loc_counts_md_comments() {
143-
let js = tokei::Language {
144-
blanks: 25,
145-
comments: 50,
146-
code: 100,
147-
..Default::default()
148-
};
149-
let js_type = tokei::LanguageType::JavaScript;
150-
151-
let md = tokei::Language {
152-
blanks: 50,
153-
comments: 200,
154-
code: 100,
155-
..Default::default()
156-
};
157-
let md_type = tokei::LanguageType::Markdown;
137+
let loc_by_language = get_loc_by_language(&languages).unwrap();
158138

159-
let mut languages = tokei::Languages::new();
160-
languages.insert(js_type, js);
161-
languages.insert(md_type, md);
162-
163-
assert_eq!(get_total_loc(&languages), 400);
139+
// NOTE: JS with 100 lines of code, MD with 300 lines of code + comments
140+
assert_eq!(loc_by_language[&Language::JavaScript], 100);
141+
assert_eq!(loc_by_language[&Language::Markdown], 300);
164142
}
165143

166144
#[test]
@@ -190,6 +168,35 @@ mod test {
190168
let mut languages = tokei::Languages::new();
191169
languages.insert(tokei::LanguageType::Jupyter, jupyter_notebook);
192170

193-
assert_eq!(get_total_loc(&languages), 21);
171+
let loc_by_language = get_loc_by_language(&languages).unwrap();
172+
173+
assert_eq!(loc_by_language[&Language::Jupyter], 21);
174+
}
175+
176+
#[test]
177+
fn test_get_loc_by_language_sorted() {
178+
let mut map = HashMap::new();
179+
map.insert(Language::Ada, 300);
180+
map.insert(Language::Java, 40);
181+
map.insert(Language::Rust, 1200);
182+
map.insert(Language::Go, 8);
183+
184+
let sorted_map = sort_by_loc(map);
185+
186+
let expected_order = vec![
187+
(Language::Rust, 1200),
188+
(Language::Ada, 300),
189+
(Language::Java, 40),
190+
(Language::Go, 8),
191+
];
192+
let actual_order: Vec<_> = sorted_map.into_iter().collect();
193+
194+
assert_eq!(expected_order, actual_order);
195+
}
196+
197+
#[test]
198+
fn test_get_total_loc() {
199+
let loc_by_language = [(Language::JavaScript, 100), (Language::Markdown, 300)];
200+
assert_eq!(get_total_loc(&loc_by_language), 400);
194201
}
195202
}

src/info/loc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::info::langs::get_total_loc;
2+
use crate::info::langs::language::Language;
13
use serde::Serialize;
24

35
use crate::{
@@ -17,7 +19,8 @@ pub struct LocInfo {
1719
}
1820

1921
impl LocInfo {
20-
pub fn new(lines_of_code: usize, number_separator: NumberSeparator) -> Self {
22+
pub fn new(loc_by_language: &[(Language, usize)], number_separator: NumberSeparator) -> Self {
23+
let lines_of_code = get_total_loc(loc_by_language);
2124
Self {
2225
lines_of_code,
2326
number_separator,

src/info/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ impl Info {
114114
let git_repo = git_repository::discover(&config.input)?;
115115
let repo_path = get_work_dir(&git_repo)?;
116116

117-
let languages_handle = std::thread::spawn({
117+
let loc_by_language_sorted_handle = std::thread::spawn({
118118
let ignored_directories = config.exclude.clone();
119119
let language_types = config.r#type.clone();
120120
let include_hidden = config.include_hidden;
121121
let workdir = repo_path.clone();
122122
move || {
123-
langs::get_language_statistics(
123+
langs::get_loc_by_language_sorted(
124124
&workdir,
125125
&ignored_directories,
126126
&language_types,
@@ -129,11 +129,11 @@ impl Info {
129129
}
130130
});
131131

132-
let (languages, lines_of_code) = languages_handle
132+
let loc_by_language = loc_by_language_sorted_handle
133133
.join()
134134
.ok()
135135
.context("BUG: panic in language statistics thread")??;
136-
let dominant_language = langs::get_dominant_language(&languages);
136+
let dominant_language = langs::get_main_language(&loc_by_language);
137137
let true_color = match config.true_color {
138138
When::Always => true,
139139
When::Never => false,
@@ -178,7 +178,7 @@ impl Info {
178178
)?;
179179
let created = CreatedInfo::new(config.iso_time, &commits);
180180
let languages = LanguagesInfo::new(
181-
languages,
181+
&loc_by_language,
182182
true_color,
183183
config.number_of_languages,
184184
text_colors.info,
@@ -189,7 +189,7 @@ impl Info {
189189
let contributors =
190190
ContributorsInfo::new(&commits, config.number_of_authors, config.number_separator);
191191
let commits = CommitsInfo::new(&commits, config.number_separator);
192-
let lines_of_code = LocInfo::new(lines_of_code, config.number_separator);
192+
let lines_of_code = LocInfo::new(&loc_by_language, config.number_separator);
193193

194194
let info_fields: Vec<Box<dyn InfoField>> = vec![
195195
Box::new(project),

0 commit comments

Comments
 (0)