1#[allow(dead_code)]
2use colored::*;
3use std::collections::hash_map::DefaultHasher;
4use std::collections::{BTreeMap, HashMap};
5use std::hash::{Hash, Hasher};
6use std::time::{SystemTime, UNIX_EPOCH};
7
8use crate::analyzer::{CodeIssue, Severity};
9use crate::educational::EducationalAdvisor;
10use crate::hall_of_shame::HallOfShame;
11use crate::i18n::I18n;
12use crate::scoring::{CodeQualityScore, CodeScorer};
13
14pub struct Reporter {
15 harsh_mode: bool,
16 savage_mode: bool,
17 verbose: bool,
18 top_files: usize,
19 max_issues_per_file: usize,
20 summary_only: bool,
21 markdown: bool,
22 i18n: I18n,
23}
24
25#[allow(dead_code)]
26impl Reporter {
27 #[allow(clippy::too_many_arguments)]
28 pub fn new(
29 harsh_mode: bool,
30 savage_mode: bool,
31 verbose: bool,
32 top_files: usize,
33 max_issues_per_file: usize,
34 summary_only: bool,
35 markdown: bool,
36 lang: &str,
37 ) -> Self {
38 Self {
39 harsh_mode,
40 savage_mode,
41 verbose,
42 top_files,
43 max_issues_per_file,
44 summary_only,
45 markdown,
46 i18n: I18n::new(lang),
47 }
48 }
49
50 fn get_random_roast(&self, category: &str, score: f64, seed: u64) -> String {
52 let roasts = self.get_category_roasts(category, score);
53 if roasts.is_empty() {
54 return if self.i18n.lang == "zh-CN" {
55 "代码需要改进 🔧".to_string()
56 } else {
57 "Code needs improvement 🔧".to_string()
58 };
59 }
60
61 let mut hasher = DefaultHasher::new();
63 seed.hash(&mut hasher);
64 category.hash(&mut hasher);
65 let hash = hasher.finish();
66 let index = (hash as usize) % roasts.len();
67
68 roasts[index].to_string()
69 }
70
71 fn get_category_roasts(&self, category: &str, score: f64) -> Vec<&str> {
73 if self.i18n.lang == "zh-CN" {
74 match category {
75 "命名规范" => {
76 if score >= 80.0 {
77 vec![
78 "恭喜!你成功让变量名比注释还难懂 🏆",
79 "这些变量名是用随机字符生成器起的吗? 🎲",
80 "变量命名水平堪比密码设置 🔐",
81 "看到这些变量名,我想起了古代象形文字 📜",
82 "变量名比我的人生还迷茫 😵💫",
83 "这命名风格很有'艺术感' 🎨",
84 "变量名的创意程度超越了我的理解 🚀",
85 ]
86 } else if score >= 60.0 {
87 vec![
88 "变量命名还有改进空间 📝",
89 "建议给变量起个有意义的名字 💭",
90 "变量名可以更清晰一些 ✨",
91 "命名规范需要加强 📚",
92 ]
93 } else {
94 vec!["变量命名还不错 👍", "命名风格可以接受 ✅"]
95 }
96 }
97 "复杂度" => {
98 if score >= 80.0 {
99 vec![
100 "复杂度爆表!连AI都看不懂了 🤖",
101 "这代码比迷宫还复杂 🌀",
102 "嵌套层数比俄罗斯套娃还多 🪆",
103 "代码复杂度已经超越了人类理解范围 🧠",
104 "这函数比我的感情生活还复杂 💔",
105 "建议拆分成多个小函数,拯救一下可读性 🆘",
106 "复杂度高到需要GPS导航 🗺️",
107 "这代码比数学公式还抽象 📐",
108 "嵌套深度堪比洋葱,剥一层哭一次 🧅",
109 "代码结构比立体拼图还复杂 🧩",
110 "这复杂度让我想起了哲学问题 🤔",
111 "函数长度已经突破天际 🚀",
112 "这代码需要配个说明书 📖",
113 "复杂度比我的作息时间还乱 ⏰",
114 "建议给这个函数买个保险 🛡️",
115 ]
116 } else if score >= 60.0 {
117 vec![
118 "代码有点复杂,建议简化 🔧",
119 "函数可以拆分得更小一些 ✂️",
120 "嵌套层数有点多 📚",
121 "复杂度需要控制一下 ⚖️",
122 "代码结构可以更清晰 🏗️",
123 "建议重构一下逻辑 🔄",
124 "函数职责可以更单一 🎯",
125 "代码可读性需要提升 👓",
126 ]
127 } else {
128 vec!["代码结构还算清晰 👌", "复杂度控制得不错 ✅"]
129 }
130 }
131 "代码重复" => {
132 if score >= 80.0 {
133 vec![
134 "建议改名为copy-paste.rs 📋",
135 "重复代码比我重复的梦还多 💤",
136 "Ctrl+C 和 Ctrl+V 是你最好的朋友吗? ⌨️",
137 "代码重复度堪比复读机 🔄",
138 "这么多重复,建议学学DRY原则 🏜️",
139 "重复代码多到可以开复制店了 🏪",
140 "代码重复率比我的日常还高 📈",
141 "这重复程度可以申请吉尼斯纪录了 🏆",
142 "代码复制粘贴技能满级 🎮",
143 "重复代码比回音还响亮 📢",
144 "这是代码还是复印机作品? 🖨️",
145 "DRY原则在你这里变成了WET原则 💧",
146 "重复代码比我的口头禅还频繁 🗣️",
147 "建议给复制粘贴键盘买个保险 ⌨️",
148 "代码重复度比镜子还厉害 🪞",
149 ]
150 } else if score >= 60.0 {
151 vec![
152 "有一些重复代码需要处理 🔧",
153 "建议提取公共函数 📦",
154 "重复代码可以优化 ✨",
155 "考虑重构重复的部分 🔄",
156 "代码复用性可以提升 🔗",
157 "建议抽象出通用逻辑 🎯",
158 "重复部分可以模块化 📋",
159 "代码结构需要优化 🏗️",
160 ]
161 } else {
162 vec!["代码重复控制得不错 👍", "重复度在可接受范围 ✅"]
163 }
164 }
165 "Rust功能" => {
166 if score >= 80.0 {
167 vec![
168 "宏定义比我的借口还多 🎭",
169 "unwrap() 用得比我说'没问题'还频繁 😅",
170 "String 分配比我花钱还随意 💸",
171 "这代码让 Rust 编译器都想罢工 🚫",
172 "panic! 用得这么随意,用户体验堪忧 😱",
173 "迭代器哭了:为什么不用我? 😢",
174 "match 表示:我可以更简洁的 💪",
175 "Vec::new() 比我换衣服还频繁 👕",
176 "to_string() 调用比我眨眼还多 👁️",
177 "这代码让 Rust 的零成本抽象哭了 😭",
178 "错误处理?什么是错误处理? 🤷♂️",
179 "生命周期标注比我的简历还复杂 📄",
180 "这代码违反了 Rust 的哲学原则 📚",
181 "建议重新学习 Rust 最佳实践 🎓",
182 "Rust 社区看到这代码会流泪 🦀",
183 ]
184 } else if score >= 60.0 {
185 vec![
186 "Rust 特性使用需要改进 🦀",
187 "建议更好地利用 Rust 的特性 ⚡",
188 "代码可以更 Rust 化 🔧",
189 "某些模式可以优化 ✨",
190 "错误处理可以更优雅 🎭",
191 "内存管理还有优化空间 💾",
192 "迭代器使用可以加强 🔄",
193 "类型系统利用不够充分 📊",
194 ]
195 } else {
196 vec!["Rust 特性使用得不错 🦀", "代码很 Rust 化 ⚡"]
197 }
198 }
199 _ => vec!["代码需要改进 🔧"],
200 }
201 } else {
202 match category {
204 "Naming" => {
205 if score >= 80.0 {
206 vec![
207 "Congrats! Your variable names are more confusing than comments 🏆",
208 "Did you use a random character generator for these names? 🎲",
209 "Variable naming skills rival password creation 🔐",
210 "These names remind me of ancient hieroglyphs 📜",
211 "Variable names are more lost than my life purpose 😵💫",
212 "This naming style is very 'artistic' 🎨",
213 "The creativity of these names exceeds my understanding 🚀",
214 "Variable names harder to decode than alien language 👽",
215 "These names are more abstract than modern art 🖼️",
216 "Did you name these variables with your eyes closed? 👀",
217 "Variable naming master class: how to confuse everyone 🎓",
218 "These names could win a cryptography contest 🔍",
219 "Variable names more mysterious than unsolved puzzles 🧩",
220 "I've seen more meaningful names in spam emails 📧",
221 "These names make dictionary words jealous 📚",
222 ]
223 } else if score >= 60.0 {
224 vec![
225 "Variable naming has room for improvement 📝",
226 "Consider giving variables meaningful names 💭",
227 "Variable names could be clearer ✨",
228 "Naming conventions need strengthening 📚",
229 "Variable readability could be enhanced 👀",
230 "Naming is an art - keep practicing! 💪",
231 "Variables could be more expressive 🗣️",
232 "Naming style needs consistency 📐",
233 ]
234 } else {
235 vec![
236 "Variable naming is decent 👍",
237 "Naming style is acceptable ✅",
238 ]
239 }
240 }
241 "Complexity" => {
242 if score >= 80.0 {
243 vec![
244 "Complexity off the charts! Even AI can't understand 🤖",
245 "This code is more complex than a maze 🌀",
246 "More nesting levels than Russian dolls 🪆",
247 "Code complexity has transcended human understanding 🧠",
248 "This function is more complex than my love life 💔",
249 "Consider splitting into smaller functions to save readability 🆘",
250 "Complexity so high it needs GPS navigation 🗺️",
251 "This code is more abstract than quantum physics 📐",
252 "Nesting deeper than an onion, each layer brings tears 🧅",
253 "Code structure more complex than a 3D puzzle 🧩",
254 "This complexity makes philosophy look simple 🤔",
255 "Function length has reached astronomical proportions 🚀",
256 "This code needs a user manual 📖",
257 "Complexity more chaotic than my sleep schedule ⏰",
258 "Consider getting insurance for this function 🛡️",
259 ]
260 } else if score >= 60.0 {
261 vec![
262 "Code is a bit complex, consider simplifying 🔧",
263 "Functions could be split smaller ✂️",
264 "A bit too many nesting levels 📚",
265 "Complexity needs some control ⚖️",
266 "Code structure could be clearer 🏗️",
267 "Consider refactoring the logic 🔄",
268 "Function responsibilities could be more focused 🎯",
269 "Code readability needs improvement 👓",
270 ]
271 } else {
272 vec![
273 "Code structure is fairly clear 👌",
274 "Complexity is well controlled ✅",
275 ]
276 }
277 }
278 "Duplication" => {
279 if score >= 80.0 {
280 vec![
281 "Consider renaming to copy-paste.rs 📋",
282 "More duplicate code than my recurring dreams 💤",
283 "Are Ctrl+C and Ctrl+V your best friends? ⌨️",
284 "Code duplication rivals a parrot 🔄",
285 "So much duplication, time to learn DRY principle 🏜️",
286 "Enough duplicate code to open a copy shop 🏪",
287 "Code duplication rate higher than my daily routine 📈",
288 "This duplication level deserves a Guinness World Record 🏆",
289 "Copy-paste skills have reached maximum level 🎮",
290 "Duplicate code echoes louder than a canyon 📢",
291 "Is this code or a photocopier masterpiece? 🖨️",
292 "DRY principle became WET principle in your hands 💧",
293 "Code repetition more frequent than my catchphrases 🗣️",
294 "Consider buying insurance for your copy-paste keys ⌨️",
295 "Duplication level surpasses hall of mirrors 🪞",
296 ]
297 } else if score >= 60.0 {
298 vec![
299 "Some duplicate code needs handling 🔧",
300 "Consider extracting common functions 📦",
301 "Duplicate code can be optimized ✨",
302 "Consider refactoring repeated parts 🔄",
303 "Code reusability could be improved 🔗",
304 "Consider abstracting common logic 🎯",
305 "Repeated sections could be modularized 📋",
306 "Code structure needs optimization 🏗️",
307 ]
308 } else {
309 vec![
310 "Code duplication is well controlled 👍",
311 "Duplication within acceptable range ✅",
312 ]
313 }
314 }
315 "Rust Features" => {
316 if score >= 80.0 {
317 vec![
318 "More macro definitions than my excuses 🎭",
319 "unwrap() used more frequently than I say 'no problem' 😅",
320 "String allocation more casual than my spending 💸",
321 "This code makes Rust compiler want to quit 🚫",
322 "panic! used so casually, user experience is questionable 😱",
323 "Iterators are crying: why don't you use me? 😢",
324 "match says: I can be more concise 💪",
325 "Vec::new() calls more frequent than my outfit changes 👕",
326 "to_string() calls exceed my blink count 👁️",
327 "This code made Rust's zero-cost abstractions weep 😭",
328 "Error handling? What's error handling? 🤷♂️",
329 "Lifetime annotations more complex than my resume 📄",
330 "This code violates Rust's philosophical principles 📚",
331 "Consider retaking Rust best practices course 🎓",
332 "Rust community would shed tears seeing this code 🦀",
333 ]
334 } else if score >= 60.0 {
335 vec![
336 "Rust feature usage needs improvement 🦀",
337 "Consider better utilization of Rust features ⚡",
338 "Code could be more Rust-idiomatic 🔧",
339 "Some patterns can be optimized ✨",
340 "Error handling could be more elegant 🎭",
341 "Memory management has room for optimization 💾",
342 "Iterator usage could be strengthened 🔄",
343 "Type system utilization is insufficient 📊",
344 ]
345 } else {
346 vec![
347 "Rust features used well 🦀",
348 "Code is very Rust-idiomatic ⚡",
349 ]
350 }
351 }
352 _ => vec!["Code needs improvement 🔧"],
353 }
354 }
355 }
356
357 #[allow(dead_code)]
358 pub fn report(&self, issues: Vec<CodeIssue>) {
359 self.report_with_metrics(issues, 1, 100);
360 }
361
362 pub fn report_with_enhanced_features(
363 &self,
364 mut issues: Vec<CodeIssue>,
365 file_count: usize,
366 total_lines: usize,
367 educational_advisor: Option<&EducationalAdvisor>,
368 hall_of_shame: Option<&HallOfShame>,
369 show_suggestions: bool,
370 ) {
371 let scorer = CodeScorer::new();
373 let quality_score = scorer.calculate_score(&issues, file_count, total_lines);
374
375 if issues.is_empty() {
376 self.print_clean_code_message_with_score(&quality_score);
377 return;
378 }
379
380 issues.sort_by(|a, b| {
382 let severity_order = |s: &Severity| match s {
383 Severity::Nuclear => 3,
384 Severity::Spicy => 2,
385 Severity::Mild => 1,
386 };
387 severity_order(&b.severity).cmp(&severity_order(&a.severity))
388 });
389
390 if self.harsh_mode {
392 issues.retain(|issue| matches!(issue.severity, Severity::Nuclear | Severity::Spicy));
393 }
394
395 if self.markdown {
396 self.print_markdown_report_enhanced(
397 &issues,
398 &quality_score,
399 educational_advisor,
400 hall_of_shame,
401 show_suggestions,
402 );
403 } else {
404 if !self.summary_only {
405 self.print_header(&issues);
406 self.print_quality_score(&quality_score);
407 if self.verbose {
408 self.print_detailed_analysis(&issues);
409 }
410 self.print_top_files(&issues);
411 self.print_issues_enhanced(&issues, educational_advisor);
412 }
413 self.print_summary_with_score(&issues, &quality_score);
414 if !self.summary_only {
415 if let Some(shame) = hall_of_shame {
417 self.print_hall_of_shame(shame);
418 }
419
420 if show_suggestions {
422 if let Some(shame) = hall_of_shame {
423 self.print_improvement_suggestions(shame);
424 }
425 }
426
427 if !show_suggestions {
429 self.print_footer(&issues);
430 }
431 }
432 }
433 }
434
435 pub fn report_with_metrics(
436 &self,
437 mut issues: Vec<CodeIssue>,
438 file_count: usize,
439 total_lines: usize,
440 ) {
441 let scorer = CodeScorer::new();
443 let quality_score = scorer.calculate_score(&issues, file_count, total_lines);
444
445 if issues.is_empty() {
446 self.print_clean_code_message_with_score(&quality_score);
447 return;
448 }
449
450 issues.sort_by(|a, b| {
452 let severity_order = |s: &Severity| match s {
453 Severity::Nuclear => 3,
454 Severity::Spicy => 2,
455 Severity::Mild => 1,
456 };
457 severity_order(&b.severity).cmp(&severity_order(&a.severity))
458 });
459
460 if self.harsh_mode {
462 issues.retain(|issue| matches!(issue.severity, Severity::Nuclear | Severity::Spicy));
463 }
464
465 if self.markdown {
466 self.print_markdown_report(&issues);
467 } else {
468 if !self.summary_only {
469 self.print_header(&issues);
470 self.print_quality_score(&quality_score);
471 if self.verbose {
472 self.print_detailed_analysis(&issues);
473 }
474 self.print_top_files(&issues);
475 self.print_issues(&issues);
476 }
477 self.print_summary_with_score(&issues, &quality_score);
478 if !self.summary_only {
479 self.print_footer(&issues);
480 }
481 }
482 }
483
484 #[allow(dead_code)]
485 fn print_clean_code_message(&self) {
486 if self.markdown {
487 println!("# {}", self.i18n.get("title"));
488 println!();
489 println!("{}", self.i18n.get("clean_code"));
490 println!();
491 println!("{}", self.i18n.get("clean_code_warning"));
492 } else {
493 println!("{}", self.i18n.get("clean_code").bright_green().bold());
494 println!("{}", self.i18n.get("clean_code_warning").yellow());
495 }
496 }
497
498 fn print_clean_code_message_with_score(&self, quality_score: &CodeQualityScore) {
499 if self.markdown {
500 println!("# {}", self.i18n.get("title"));
501 println!();
502 println!("## 🏆 代码质量评分");
503 println!();
504 println!(
505 "**评分**: {:.1}/100 {}",
506 quality_score.total_score,
507 quality_score.quality_level.emoji()
508 );
509 println!(
510 "**等级**: {}",
511 quality_score.quality_level.description(&self.i18n.lang)
512 );
513 println!();
514 println!("{}", self.i18n.get("clean_code"));
515 println!();
516 println!("{}", self.i18n.get("clean_code_warning"));
517 } else {
518 println!("{}", self.i18n.get("clean_code").bright_green().bold());
519 println!();
520 println!(
521 "{} 代码质量评分: {:.1}/100 {}",
522 "🏆".bright_yellow(),
523 quality_score.total_score.to_string().bright_green().bold(),
524 quality_score.quality_level.emoji()
525 );
526 println!(
527 "{} 质量等级: {}",
528 "📊".bright_blue(),
529 quality_score
530 .quality_level
531 .description(&self.i18n.lang)
532 .bright_green()
533 .bold()
534 );
535 println!("{}", self.i18n.get("clean_code_warning").yellow());
536 }
537 }
538
539 fn print_quality_score(&self, quality_score: &CodeQualityScore) {
540 let title = match self.i18n.lang.as_str() {
541 "zh-CN" => "🏆 代码质量评分",
542 _ => "🏆 Code Quality Score",
543 };
544 println!("{}", title.bright_yellow().bold());
545 println!("{}", "─".repeat(50).bright_black());
546
547 let _score_color = match quality_score.quality_level {
548 crate::scoring::QualityLevel::Excellent => {
549 quality_score.total_score.to_string().bright_green().bold()
550 }
551 crate::scoring::QualityLevel::Good => quality_score.total_score.to_string().green(),
552 crate::scoring::QualityLevel::Average => quality_score.total_score.to_string().yellow(),
553 crate::scoring::QualityLevel::Poor => quality_score.total_score.to_string().red(),
554 crate::scoring::QualityLevel::Terrible => {
555 quality_score.total_score.to_string().bright_red().bold()
556 }
557 };
558
559 let (score_label, level_label) = match self.i18n.lang.as_str() {
560 "zh-CN" => ("📊 总分", "🎯 等级"),
561 _ => ("📊 Score", "🎯 Level"),
562 };
563
564 println!(
565 " {}: {:.1}/100 {}",
566 score_label,
567 quality_score.total_score,
568 quality_score.quality_level.emoji()
569 );
570 println!(
571 " {}: {}",
572 level_label,
573 quality_score
574 .quality_level
575 .description(&self.i18n.lang)
576 .bright_white()
577 .bold()
578 );
579
580 if quality_score.total_lines > 0 {
581 let (lines_label, files_label, density_label) = match self.i18n.lang.as_str() {
582 "zh-CN" => ("📏 代码行数", "📁 文件数量", "🔍 问题密度"),
583 _ => ("📏 Lines of Code", "📁 Files", "🔍 Issue Density"),
584 };
585 let density_unit = match self.i18n.lang.as_str() {
586 "zh-CN" => "问题/千行",
587 _ => "issues/1k lines",
588 };
589
590 println!(
591 " {}: {}",
592 lines_label,
593 quality_score.total_lines.to_string().cyan()
594 );
595 println!(
596 " {}: {}",
597 files_label,
598 quality_score.file_count.to_string().cyan()
599 );
600 println!(
601 " {}: {:.2} {}",
602 density_label,
603 quality_score.issue_density.to_string().cyan(),
604 density_unit
605 );
606 }
607
608 if quality_score.severity_distribution.nuclear > 0
609 || quality_score.severity_distribution.spicy > 0
610 || quality_score.severity_distribution.mild > 0
611 {
612 println!();
613 let distribution_title = match self.i18n.lang.as_str() {
614 "zh-CN" => "🎭 问题分布:",
615 _ => "🎭 Issue Distribution:",
616 };
617 let (nuclear_label, spicy_label, mild_label) = match self.i18n.lang.as_str() {
618 "zh-CN" => ("💥 核弹级", "🌶️ 严重", "😐 轻微"),
619 _ => ("💥 Nuclear", "🌶️ Spicy", "😐 Mild"),
620 };
621
622 println!(" {distribution_title}");
623 if quality_score.severity_distribution.nuclear > 0 {
624 println!(
625 " {}: {}",
626 nuclear_label,
627 quality_score
628 .severity_distribution
629 .nuclear
630 .to_string()
631 .red()
632 .bold()
633 );
634 }
635 if quality_score.severity_distribution.spicy > 0 {
636 println!(
637 " {}: {}",
638 spicy_label,
639 quality_score
640 .severity_distribution
641 .spicy
642 .to_string()
643 .yellow()
644 );
645 }
646 if quality_score.severity_distribution.mild > 0 {
647 println!(
648 " {}: {}",
649 mild_label,
650 quality_score.severity_distribution.mild.to_string().blue()
651 );
652 }
653 }
654
655 if !quality_score.category_scores.is_empty() && self.verbose {
657 println!();
658 let category_title = match self.i18n.lang.as_str() {
659 "zh-CN" => "📋 分类得分:",
660 _ => "📋 Category Scores:",
661 };
662 println!(" {category_title}");
663 let mut sorted_categories: Vec<_> = quality_score.category_scores.iter().collect();
664 sorted_categories
665 .sort_by(|a, b| b.1.partial_cmp(a.1).unwrap_or(std::cmp::Ordering::Equal));
666
667 for (category, score) in sorted_categories.iter().take(5) {
668 let category_name = match (self.i18n.lang.as_str(), category.as_str()) {
669 ("zh-CN", "naming") => "命名规范",
670 ("zh-CN", "complexity") => "复杂度",
671 ("zh-CN", "rust-basics") => "Rust基础",
672 ("zh-CN", "advanced-rust") => "高级特性",
673 ("zh-CN", "rust-features") => "Rust功能",
674 ("zh-CN", "structure") => "代码结构",
675 ("zh-CN", "duplication") => "重复代码",
676 (_, "naming") => "Naming",
677 (_, "complexity") => "Complexity",
678 (_, "rust-basics") => "Rust Basics",
679 (_, "advanced-rust") => "Advanced Rust",
680 (_, "rust-features") => "Rust Features",
681 (_, "structure") => "Code Structure",
682 (_, "duplication") => "Code Duplication",
683 _ => category,
684 };
685 println!(
686 " {} {:.1}",
687 category_name.cyan(),
688 score.to_string().yellow()
689 );
690 }
691 }
692
693 println!();
694 }
695
696 fn print_header(&self, issues: &[CodeIssue]) {
697 let total = issues.len();
698 let nuclear = issues
699 .iter()
700 .filter(|i| matches!(i.severity, Severity::Nuclear))
701 .count();
702 let spicy = issues
703 .iter()
704 .filter(|i| matches!(i.severity, Severity::Spicy))
705 .count();
706 let mild = issues
707 .iter()
708 .filter(|i| matches!(i.severity, Severity::Mild))
709 .count();
710
711 println!("{}", self.i18n.get("title").bright_red().bold());
712 println!("{}", self.i18n.get("preparing").yellow());
713 println!();
714
715 println!("{}", self.i18n.get("report_title").bright_red().bold());
716 println!("{}", "─".repeat(50).bright_black());
717
718 if self.savage_mode {
719 println!("{}", self.i18n.get("found_issues").red().bold());
720 } else {
721 println!("{}", self.i18n.get("found_issues").yellow());
722 }
723
724 println!();
725 println!("{}", self.i18n.get("statistics"));
726 println!(
727 " {} {}",
728 nuclear.to_string().red().bold(),
729 self.i18n.get("nuclear_issues")
730 );
731 println!(
732 " {} {}",
733 spicy.to_string().yellow().bold(),
734 self.i18n.get("spicy_issues")
735 );
736 println!(
737 " {} {}",
738 mild.to_string().blue().bold(),
739 self.i18n.get("mild_issues")
740 );
741 println!(
742 " {} {}",
743 total.to_string().bright_white().bold(),
744 self.i18n.get("total")
745 );
746 println!();
747 }
748
749 fn print_issues(&self, issues: &[CodeIssue]) {
750 let mut file_groups: HashMap<String, Vec<&CodeIssue>> = HashMap::new();
751
752 for issue in issues {
753 let file_name = issue
754 .file_path
755 .file_name()
756 .unwrap_or_default()
757 .to_string_lossy()
758 .to_string();
759 file_groups.entry(file_name).or_default().push(issue);
760 }
761
762 for (file_name, file_issues) in file_groups {
763 println!("{} {}", "📁".bright_blue(), file_name.bright_blue().bold());
764
765 let mut rule_groups: BTreeMap<String, Vec<&CodeIssue>> = BTreeMap::new();
767 for issue in &file_issues {
768 rule_groups
769 .entry(issue.rule_name.clone())
770 .or_default()
771 .push(issue);
772 }
773
774 let _max_per_rule = 5;
776 let mut total_shown = 0;
777 let max_total = if self.max_issues_per_file > 0 {
778 self.max_issues_per_file
779 } else {
780 usize::MAX
781 };
782
783 let mut sorted_rules: Vec<_> = rule_groups.into_iter().collect();
785 sorted_rules.sort_by(|a, b| {
786 let severity_order = |s: &Severity| match s {
787 Severity::Nuclear => 3,
788 Severity::Spicy => 2,
789 Severity::Mild => 1,
790 };
791 let max_severity_a =
792 a.1.iter()
793 .map(|i| severity_order(&i.severity))
794 .max()
795 .unwrap_or(1);
796 let max_severity_b =
797 b.1.iter()
798 .map(|i| severity_order(&i.severity))
799 .max()
800 .unwrap_or(1);
801 max_severity_b.cmp(&max_severity_a)
802 });
803
804 for (rule_name, rule_issues) in sorted_rules {
805 if total_shown >= max_total {
806 break;
807 }
808
809 let rule_issues_len = rule_issues.len();
810
811 if rule_name.contains("naming") || rule_name.contains("single-letter") {
813 let bad_names: Vec<String> = rule_issues
815 .iter()
816 .filter_map(|issue| {
817 if let Some(start) = issue.message.find("'") {
818 issue.message[start + 1..].find("'").map(|end| {
819 issue.message[start + 1..start + 1 + end].to_string()
820 })
821 } else {
822 None
823 }
824 })
825 .take(5)
826 .collect();
827
828 let names_display = if bad_names.len() < rule_issues_len {
829 format!("{}, ...", bad_names.join(", "))
830 } else {
831 bad_names.join(", ")
832 };
833
834 let label = if self.i18n.lang == "zh-CN" {
835 "变量命名问题"
836 } else {
837 "Variable naming issues"
838 };
839
840 println!(
841 " 🏷️ {}: {} ({})",
842 label.bright_yellow().bold(),
843 rule_issues_len.to_string().bright_red().bold(),
844 names_display.bright_black()
845 );
846 total_shown += 1;
847 } else if rule_name.contains("duplication") {
848 let label = if self.i18n.lang == "zh-CN" {
849 "代码重复问题"
850 } else {
851 "Code duplication issues"
852 };
853
854 let instance_info = if let Some(first_issue) = rule_issues.first() {
856 if first_issue.message.contains("instances") {
857 let parts: Vec<&str> = first_issue.message.split_whitespace().collect();
858 if let Some(pos) = parts.iter().position(|&x| x == "instances") {
859 if pos > 0 {
860 format!("{} instances", parts[pos - 1])
861 } else {
862 "multiple instances".to_string()
863 }
864 } else if self.i18n.lang == "zh-CN" {
865 "多个代码块".to_string()
866 } else {
867 "multiple blocks".to_string()
868 }
869 } else if self.i18n.lang == "zh-CN" {
870 "多个代码块".to_string()
871 } else {
872 "multiple blocks".to_string()
873 }
874 } else if self.i18n.lang == "zh-CN" {
875 "多个代码块".to_string()
876 } else {
877 "multiple blocks".to_string()
878 };
879
880 println!(
881 " 🔄 {}: {} ({})",
882 label.bright_cyan().bold(),
883 rule_issues_len.to_string().bright_cyan().bold(),
884 instance_info.bright_black()
885 );
886 total_shown += 1;
887 } else if rule_name.contains("nesting") {
888 let label = if self.i18n.lang == "zh-CN" {
889 "嵌套深度问题"
890 } else {
891 "Nesting depth issues"
892 };
893
894 let depths: Vec<usize> = rule_issues
896 .iter()
897 .filter_map(|issue| {
898 if let Some(start) = issue.message.find("depth: ") {
899 let depth_str = &issue.message[start + 7..];
900 if let Some(end) = depth_str.find(')') {
901 depth_str[..end].parse().ok()
902 } else {
903 None
904 }
905 } else if let Some(start) = issue.message.find("深度: ") {
906 let depth_str = &issue.message[start + 6..];
907 if let Some(end) = depth_str.find(')') {
908 depth_str[..end].parse().ok()
909 } else {
910 None
911 }
912 } else {
913 None
914 }
915 })
916 .collect();
917
918 let depth_info = if !depths.is_empty() {
919 let min_depth = depths.iter().min().unwrap_or(&4);
920 let max_depth = depths.iter().max().unwrap_or(&8);
921 if min_depth == max_depth {
922 format!("depth {min_depth}")
923 } else {
924 format!("depth {min_depth}-{max_depth}")
925 }
926 } else if self.i18n.lang == "zh-CN" {
927 "深度嵌套".to_string()
928 } else {
929 "deep nesting".to_string()
930 };
931
932 println!(
933 " 📦 {}: {} ({})",
934 label.bright_magenta().bold(),
935 rule_issues_len.to_string().bright_magenta().bold(),
936 depth_info.bright_black()
937 );
938 total_shown += 1;
939 } else {
940 let display_name = match (self.i18n.lang.as_str(), rule_name.as_str()) {
942 ("zh-CN", "panic-abuse") => "panic 滥用",
943 ("zh-CN", "god-function") => "上帝函数",
944 ("zh-CN", "magic-number") => "魔法数字",
945 ("zh-CN", "todo-comment") => "TODO 注释",
946 ("zh-CN", "println-debugging") => "println 调试",
947 ("zh-CN", "string-abuse") => "String 滥用",
948 ("zh-CN", "vec-abuse") => "Vec 滥用",
949 ("zh-CN", "iterator-abuse") => "迭代器滥用",
950 ("zh-CN", "match-abuse") => "Match 滥用",
951 ("zh-CN", "hungarian-notation") => "匈牙利命名法",
952 ("zh-CN", "abbreviation-abuse") => "过度缩写",
953 ("zh-CN", "meaningless-naming") => "无意义命名",
954 ("zh-CN", "commented-code") => "被注释代码",
955 ("zh-CN", "dead-code") => "死代码",
956 _ => &rule_name.replace("-", " "),
957 };
958 println!(
959 " ⚠️ {}: {}",
960 display_name.bright_yellow().bold(),
961 rule_issues_len.to_string().bright_yellow().bold()
962 );
963 total_shown += 1;
964 }
965 }
966 println!();
967 }
968 }
969
970 fn print_issue(&self, issue: &CodeIssue) {
971 if issue.rule_name.contains("duplication") {
973 let message = if self.i18n.lang == "zh-CN" {
974 &issue.message
975 } else {
976 if issue.message.contains("相似代码块") {
978 "Found similar code blocks, consider refactoring into functions"
979 } else if issue.message.contains("DRY原则哭了") {
980 "Code duplication detected, DRY principle violated"
981 } else {
982 &issue.message
983 }
984 };
985 println!(
986 " {} {} {}",
987 "🔄".bright_cyan(),
988 "duplicate".bright_black(),
989 message.bright_cyan().bold()
990 );
991 } else if issue.rule_name.contains("nesting") {
992 let message = if self.i18n.lang == "zh-CN" {
993 &issue.message
994 } else {
995 if issue.message.contains("俄罗斯套娃") {
997 "Nesting deeper than Russian dolls, are you writing a maze?"
998 } else if issue.message.contains("挖到地心") {
999 "Nesting so deep, trying to dig to the Earth's core?"
1000 } else if issue.message.contains("像洋葱一样") {
1001 "Code nested like an onion, makes me want to cry"
1002 } else {
1003 &issue.message
1004 }
1005 };
1006 println!(
1007 " {} {} {}",
1008 "📦".bright_magenta(),
1009 "nesting".bright_black(),
1010 message.bright_magenta()
1011 );
1012 } else {
1013 let severity_icon = match issue.severity {
1015 Severity::Nuclear => "💥",
1016 Severity::Spicy => "🌶️",
1017 Severity::Mild => "😐",
1018 };
1019
1020 let line_info = format!("{}:{}", issue.line, issue.column);
1021 let colored_message = match issue.severity {
1022 Severity::Nuclear => issue.message.red().bold(),
1023 Severity::Spicy => issue.message.yellow(),
1024 Severity::Mild => issue.message.blue(),
1025 };
1026
1027 let _final_message = if self.savage_mode {
1028 self.make_message_savage(&issue.message)
1029 } else {
1030 issue.message.clone()
1031 };
1032
1033 println!(
1034 " {} {} {}",
1035 severity_icon.bright_yellow(),
1036 line_info.bright_black(),
1037 colored_message
1038 );
1039 }
1040 }
1041
1042 fn make_message_savage(&self, message: &str) -> String {
1043 let savage_prefixes = [
1044 "🔥 严重警告:",
1045 "💀 代码死刑:",
1046 "🗑️ 垃圾警报:",
1047 "😱 恐怖发现:",
1048 "🤮 令人作呕:",
1049 ];
1050
1051 let prefix = savage_prefixes[message.len() % savage_prefixes.len()];
1052 format!("{prefix} {message}")
1053 }
1054
1055 fn print_summary_with_score(&self, issues: &[CodeIssue], quality_score: &CodeQualityScore) {
1056 self.print_enhanced_summary(issues, quality_score);
1058 }
1059
1060 fn print_enhanced_summary(&self, issues: &[CodeIssue], quality_score: &CodeQualityScore) {
1061 println!();
1062
1063 if self.i18n.lang == "zh-CN" {
1065 println!("{}", "🏆 代码质量报告".bright_cyan().bold());
1066 println!("{}", "═".repeat(60).bright_black());
1067 } else {
1068 println!("{}", "🏆 Code Quality Report".bright_cyan().bold());
1069 println!("{}", "═".repeat(60).bright_black());
1070 }
1071
1072 let score_bar = self.create_enhanced_score_bar(quality_score.total_score);
1074 let score_emoji = quality_score.quality_level.emoji();
1075 let score_desc = quality_score.quality_level.description(&self.i18n.lang);
1076
1077 if self.i18n.lang == "zh-CN" {
1078 println!("╭─ 📊 总体评分 ─────────────────────────────────────────╮");
1079 println!("│ │");
1080
1081 let score_text = format!("总分: {:.1}/100", quality_score.total_score);
1083 let status_text = format!("({score_emoji} {score_desc})");
1084 println!(
1085 "│ {} {} {}│",
1086 score_text.bright_red().bold(),
1087 score_bar,
1088 status_text.bright_black()
1089 );
1090
1091 let file_count = issues
1093 .iter()
1094 .map(|i| &i.file_path)
1095 .collect::<std::collections::HashSet<_>>()
1096 .len();
1097 let total_issues = issues.len();
1098 println!("│ │");
1099 let stats_text = format!("分析文件: {file_count} 个 问题总数: {total_issues} 个");
1100 println!("│ {stats_text} │");
1101 println!("│ │");
1102 println!("╰──────────────────────────────────────────────────────╯");
1103 } else {
1104 println!("╭─ 📊 Overall Score ───────────────────────────────────╮");
1105 println!("│ │");
1106
1107 let score_text = format!("Score: {:.1}/100", quality_score.total_score);
1109 let status_text = format!("({score_emoji} {score_desc})");
1110 println!(
1111 "│ {} {} {}│",
1112 score_text.bright_red().bold(),
1113 score_bar,
1114 status_text.bright_black()
1115 );
1116
1117 let file_count = issues
1119 .iter()
1120 .map(|i| &i.file_path)
1121 .collect::<std::collections::HashSet<_>>()
1122 .len();
1123 let total_issues = issues.len();
1124 println!("│ │");
1125 let stats_text =
1126 format!("Files analyzed: {file_count} Total issues: {total_issues}");
1127 println!("│ {stats_text} │");
1128 println!("│ │");
1129 println!("╰──────────────────────────────────────────────────────╯");
1130 }
1131
1132 println!();
1133 self.print_category_scores_enhanced(&quality_score.category_scores);
1134
1135 println!();
1136 self.print_quality_legend();
1137
1138 }
1141
1142 fn create_enhanced_score_bar(&self, score: f64) -> String {
1143 let bar_length = 20;
1144 let filled_length = ((score / 100.0) * bar_length as f64) as usize;
1146 let empty_length = bar_length - filled_length;
1147
1148 let filled_char = if score >= 80.0 {
1149 "█".red()
1150 } else if score >= 60.0 {
1151 "█".yellow()
1152 } else if score >= 40.0 {
1153 "█".blue()
1154 } else {
1155 "█".green()
1156 };
1157
1158 let empty_char = "▒".bright_black();
1159
1160 format!(
1161 "{}{}",
1162 filled_char.to_string().repeat(filled_length),
1163 empty_char.to_string().repeat(empty_length)
1164 )
1165 }
1166
1167 fn print_category_scores_enhanced(
1168 &self,
1169 category_scores: &std::collections::HashMap<String, f64>,
1170 ) {
1171 if self.i18n.lang == "zh-CN" {
1172 println!("{}", "📋 分类评分详情".bright_yellow().bold());
1173 } else {
1174 println!("{}", "📋 Category Scores".bright_yellow().bold());
1175 }
1176 println!("{}", "─".repeat(60).bright_black());
1177
1178 let categories = [
1180 ("naming", "命名规范", "Naming", "🏷️"),
1181 ("complexity", "复杂度", "Complexity", "🧩"),
1182 ("duplication", "代码重复", "Duplication", "🔄"),
1183 ("rust-basics", "Rust基础", "Rust Basics", "🦀"),
1184 ("advanced-rust", "高级特性", "Advanced Rust", "⚡"),
1185 ("rust-features", "Rust功能", "Rust Features", "🚀"),
1186 ("structure", "代码结构", "Code Structure", "🏗️"),
1187 ];
1188
1189 for (category_key, zh_name, en_name, icon) in &categories {
1190 if let Some(score) = category_scores.get(*category_key) {
1191 let display_name = if self.i18n.lang == "zh-CN" {
1192 zh_name
1193 } else {
1194 en_name
1195 };
1196 let (status_icon, status_text) = self.get_score_status(*score);
1197 let score_bar = self.create_enhanced_score_bar(*score);
1198
1199 let score_unit = if self.i18n.lang == "zh-CN" { "分" } else { "" };
1201 println!(
1202 " {} {} [{:>3}{}] {} {}",
1203 status_icon,
1204 format!("{icon} {display_name}").bright_white().bold(),
1205 format!("{score:.0}").bright_cyan(),
1206 score_unit,
1207 score_bar,
1208 status_text.bright_black()
1209 );
1210
1211 if let Some(roast) = self.get_category_roast(category_key, *score) {
1213 println!(" 💬 {}", roast.bright_yellow().italic());
1214 }
1215 }
1216 }
1217 println!();
1218 }
1219
1220 fn print_quality_legend(&self) {
1221 if self.i18n.lang == "zh-CN" {
1222 println!(
1223 "{}",
1224 "📏 评分标准 (分数越高代码越烂)".bright_yellow().bold()
1225 );
1226 println!("{}", "─".repeat(40).bright_black());
1227 println!(" 💀 81-100分: 糟糕,急需重写 🔥 61-80分: 较差,建议重构");
1228 println!(" ⚠️ 41-60分: 一般,需要改进 ✅ 21-40分: 良好,还有提升空间");
1229 println!(" 🌟 0-20分: 优秀,继续保持");
1230 } else {
1231 println!(
1232 "{}",
1233 "📏 Scoring Scale (higher score = worse code)"
1234 .bright_yellow()
1235 .bold()
1236 );
1237 println!("{}", "─".repeat(50).bright_black());
1238 println!(
1239 " 💀 81-100: Terrible, rewrite needed 🔥 61-80: Poor, refactoring recommended"
1240 );
1241 println!(
1242 " ⚠️ 41-60: Average, needs improvement ✅ 21-40: Good, room for improvement"
1243 );
1244 println!(" 🌟 0-20: Excellent, keep it up");
1245 }
1246 }
1247
1248 fn print_improvement_suggestions_enhanced(&self, quality_score: &CodeQualityScore) {
1249 if self.i18n.lang == "zh-CN" {
1250 println!("{}", "💡 改进建议".bright_green().bold());
1251 } else {
1252 println!("{}", "💡 Improvement Suggestions".bright_green().bold());
1253 }
1254 println!("{}", "─".repeat(50).bright_black());
1255
1256 let suggestions = self.generate_improvement_suggestions_from_score(quality_score);
1257 for suggestion in suggestions {
1258 println!(" • {}", suggestion.green());
1259 }
1260 }
1261
1262 fn generate_improvement_suggestions_from_score(
1263 &self,
1264 quality_score: &CodeQualityScore,
1265 ) -> Vec<String> {
1266 let mut suggestions = Vec::new();
1267
1268 let mut sorted_categories: Vec<_> = quality_score.category_scores.iter().collect();
1270 sorted_categories.sort_by(|a, b| b.1.partial_cmp(a.1).unwrap_or(std::cmp::Ordering::Equal));
1271
1272 for (category, score) in sorted_categories.iter().take(3) {
1273 if **score > 60.0 {
1274 let suggestion = match (self.i18n.lang.as_str(), category.as_str()) {
1275 ("zh-CN", "naming") => "🏷️ 重点改进变量和函数命名 - 清晰的名称让代码自文档化",
1276 ("zh-CN", "complexity") => "🧩 将复杂函数分解为更小、更专注的函数",
1277 ("zh-CN", "duplication") => "🔄 消除重复代码,提取公共函数和模块",
1278 ("zh-CN", "rust-features") => "🦀 学习和应用 Rust 最佳实践,减少不必要的分配",
1279 (_, "naming") => "🏷️ Focus on improving variable and function naming - clear names make code self-documenting",
1280 (_, "complexity") => "🧩 Break down complex functions into smaller, focused functions",
1281 (_, "duplication") => "🔄 Eliminate code duplication, extract common functions and modules",
1282 (_, "rust-features") => "🦀 Learn and apply Rust best practices, reduce unnecessary allocations",
1283 _ => continue,
1284 };
1285 suggestions.push(suggestion.to_string());
1286 }
1287 }
1288
1289 if suggestions.is_empty() {
1290 if self.i18n.lang == "zh-CN" {
1291 suggestions.push("🎉 代码质量不错!继续保持良好的编程习惯".to_string());
1292 } else {
1293 suggestions.push(
1294 "🎉 Code quality looks good! Keep up the good programming habits".to_string(),
1295 );
1296 }
1297 }
1298
1299 suggestions
1300 }
1301
1302 fn print_old_summary_with_score(&self, issues: &[CodeIssue], quality_score: &CodeQualityScore) {
1303 self.print_scoring_breakdown(issues, quality_score);
1305 let _nuclear_count = issues
1306 .iter()
1307 .filter(|i| matches!(i.severity, Severity::Nuclear))
1308 .count();
1309 let _total_count = issues.len();
1310
1311 println!("{}", self.i18n.get("summary").bright_white().bold());
1312 println!("{}", "─".repeat(50).bright_black());
1313
1314 let score_summary = match quality_score.quality_level {
1316 crate::scoring::QualityLevel::Excellent => match self.i18n.lang.as_str() {
1317 "zh-CN" => format!(
1318 "🏆 代码质量优秀!评分: {:.1}/100",
1319 quality_score.total_score
1320 ),
1321 _ => format!(
1322 "🏆 Excellent code quality! Score: {:.1}/100",
1323 quality_score.total_score
1324 ),
1325 },
1326 crate::scoring::QualityLevel::Good => match self.i18n.lang.as_str() {
1327 "zh-CN" => format!(
1328 "👍 代码质量良好,评分: {:.1}/100",
1329 quality_score.total_score
1330 ),
1331 _ => format!(
1332 "👍 Good code quality, Score: {:.1}/100",
1333 quality_score.total_score
1334 ),
1335 },
1336 crate::scoring::QualityLevel::Average => match self.i18n.lang.as_str() {
1337 "zh-CN" => format!(
1338 "😐 代码质量一般,评分: {:.1}/100,还有改进空间",
1339 quality_score.total_score
1340 ),
1341 _ => format!(
1342 "😐 Average code quality, Score: {:.1}/100, room for improvement",
1343 quality_score.total_score
1344 ),
1345 },
1346 crate::scoring::QualityLevel::Poor => match self.i18n.lang.as_str() {
1347 "zh-CN" => format!(
1348 "😟 代码质量较差,评分: {:.1}/100,建议重构",
1349 quality_score.total_score
1350 ),
1351 _ => format!(
1352 "😟 Poor code quality, Score: {:.1}/100, refactoring recommended",
1353 quality_score.total_score
1354 ),
1355 },
1356 crate::scoring::QualityLevel::Terrible => match self.i18n.lang.as_str() {
1357 "zh-CN" => format!(
1358 "💀 代码质量糟糕,评分: {:.1}/100,急需重写",
1359 quality_score.total_score
1360 ),
1361 _ => format!(
1362 "💀 Terrible code quality, Score: {:.1}/100, rewrite urgently needed",
1363 quality_score.total_score
1364 ),
1365 },
1366 };
1367
1368 let score_color = match quality_score.quality_level {
1369 crate::scoring::QualityLevel::Excellent => score_summary.bright_green().bold(),
1370 crate::scoring::QualityLevel::Good => score_summary.green(),
1371 crate::scoring::QualityLevel::Average => score_summary.yellow(),
1372 crate::scoring::QualityLevel::Poor => score_summary.red(),
1373 crate::scoring::QualityLevel::Terrible => score_summary.bright_red().bold(),
1374 };
1375
1376 println!("{score_color}");
1377 println!();
1378
1379 let nuclear_count = issues
1380 .iter()
1381 .filter(|i| matches!(i.severity, Severity::Nuclear))
1382 .count();
1383 let total_count = issues.len();
1384
1385 let summary_message = if nuclear_count > 0 {
1386 if self.savage_mode {
1387 match self.i18n.lang.as_str() {
1388 "zh-CN" => "你的代码质量堪忧,建议重新学习编程基础 💀".to_string(),
1389 _ => "Your code quality is concerning, suggest learning programming basics again 💀".to_string(),
1390 }
1391 } else {
1392 match self.i18n.lang.as_str() {
1393 "zh-CN" => "发现了一些严重问题,建议优先修复核弹级问题 🔥".to_string(),
1394 _ => "Found some serious issues, suggest fixing nuclear problems first 🔥"
1395 .to_string(),
1396 }
1397 }
1398 } else if total_count > 10 {
1399 match self.i18n.lang.as_str() {
1400 "zh-CN" => "问题有点多,建议分批修复 📝".to_string(),
1401 _ => "Quite a few issues, suggest fixing them in batches 📝".to_string(),
1402 }
1403 } else {
1404 match self.i18n.lang.as_str() {
1405 "zh-CN" => "问题不多,稍微改进一下就好了 👍".to_string(),
1406 _ => "Not many issues, just need some minor improvements 👍".to_string(),
1407 }
1408 };
1409
1410 let color = if nuclear_count > 0 {
1411 summary_message.red().bold()
1412 } else if total_count > 10 {
1413 summary_message.yellow()
1414 } else {
1415 summary_message.green()
1416 };
1417
1418 println!("{color}");
1419 }
1420
1421 fn print_scoring_breakdown(&self, _issues: &[CodeIssue], quality_score: &CodeQualityScore) {
1422 let title = if self.i18n.lang == "zh-CN" {
1423 "📊 评分详情"
1424 } else {
1425 "📊 Scoring Details"
1426 };
1427
1428 println!("\n{}", title.bright_cyan().bold());
1429 println!("{}", "─".repeat(50).bright_black());
1430
1431 self.print_category_scores(&quality_score.category_scores);
1433
1434 self.print_weighted_calculation(&quality_score.category_scores, quality_score.total_score);
1436
1437 let scale_title = if self.i18n.lang == "zh-CN" {
1439 "\n📏 评分标准 (分数越高代码越烂):"
1440 } else {
1441 "\n📏 Scoring Scale (higher score = worse code):"
1442 };
1443
1444 println!("{}", scale_title.bright_yellow());
1445 if self.i18n.lang == "zh-CN" {
1446 println!(" 💀 81-100: 糟糕 🔥 61-80: 较差 ⚠️ 41-60: 一般");
1447 println!(" ✅ 21-40: 良好 🌟 0-20: 优秀");
1448 } else {
1449 println!(" 💀 81-100: Terrible 🔥 61-80: Poor ⚠️ 41-60: Average");
1450 println!(" ✅ 21-40: Good 🌟 0-20: Excellent");
1451 }
1452 }
1453
1454 fn calculate_base_score_for_display(
1455 &self,
1456 issues: &[CodeIssue],
1457 scorer: &crate::scoring::CodeScorer,
1458 ) -> f64 {
1459 let mut score = 0.0;
1460 for issue in issues {
1461 let rule_weight = scorer.rule_weights.get(&issue.rule_name).unwrap_or(&1.0);
1462 let severity_weight = match issue.severity {
1463 crate::analyzer::Severity::Nuclear => 10.0,
1464 crate::analyzer::Severity::Spicy => 5.0,
1465 crate::analyzer::Severity::Mild => 2.0,
1466 };
1467 score += rule_weight * severity_weight;
1468 }
1469 score
1470 }
1471
1472 fn calculate_density_penalty_for_display(
1473 &self,
1474 issue_count: usize,
1475 file_count: usize,
1476 total_lines: usize,
1477 ) -> f64 {
1478 if total_lines == 0 || file_count == 0 {
1479 return 0.0;
1480 }
1481
1482 let issues_per_1000_lines = (issue_count as f64 / total_lines as f64) * 1000.0;
1483 let issues_per_file = issue_count as f64 / file_count as f64;
1484
1485 let density_penalty = match issues_per_1000_lines {
1486 x if x > 50.0 => 25.0,
1487 x if x > 30.0 => 15.0,
1488 x if x > 20.0 => 10.0,
1489 x if x > 10.0 => 5.0,
1490 _ => 0.0,
1491 };
1492
1493 let file_penalty = match issues_per_file {
1494 x if x > 20.0 => 15.0,
1495 x if x > 10.0 => 10.0,
1496 x if x > 5.0 => 5.0,
1497 _ => 0.0,
1498 };
1499
1500 density_penalty + file_penalty
1501 }
1502
1503 fn calculate_severity_penalty_for_display(
1504 &self,
1505 distribution: &crate::scoring::SeverityDistribution,
1506 ) -> f64 {
1507 let mut penalty = 0.0;
1508
1509 if distribution.nuclear > 0 {
1510 penalty += 20.0 + (distribution.nuclear as f64 - 1.0) * 5.0;
1511 }
1512
1513 if distribution.spicy > 5 {
1514 penalty += (distribution.spicy as f64 - 5.0) * 2.0;
1515 }
1516
1517 if distribution.mild > 20 {
1518 penalty += (distribution.mild as f64 - 20.0) * 0.5;
1519 }
1520
1521 penalty
1522 }
1523
1524 fn print_category_scores(&self, category_scores: &std::collections::HashMap<String, f64>) {
1525 let title = if self.i18n.lang == "zh-CN" {
1526 "📋 分类评分详情:"
1527 } else {
1528 "📋 Category Scores:"
1529 };
1530
1531 println!("{}", title.bright_yellow());
1532
1533 let categories = [
1535 ("naming", "命名规范", "Naming", "🏷️"),
1536 ("complexity", "复杂度", "Complexity", "🧩"),
1537 ("duplication", "代码重复", "Duplication", "🔄"),
1538 ("rust-basics", "Rust基础", "Rust Basics", "🦀"),
1539 ("advanced-rust", "高级特性", "Advanced Rust", "⚡"),
1540 ("rust-features", "Rust功能", "Rust Features", "🚀"),
1541 ("structure", "代码结构", "Code Structure", "🏗️"),
1542 ];
1543
1544 for (category_key, zh_name, en_name, icon) in &categories {
1545 if let Some(score) = category_scores.get(*category_key) {
1546 let display_name = if self.i18n.lang == "zh-CN" {
1547 zh_name
1548 } else {
1549 en_name
1550 };
1551 let (status_icon, status_text) = self.get_score_status(*score);
1552
1553 let score_unit = if self.i18n.lang == "zh-CN" { "分" } else { "" };
1555 println!(
1556 " {} {} {}{} {}",
1557 status_icon,
1558 format!("{icon} {display_name}").bright_white(),
1559 format!("{score:.0}").bright_cyan(),
1560 score_unit,
1561 status_text.bright_black()
1562 );
1563
1564 if let Some(roast) = self.get_category_roast(category_key, *score) {
1566 println!(" 💬 {}", roast.bright_yellow().italic());
1567 }
1568 }
1569 }
1570 println!();
1571 }
1572
1573 fn get_score_status(&self, score: f64) -> (&str, &str) {
1574 match score as u32 {
1576 81..=100 => (
1577 "⚠",
1578 if self.i18n.lang == "zh-CN" {
1579 "糟糕,急需修复"
1580 } else {
1581 "Terrible, urgent fixes needed"
1582 },
1583 ),
1584 61..=80 => (
1585 "•",
1586 if self.i18n.lang == "zh-CN" {
1587 "较差,建议重构"
1588 } else {
1589 "Poor, refactoring recommended"
1590 },
1591 ),
1592 41..=60 => (
1593 "○",
1594 if self.i18n.lang == "zh-CN" {
1595 "一般,需要改进"
1596 } else {
1597 "Average, needs improvement"
1598 },
1599 ),
1600 21..=40 => (
1601 "✓",
1602 if self.i18n.lang == "zh-CN" {
1603 "良好,还有提升空间"
1604 } else {
1605 "Good, room for improvement"
1606 },
1607 ),
1608 _ => (
1609 "✓✓",
1610 if self.i18n.lang == "zh-CN" {
1611 "优秀,继续保持"
1612 } else {
1613 "Excellent, keep it up"
1614 },
1615 ),
1616 }
1617 }
1618
1619 fn get_category_roast(&self, category: &str, score: f64) -> Option<String> {
1620 if score < 60.0 {
1622 return None;
1623 }
1624
1625 let category_name = if self.i18n.lang == "zh-CN" {
1627 match category {
1628 "naming" => "命名规范",
1629 "complexity" => "复杂度",
1630 "duplication" => "代码重复",
1631 "rust-features" => "Rust功能",
1632 _ => category,
1633 }
1634 } else {
1635 match category {
1636 "naming" => "Naming",
1637 "complexity" => "Complexity",
1638 "duplication" => "Duplication",
1639 "rust-features" => "Rust Features",
1640 _ => category,
1641 }
1642 };
1643
1644 let timestamp = SystemTime::now()
1646 .duration_since(UNIX_EPOCH)
1647 .unwrap_or_default()
1648 .as_millis() as u64;
1649 let seed = timestamp + (score * 1000.0) as u64;
1650 let roast_message = self.get_random_roast(category_name, score, seed);
1651
1652 if roast_message.is_empty() {
1653 None
1654 } else {
1655 Some(roast_message)
1656 }
1657 }
1658
1659 fn print_weighted_calculation(
1660 &self,
1661 category_scores: &std::collections::HashMap<String, f64>,
1662 _total_score: f64,
1663 ) {
1664 let calc_title = if self.i18n.lang == "zh-CN" {
1665 "🧮 加权计算:"
1666 } else {
1667 "🧮 Weighted Calculation:"
1668 };
1669
1670 println!("{}", calc_title.bright_yellow());
1671
1672 let weights = [
1674 ("naming", 0.25, "命名规范", "Naming"),
1675 ("complexity", 0.20, "复杂度", "Complexity"),
1676 ("duplication", 0.15, "代码重复", "Duplication"),
1677 ("rust-basics", 0.15, "Rust基础", "Rust Basics"),
1678 ("advanced-rust", 0.10, "高级特性", "Advanced Rust"),
1679 ("rust-features", 0.10, "Rust功能", "Rust Features"),
1680 ("structure", 0.05, "代码结构", "Code Structure"),
1681 ];
1682
1683 let mut calculation_parts = Vec::new();
1684 let mut weighted_sum = 0.0;
1685
1686 for (category_key, weight, _zh_name, _en_name) in &weights {
1687 if let Some(score) = category_scores.get(*category_key) {
1688 let weighted_value = score * weight;
1689 weighted_sum += weighted_value;
1690 calculation_parts.push(format!("{score:.1}×{weight:.2}"));
1691 }
1692 }
1693
1694 if self.i18n.lang == "zh-CN" {
1695 println!(
1696 " 评分计算: ({}) ÷ 1.00 = {}",
1697 calculation_parts.join(" + ").bright_white(),
1698 format!("{weighted_sum:.1}").bright_green().bold()
1699 );
1700 } else {
1701 println!(
1702 " Score calculation: ({}) ÷ 1.00 = {}",
1703 calculation_parts.join(" + ").bright_white(),
1704 format!("{weighted_sum:.1}").bright_green().bold()
1705 );
1706 }
1707 }
1708
1709 fn print_detailed_base_score_breakdown(
1710 &self,
1711 issues: &[CodeIssue],
1712 scorer: &crate::scoring::CodeScorer,
1713 ) {
1714 let mut rule_scores: std::collections::HashMap<String, (usize, f64)> =
1716 std::collections::HashMap::new();
1717
1718 for issue in issues {
1719 let rule_weight = scorer.rule_weights.get(&issue.rule_name).unwrap_or(&1.0);
1720 let severity_weight = match issue.severity {
1721 crate::analyzer::Severity::Nuclear => 10.0,
1722 crate::analyzer::Severity::Spicy => 5.0,
1723 crate::analyzer::Severity::Mild => 2.0,
1724 };
1725 let issue_score = rule_weight * severity_weight;
1726
1727 let entry = rule_scores
1728 .entry(issue.rule_name.clone())
1729 .or_insert((0, 0.0));
1730 entry.0 += 1; entry.1 += issue_score; }
1733
1734 let mut sorted_rules: Vec<_> = rule_scores.into_iter().collect();
1736 sorted_rules.sort_by(|a, b| {
1737 b.1 .1
1738 .partial_cmp(&a.1 .1)
1739 .unwrap_or(std::cmp::Ordering::Equal)
1740 });
1741
1742 let breakdown_title = if self.i18n.lang == "zh-CN" {
1743 "🔍 基础分数详细计算:"
1744 } else {
1745 "🔍 Base score detailed calculation:"
1746 };
1747
1748 println!("{}", breakdown_title.bright_yellow());
1749
1750 for (rule_name, (count, total_score)) in sorted_rules.iter().take(10) {
1751 let rule_weight = scorer.rule_weights.get(rule_name).unwrap_or(&1.0);
1752
1753 let rule_display = match (self.i18n.lang.as_str(), rule_name.as_str()) {
1754 ("zh-CN", "terrible-naming") => "糟糕命名",
1755 ("zh-CN", "single-letter-variable") => "单字母变量",
1756 ("zh-CN", "deep-nesting") => "深度嵌套",
1757 ("zh-CN", "code-duplication") => "代码重复",
1758 ("zh-CN", "long-function") => "超长函数",
1759 ("zh-CN", "macro-abuse") => "宏滥用",
1760 (_, "terrible-naming") => "Terrible naming",
1761 (_, "single-letter-variable") => "Single letter vars",
1762 (_, "deep-nesting") => "Deep nesting",
1763 (_, "code-duplication") => "Code duplication",
1764 (_, "long-function") => "Long function",
1765 (_, "macro-abuse") => "Macro abuse",
1766 _ => rule_name,
1767 };
1768
1769 if self.i18n.lang == "zh-CN" {
1770 println!(
1771 " • {} × {} (权重{:.1}) = {}",
1772 format!("{count}").cyan(),
1773 rule_display.bright_white(),
1774 format!("{rule_weight:.1}").yellow(),
1775 format!("{total_score:.1}").bright_red()
1776 );
1777 } else {
1778 println!(
1779 " • {} × {} (weight {:.1}) = {}",
1780 format!("{count}").cyan(),
1781 rule_display.bright_white(),
1782 format!("{rule_weight:.1}").yellow(),
1783 format!("{total_score:.1}").bright_red()
1784 );
1785 }
1786 }
1787 println!();
1788 }
1789
1790 fn print_footer(&self, _issues: &[CodeIssue]) {
1791 println!();
1793 if self.i18n.lang == "zh-CN" {
1794 println!("{}", "继续努力,让代码变得更好!🚀".bright_cyan());
1795 } else {
1796 println!(
1797 "{}",
1798 "Keep working to make your code better! 🚀".bright_cyan()
1799 );
1800 }
1801 }
1802
1803 fn print_top_files(&self, issues: &[CodeIssue]) {
1804 if self.top_files == 0 {
1805 return;
1806 }
1807
1808 let mut file_issue_counts: HashMap<String, usize> = HashMap::new();
1809 for issue in issues {
1810 let file_name = issue
1811 .file_path
1812 .file_name()
1813 .unwrap_or_default()
1814 .to_string_lossy()
1815 .to_string();
1816 *file_issue_counts.entry(file_name).or_insert(0) += 1;
1817 }
1818
1819 let mut sorted_files: Vec<_> = file_issue_counts.into_iter().collect();
1820 sorted_files.sort_by(|a, b| b.1.cmp(&a.1));
1821
1822 if !sorted_files.is_empty() {
1823 println!("{}", self.i18n.get("top_files").bright_yellow().bold());
1824 println!("{}", "─".repeat(50).bright_black());
1825
1826 for (i, (file_name, count)) in sorted_files.iter().take(self.top_files).enumerate() {
1827 let rank = format!("{}.", i + 1);
1828 println!(
1829 " {} {} ({} issues)",
1830 rank.bright_white(),
1831 file_name.bright_blue(),
1832 count.to_string().red()
1833 );
1834 }
1835 println!();
1836 }
1837 }
1838
1839 fn print_detailed_analysis(&self, issues: &[CodeIssue]) {
1840 println!(
1841 "{}",
1842 self.i18n.get("detailed_analysis").bright_magenta().bold()
1843 );
1844 println!("{}", "─".repeat(50).bright_black());
1845
1846 let mut rule_stats: HashMap<String, usize> = HashMap::new();
1847 for issue in issues {
1848 *rule_stats.entry(issue.rule_name.clone()).or_insert(0) += 1;
1849 }
1850
1851 let rule_descriptions = match self.i18n.lang.as_str() {
1852 "zh-CN" => [
1853 ("terrible-naming", "糟糕的变量命名"),
1854 ("single-letter-variable", "单字母变量"),
1855 ("deep-nesting", "过度嵌套"),
1856 ("long-function", "超长函数"),
1857 ("unwrap-abuse", "unwrap() 滥用"),
1858 ("unnecessary-clone", "不必要的 clone()"),
1859 ]
1860 .iter()
1861 .cloned()
1862 .collect::<HashMap<_, _>>(),
1863 _ => [
1864 ("terrible-naming", "Terrible variable naming"),
1865 ("single-letter-variable", "Single letter variables"),
1866 ("deep-nesting", "Deep nesting"),
1867 ("long-function", "Long functions"),
1868 ("unwrap-abuse", "unwrap() abuse"),
1869 ("unnecessary-clone", "Unnecessary clone()"),
1870 ]
1871 .iter()
1872 .cloned()
1873 .collect::<HashMap<_, _>>(),
1874 };
1875
1876 for (rule_name, count) in rule_stats {
1877 let rule_name_str = rule_name.as_str();
1878
1879 let display_name = if self.i18n.lang == "zh-CN" {
1881 match rule_name_str {
1882 "terrible-naming" => "糟糕的变量命名",
1883 "single-letter-variable" => "单字母变量",
1884 "deep-nesting" => "过度嵌套",
1885 "long-function" => "超长函数",
1886 "unwrap-abuse" => "unwrap() 滥用",
1887 "unnecessary-clone" => "不必要的 clone()",
1888 "panic-abuse" => "panic 滥用",
1889 "god-function" => "上帝函数",
1890 "magic-number" => "魔法数字",
1891 "todo-comment" => "TODO 注释",
1892 "println-debugging" => "println 调试",
1893 "string-abuse" => "String 滥用",
1894 "vec-abuse" => "Vec 滥用",
1895 "iterator-abuse" => "迭代器滥用",
1896 "match-abuse" => "Match 滥用",
1897 "hungarian-notation" => "匈牙利命名法",
1898 "abbreviation-abuse" => "过度缩写",
1899 "meaningless-naming" => "无意义命名",
1900 "commented-code" => "被注释代码",
1901 "dead-code" => "死代码",
1902 "code-duplication" => "代码重复",
1903 "macro-abuse" => "宏滥用",
1904 _ => rule_name_str,
1905 }
1906 } else {
1907 rule_descriptions
1908 .get(rule_name_str)
1909 .unwrap_or(&rule_name_str)
1910 };
1911
1912 let issues_text = if self.i18n.lang == "zh-CN" {
1913 "个问题"
1914 } else {
1915 "issues"
1916 };
1917
1918 println!(
1919 " 📌 {}: {} {}",
1920 display_name.cyan(),
1921 count.to_string().yellow(),
1922 issues_text
1923 );
1924 }
1925 println!();
1926 }
1927
1928 fn print_markdown_report(&self, issues: &[CodeIssue]) {
1929 let total = issues.len();
1930 let nuclear = issues
1931 .iter()
1932 .filter(|i| matches!(i.severity, Severity::Nuclear))
1933 .count();
1934 let spicy = issues
1935 .iter()
1936 .filter(|i| matches!(i.severity, Severity::Spicy))
1937 .count();
1938 let mild = issues
1939 .iter()
1940 .filter(|i| matches!(i.severity, Severity::Mild))
1941 .count();
1942
1943 println!("# {}", self.i18n.get("title"));
1944 println!();
1945 println!("## {}", self.i18n.get("statistics"));
1946 println!();
1947 println!("| Severity | Count | Description |");
1948 println!("| --- | --- | --- |");
1949 println!(
1950 "| 🔥 Nuclear | {} | {} |",
1951 nuclear,
1952 self.i18n.get("nuclear_issues")
1953 );
1954 println!(
1955 "| 🌶️ Spicy | {} | {} |",
1956 spicy,
1957 self.i18n.get("spicy_issues")
1958 );
1959 println!("| 😐 Mild | {} | {} |", mild, self.i18n.get("mild_issues"));
1960 println!(
1961 "| **Total** | **{}** | **{}** |",
1962 total,
1963 self.i18n.get("total")
1964 );
1965 println!();
1966
1967 if self.verbose {
1968 println!("## {}", self.i18n.get("detailed_analysis"));
1969 println!();
1970
1971 let mut rule_stats: HashMap<String, usize> = HashMap::new();
1972 for issue in issues {
1973 *rule_stats.entry(issue.rule_name.clone()).or_insert(0) += 1;
1974 }
1975
1976 for (rule_name, count) in rule_stats {
1977 println!("- **{rule_name}**: {count} issues");
1978 }
1979 println!();
1980 }
1981
1982 println!("## Issues by File");
1983 println!();
1984
1985 let mut file_groups: BTreeMap<String, Vec<&CodeIssue>> = BTreeMap::new();
1986 for issue in issues {
1987 let file_name = issue
1988 .file_path
1989 .file_name()
1990 .unwrap_or_default()
1991 .to_string_lossy()
1992 .to_string();
1993 file_groups.entry(file_name).or_default().push(issue);
1994 }
1995
1996 for (file_name, file_issues) in file_groups {
1997 println!("### 📁 {file_name}");
1998 println!();
1999
2000 let issues_to_show = if self.max_issues_per_file > 0 {
2001 file_issues
2002 .into_iter()
2003 .take(self.max_issues_per_file)
2004 .collect::<Vec<_>>()
2005 } else {
2006 file_issues
2007 };
2008
2009 for issue in issues_to_show {
2010 let severity_icon = match issue.severity {
2011 Severity::Nuclear => "💥",
2012 Severity::Spicy => "🌶️",
2013 Severity::Mild => "😐",
2014 };
2015
2016 let messages = self.i18n.get_roast_messages(&issue.rule_name);
2017 let message = if !messages.is_empty() {
2018 messages[issue.line % messages.len()].clone()
2019 } else {
2020 issue.message.clone()
2021 };
2022
2023 println!(
2024 "- {} **Line {}:{}** - {}",
2025 severity_icon, issue.line, issue.column, message
2026 );
2027 }
2028 println!();
2029 }
2030
2031 println!("## {}", self.i18n.get("suggestions"));
2032 println!();
2033
2034 let rule_names: Vec<String> = issues
2035 .iter()
2036 .map(|issue| issue.rule_name.clone())
2037 .collect::<std::collections::HashSet<_>>()
2038 .into_iter()
2039 .collect();
2040
2041 let suggestions = self.i18n.get_suggestions(&rule_names);
2042 for suggestion in suggestions {
2043 println!("- {suggestion}");
2044 }
2045 }
2046
2047 fn print_issues_enhanced(
2048 &self,
2049 issues: &[CodeIssue],
2050 educational_advisor: Option<&EducationalAdvisor>,
2051 ) {
2052 let mut file_groups: HashMap<String, Vec<&CodeIssue>> = HashMap::new();
2053
2054 for issue in issues {
2055 let file_name = issue
2056 .file_path
2057 .file_name()
2058 .unwrap_or_default()
2059 .to_string_lossy()
2060 .to_string();
2061 file_groups.entry(file_name).or_default().push(issue);
2062 }
2063
2064 for (file_name, file_issues) in file_groups {
2065 println!("{} {}", "📁".bright_blue(), file_name.bright_blue().bold());
2066
2067 let mut rule_groups: BTreeMap<String, Vec<&CodeIssue>> = BTreeMap::new();
2069 for issue in &file_issues {
2070 rule_groups
2071 .entry(issue.rule_name.clone())
2072 .or_default()
2073 .push(issue);
2074 }
2075
2076 let mut sorted_rules: Vec<_> = rule_groups.into_iter().collect();
2078 sorted_rules.sort_by(|a, b| b.1.len().cmp(&a.1.len()));
2079
2080 for (rule_name, rule_issues) in sorted_rules {
2082 let count = rule_issues.len();
2083 let icon = self.get_rule_icon(&rule_name);
2084 let translated_name = if self.i18n.lang == "zh-CN" {
2085 self.translate_rule_display_name(&rule_name)
2086 } else {
2087 rule_name.replace("-", " ")
2088 };
2089
2090 if rule_name.contains("naming") {
2092 let examples: Vec<String> = rule_issues
2093 .iter()
2094 .take(5)
2095 .filter_map(|issue| {
2096 if let Some(start) = issue.message.find("'") {
2098 issue.message[start + 1..].find("'").map(|end| {
2099 issue.message[start + 1..start + 1 + end].to_string()
2100 })
2101 } else {
2102 None
2103 }
2104 })
2105 .collect();
2106
2107 if !examples.is_empty() {
2108 println!(
2109 " {} {}: {} ({})",
2110 icon,
2111 translated_name,
2112 count,
2113 examples.join(", ")
2114 );
2115 } else {
2116 println!(" {icon} {translated_name}: {count}");
2117 }
2118 } else if rule_name.contains("duplication") {
2119 if let Some(first_issue) = rule_issues.first() {
2121 if let Some(instances_start) = first_issue.message.find("发现 ") {
2122 if let Some(instances_end) =
2123 first_issue.message[instances_start..].find(" 个")
2124 {
2125 let instances_str = &first_issue.message
2126 [instances_start + 3..instances_start + instances_end];
2127 println!(" {icon} {translated_name}: {count} ({instances_str} instances)");
2128 } else {
2129 println!(" {icon} {translated_name}: {count}");
2130 }
2131 } else if let Some(instances_start) =
2132 first_issue.message.find("Similar code blocks detected: ")
2133 {
2134 if let Some(instances_end) =
2135 first_issue.message[instances_start..].find(" instances")
2136 {
2137 let instances_str = &first_issue.message
2138 [instances_start + 30..instances_start + instances_end];
2139 println!(" {icon} {translated_name}: {count} ({instances_str} instances)");
2140 } else {
2141 println!(" {icon} {translated_name}: {count}");
2142 }
2143 } else {
2144 println!(" {icon} {translated_name}: {count}");
2145 }
2146 } else {
2147 println!(" {icon} {translated_name}: {count}");
2148 }
2149 } else {
2150 println!(" {icon} {translated_name}: {count}");
2151 }
2152
2153 if let Some(advisor) = educational_advisor {
2155 if let Some(advice) = advisor.get_advice(&rule_name) {
2156 self.print_educational_advice(advice);
2157 }
2158 }
2159 }
2160 println!();
2161 }
2162 }
2163
2164 fn get_rule_icon(&self, rule_name: &str) -> &'static str {
2165 match rule_name {
2166 name if name.contains("naming") => "🏷️",
2167 name if name.contains("nesting") => "📦",
2168 name if name.contains("duplication") => "🔄",
2169 name if name.contains("function") => "⚠️",
2170 name if name.contains("unwrap") => "🛡️",
2171 name if name.contains("string") => "📝",
2172 name if name.contains("println") => "🔍",
2173 name if name.contains("magic") => "🔢",
2174 name if name.contains("panic") => "💥",
2175 name if name.contains("todo") => "📋",
2176 name if name.contains("import") => "📦",
2177 name if name.contains("file") => "📄",
2178 name if name.contains("module") => "🏗️",
2179 _ => "⚠️",
2180 }
2181 }
2182
2183 fn translate_rule_display_name(&self, rule_name: &str) -> String {
2184 match rule_name {
2185 "terrible-naming" => "变量命名问题".to_string(),
2186 "meaningless-naming" => "无意义命名问题".to_string(),
2187 "deep-nesting" => "嵌套深度问题".to_string(),
2188 "duplication" => "代码重复问题".to_string(),
2189 "code-duplication" => "代码重复问题".to_string(),
2190 "long-function" => "过长函数".to_string(),
2191 "god-function" => "上帝函数".to_string(),
2192 "unwrap-abuse" => "unwrap滥用".to_string(),
2193 "string-abuse" => "字符串滥用".to_string(),
2194 "println-debugging" => "println调试".to_string(),
2195 "magic-number" => "魔法数字".to_string(),
2196 "panic-abuse" => "panic滥用".to_string(),
2197 "todo-comment" => "TODO注释".to_string(),
2198 "file-too-long" => "文件过长".to_string(),
2199 "unordered-imports" => "导入混乱".to_string(),
2200 "deep-module-nesting" => "模块嵌套过深".to_string(),
2201 "macro-abuse" => "宏滥用".to_string(),
2202 "abbreviation-abuse" => "缩写滥用".to_string(),
2203 "hungarian-notation" => "匈牙利命名法".to_string(),
2204 "single-letter-variable" => "单字母变量".to_string(),
2205 "iterator-abuse" => "迭代器滥用".to_string(),
2206 "match-abuse" => "match滥用".to_string(),
2207 "vec-abuse" => "Vec滥用".to_string(),
2208 "dead-code" => "死代码".to_string(),
2209 "commented-code" => "注释代码".to_string(),
2210 "unnecessary-clone" => "不必要克隆".to_string(),
2211 "channel-abuse" => "通道滥用".to_string(),
2212 "async-abuse" => "异步滥用".to_string(),
2213 "dyn-trait-abuse" => "动态trait滥用".to_string(),
2214 "unsafe-abuse" => "unsafe滥用".to_string(),
2215 "ffi-abuse" => "FFI滥用".to_string(),
2216 "pattern-matching-abuse" => "模式匹配滥用".to_string(),
2217 "reference-abuse" => "引用滥用".to_string(),
2218 "box-abuse" => "Box滥用".to_string(),
2219 "slice-abuse" => "切片滥用".to_string(),
2220 "module-complexity" => "模块复杂度".to_string(),
2221 _ => rule_name.replace("-", " "),
2222 }
2223 }
2224
2225 fn print_educational_advice(&self, advice: &crate::educational::EducationalAdvice) {
2226 println!(" {}", "💡 Educational Advice:".bright_yellow().bold());
2227 println!(
2228 " {}",
2229 format!("Why it's bad: {}", advice.why_bad).yellow()
2230 );
2231 println!(
2232 " {}",
2233 format!("How to fix: {}", advice.how_to_fix).green()
2234 );
2235
2236 if let Some(ref bad_example) = advice.example_bad {
2237 println!(" {}", "❌ Bad example:".red());
2238 println!(" {}", format!(" {bad_example}").bright_black());
2239 }
2240
2241 if let Some(ref good_example) = advice.example_good {
2242 println!(" {}", "✅ Good example:".green());
2243 println!(" {}", format!(" {good_example}").bright_black());
2244 }
2245
2246 if let Some(ref tip) = advice.best_practice_tip {
2247 println!(" {}", format!("💡 Tip: {tip}").cyan());
2248 }
2249
2250 if let Some(ref link) = advice.rust_docs_link {
2251 println!(" {}", format!("📚 Learn more: {link}").blue());
2252 }
2253 println!();
2254 }
2255
2256 fn print_hall_of_shame(&self, hall_of_shame: &HallOfShame) {
2257 let stats = hall_of_shame.generate_shame_report();
2258
2259 println!();
2260 if self.i18n.lang == "zh-CN" {
2261 println!("{}", "🏆 问题最多的文件".bright_red().bold());
2262 } else {
2263 println!(
2264 "{}",
2265 "🏆 Hall of Shame - Worst Offenders".bright_red().bold()
2266 );
2267 }
2268 println!("{}", "─".repeat(60).bright_black());
2269
2270 if stats.hall_of_shame.is_empty() {
2271 if self.i18n.lang == "zh-CN" {
2272 println!("🎉 没有文件进入耻辱榜!干得好!");
2273 } else {
2274 println!("🎉 No files in the hall of shame! Great job!");
2275 }
2276 return;
2277 }
2278
2279 if self.i18n.lang == "zh-CN" {
2280 println!("📊 项目统计:");
2281 println!(
2282 " 分析文件数: {}",
2283 stats.total_files_analyzed.to_string().cyan()
2284 );
2285 println!(" 总问题数: {}", stats.total_issues.to_string().red());
2286 println!(
2287 " 垃圾密度: {:.2} 问题/1000行",
2288 stats.garbage_density.to_string().yellow()
2289 );
2290 } else {
2291 println!("📊 Project Statistics:");
2292 println!(
2293 " Files analyzed: {}",
2294 stats.total_files_analyzed.to_string().cyan()
2295 );
2296 println!(" Total issues: {}", stats.total_issues.to_string().red());
2297 println!(
2298 " Garbage density: {:.2} issues/1000 lines",
2299 stats.garbage_density.to_string().yellow()
2300 );
2301 }
2302 println!();
2303
2304 if self.i18n.lang == "zh-CN" {
2305 println!("🗑️ 问题最多的 {} 个文件:", stats.hall_of_shame.len().min(5));
2306 } else {
2307 println!("🗑️ Top {} Worst Files:", stats.hall_of_shame.len().min(5));
2308 }
2309
2310 for (i, entry) in stats.hall_of_shame.iter().take(5).enumerate() {
2311 let file_name = entry
2312 .file_path
2313 .file_name()
2314 .unwrap_or_default()
2315 .to_string_lossy();
2316
2317 if self.i18n.lang == "zh-CN" {
2318 println!(
2319 " {}. {} ({} 个问题)",
2320 (i + 1).to_string().bright_white(),
2321 file_name.bright_red().bold(),
2322 entry.total_issues.to_string().red()
2323 );
2324
2325 println!(
2326 " 💥 严重: {}, 🌶️ 中等: {}, 😐 轻微: {}",
2327 entry.nuclear_issues.to_string().red(),
2328 entry.spicy_issues.to_string().yellow(),
2329 entry.mild_issues.to_string().blue()
2330 );
2331 } else {
2332 println!(
2333 " {}. {} ({} issues)",
2334 (i + 1).to_string().bright_white(),
2335 file_name.bright_red().bold(),
2336 entry.total_issues.to_string().red()
2337 );
2338
2339 println!(
2340 " 💥 Nuclear: {}, 🌶️ Spicy: {}, 😐 Mild: {}",
2341 entry.nuclear_issues.to_string().red(),
2342 entry.spicy_issues.to_string().yellow(),
2343 entry.mild_issues.to_string().blue()
2344 );
2345 }
2346 }
2347 println!();
2348
2349 if self.i18n.lang == "zh-CN" {
2350 println!("🔥 最常见问题:");
2351 } else {
2352 println!("🔥 Most Common Issues:");
2353 }
2354
2355 for (i, pattern) in stats.most_common_patterns.iter().take(5).enumerate() {
2356 if self.i18n.lang == "zh-CN" {
2357 println!(
2358 " {}. {} ({} 次出现)",
2359 (i + 1).to_string().bright_white(),
2360 self.translate_rule_name(&pattern.rule_name).bright_yellow(),
2361 pattern.count.to_string().red()
2362 );
2363 } else {
2364 println!(
2365 " {}. {} ({} occurrences)",
2366 (i + 1).to_string().bright_white(),
2367 pattern.rule_name.bright_yellow(),
2368 pattern.count.to_string().red()
2369 );
2370 }
2371 }
2372 println!();
2373 }
2374
2375 fn translate_rule_name(&self, rule_name: &str) -> String {
2376 if self.i18n.lang != "zh-CN" {
2377 return rule_name.to_string();
2378 }
2379
2380 match rule_name {
2381 "terrible-naming" => "糟糕命名".to_string(),
2382 "meaningless-naming" => "无意义命名".to_string(),
2383 "magic-number" => "魔法数字".to_string(),
2384 "macro-abuse" => "宏滥用".to_string(),
2385 "deep-nesting" => "深层嵌套".to_string(),
2386 "unwrap-abuse" => "unwrap滥用".to_string(),
2387 "string-abuse" => "字符串滥用".to_string(),
2388 "println-debugging" => "println调试".to_string(),
2389 "long-function" => "过长函数".to_string(),
2390 "god-function" => "上帝函数".to_string(),
2391 "file-too-long" => "文件过长".to_string(),
2392 "unordered-imports" => "导入混乱".to_string(),
2393 "deep-module-nesting" => "模块嵌套过深".to_string(),
2394 _ => rule_name.to_string(),
2395 }
2396 }
2397
2398 fn print_improvement_suggestions(&self, hall_of_shame: &HallOfShame) {
2399 let suggestions = hall_of_shame.get_improvement_suggestions(&self.i18n.lang);
2400
2401 println!();
2402 if self.i18n.lang == "zh-CN" {
2403 println!("{}", "💡 改进建议".bright_green().bold());
2404 } else {
2405 println!("{}", "💡 Improvement Suggestions".bright_green().bold());
2406 }
2407 println!("{}", "─".repeat(50).bright_black());
2408
2409 for suggestion in suggestions {
2410 println!(" {}", suggestion.green());
2411 }
2412 println!();
2413 }
2414
2415 fn print_markdown_report_enhanced(
2416 &self,
2417 issues: &[CodeIssue],
2418 quality_score: &CodeQualityScore,
2419 educational_advisor: Option<&EducationalAdvisor>,
2420 hall_of_shame: Option<&HallOfShame>,
2421 show_suggestions: bool,
2422 ) {
2423 self.print_markdown_report(issues);
2425
2426 println!("## 🏆 Code Quality Score");
2428 println!();
2429 println!(
2430 "**Score**: {:.1}/100 {}",
2431 quality_score.total_score,
2432 quality_score.quality_level.emoji()
2433 );
2434 println!(
2435 "**Level**: {}",
2436 quality_score.quality_level.description(&self.i18n.lang)
2437 );
2438 println!();
2439
2440 if let Some(shame) = hall_of_shame {
2442 self.print_markdown_hall_of_shame(shame);
2443 }
2444
2445 if show_suggestions {
2447 if let Some(shame) = hall_of_shame {
2448 self.print_markdown_improvement_suggestions(shame);
2449 }
2450 }
2451
2452 if educational_advisor.is_some() {
2454 self.print_markdown_educational_section(issues, educational_advisor);
2455 }
2456 }
2457
2458 fn print_markdown_hall_of_shame(&self, hall_of_shame: &HallOfShame) {
2459 let stats = hall_of_shame.generate_shame_report();
2460
2461 println!("## 🏆 Hall of Shame");
2462 println!();
2463
2464 if stats.hall_of_shame.is_empty() {
2465 println!("🎉 No files in the hall of shame! Great job!");
2466 return;
2467 }
2468
2469 println!("### 📊 Project Statistics");
2470 println!();
2471 println!("| Metric | Value |");
2472 println!("| --- | --- |");
2473 println!("| Files analyzed | {} |", stats.total_files_analyzed);
2474 println!("| Total issues | {} |", stats.total_issues);
2475 println!(
2476 "| Garbage density | {:.2} issues/1000 lines |",
2477 stats.garbage_density
2478 );
2479 println!();
2480
2481 println!("### 🗑️ Worst Files");
2482 println!();
2483 println!("| Rank | File | Shame Score | Nuclear | Spicy | Mild |");
2484 println!("| --- | --- | --- | --- | --- | --- |");
2485
2486 for (i, entry) in stats.hall_of_shame.iter().take(5).enumerate() {
2487 let file_name = entry
2488 .file_path
2489 .file_name()
2490 .unwrap_or_default()
2491 .to_string_lossy();
2492
2493 println!(
2494 "| {} | {} | {:.1} | {} | {} | {} |",
2495 i + 1,
2496 file_name,
2497 entry.shame_score,
2498 entry.nuclear_issues,
2499 entry.spicy_issues,
2500 entry.mild_issues
2501 );
2502 }
2503 println!();
2504
2505 println!("### 🔥 Most Common Issues");
2506 println!();
2507 println!("| Rank | Issue Type | Count |");
2508 println!("| --- | --- | --- |");
2509
2510 for (i, pattern) in stats.most_common_patterns.iter().take(5).enumerate() {
2511 println!("| {} | {} | {} |", i + 1, pattern.rule_name, pattern.count);
2512 }
2513 println!();
2514 }
2515
2516 fn print_markdown_improvement_suggestions(&self, hall_of_shame: &HallOfShame) {
2517 let suggestions = hall_of_shame.get_improvement_suggestions(&self.i18n.lang);
2518
2519 if self.i18n.lang == "zh-CN" {
2520 println!("## 💡 改进建议");
2521 } else {
2522 println!("## 💡 Improvement Suggestions");
2523 }
2524 println!();
2525
2526 for suggestion in suggestions {
2527 println!("- {suggestion}");
2528 }
2529 println!();
2530 }
2531
2532 fn print_markdown_educational_section(
2533 &self,
2534 issues: &[CodeIssue],
2535 educational_advisor: Option<&EducationalAdvisor>,
2536 ) {
2537 if let Some(advisor) = educational_advisor {
2538 println!("## 📚 Educational Content");
2539 println!();
2540
2541 let mut rule_names: std::collections::HashSet<String> =
2543 std::collections::HashSet::new();
2544 for issue in issues {
2545 rule_names.insert(issue.rule_name.clone());
2546 }
2547
2548 for rule_name in rule_names {
2549 if let Some(advice) = advisor.get_advice(&rule_name) {
2550 println!("### 📖 {}", rule_name.replace("-", " "));
2551 println!();
2552 println!("**Why it's problematic:**");
2553 println!("{}", advice.why_bad);
2554 println!();
2555 println!("**How to fix:**");
2556 println!("{}", advice.how_to_fix);
2557 println!();
2558
2559 if let Some(ref bad_example) = advice.example_bad {
2560 println!("**❌ Bad example:**");
2561 println!("```rust");
2562 println!("{bad_example}");
2563 println!("```");
2564 println!();
2565 }
2566
2567 if let Some(ref good_example) = advice.example_good {
2568 println!("**✅ Good example:**");
2569 println!("```rust");
2570 println!("{good_example}");
2571 println!("```");
2572 println!();
2573 }
2574
2575 if let Some(ref tip) = advice.best_practice_tip {
2576 println!("**💡 Best Practice Tip:**");
2577 println!("{tip}");
2578 println!();
2579 }
2580
2581 if let Some(ref link) = advice.rust_docs_link {
2582 println!("**📚 Learn More:**");
2583 println!("[Rust Documentation]({link})");
2584 println!();
2585 }
2586 }
2587 }
2588 }
2589 }
2590}