use super::context::{DebtSpecificInfo, FormatContext};
use super::dependencies::{filter_dependencies, format_function_reference};
use crate::formatting::{ColoredFormatter, FormattingConfig};
use crate::priority::score_formatter;
use colored::*;
#[allow(dead_code)]
pub(crate) struct FormattedSections {
pub header: String,
pub location: String,
pub context_dampening: Option<String>, pub action: String,
pub impact: String,
pub evidence: Option<String>, pub complexity: Option<String>,
pub pattern: Option<String>, pub coverage: Option<String>,
pub dependencies: Option<String>,
pub debt_specific: Option<String>,
pub rationale: String,
}
pub(crate) fn generate_formatted_sections(context: &FormatContext) -> FormattedSections {
FormattedSections {
header: format_header_section(context),
location: format_location_section(context),
context_dampening: format_context_dampening_section(context), action: format_action_section(context),
impact: format_impact_section(context),
evidence: format_evidence_section(context), complexity: format_complexity_section(context),
pattern: format_pattern_section(context), coverage: format_coverage_section(context),
dependencies: format_dependencies_section(context),
debt_specific: format_debt_specific_section(context),
rationale: format_rationale_section(context),
}
}
fn format_header_section(context: &FormatContext) -> String {
let separator = " • ".dimmed();
let (coverage_tag, severity_separator) = if let Some(ref coverage_info) = context.coverage_info
{
(
format!(
"{}{}",
separator,
coverage_info.tag.color(coverage_info.color).bold()
),
format!("{}", separator),
)
} else {
(String::new(), " ".to_string())
};
format!(
"#{} {}{}{}[{}]",
context.rank,
format!("SCORE: {}", score_formatter::format_score(context.score)).bright_yellow(),
coverage_tag,
severity_separator,
context
.severity_info
.label
.color(context.severity_info.color)
.bold()
)
}
fn format_location_section(context: &FormatContext) -> String {
format!(
"{} {}:{} {}()",
"├─ LOCATION:".bright_blue(),
context.location_info.file.display(),
context.location_info.line,
context.location_info.function.bright_green()
)
}
fn format_context_dampening_section(context: &FormatContext) -> Option<String> {
let dampening_info = context.context_info.as_ref()?;
let dampening_percentage = ((1.0 - dampening_info.multiplier) * 100.0) as i32;
Some(format!(
"{} {} ({}% dampening applied)",
"├─ CONTEXT:".bright_blue(),
dampening_info.description.bright_cyan(),
dampening_percentage
))
}
fn format_action_section(context: &FormatContext) -> String {
format!(
"{} {}",
"├─ RECOMMENDED ACTION:".bright_blue(),
context.action.bright_green().bold()
)
}
fn format_impact_section(context: &FormatContext) -> String {
format!(
"{} {}",
"├─ IMPACT:".bright_blue(),
super::format_impact(&context.impact).bright_cyan()
)
}
fn format_complexity_section(context: &FormatContext) -> Option<String> {
if !context.complexity_info.has_complexity {
return None;
}
if let Some(ref entropy) = context.complexity_info.entropy_analysis {
Some(format!(
"{} cyclomatic={} → {} (entropy-adjusted, factor: {:.2}), est_branches={}, cognitive={}, nesting={}, entropy={:.2}",
"├─ COMPLEXITY:".bright_blue(),
format!("{}", context.complexity_info.cyclomatic).yellow(),
format!("{}", entropy.adjusted_complexity).bright_green().bold(),
entropy.dampening_factor,
format!("{}", context.complexity_info.branch_count).yellow(),
format!("{}", context.complexity_info.cognitive).yellow(),
format!("{}", context.complexity_info.nesting).yellow(),
entropy.entropy_score
))
} else {
Some(format!(
"{} cyclomatic={}, est_branches={}, cognitive={}, nesting={}",
"├─ COMPLEXITY:".bright_blue(),
format!("{}", context.complexity_info.cyclomatic).yellow(),
format!("{}", context.complexity_info.branch_count).yellow(),
format!("{}", context.complexity_info.cognitive).yellow(),
format!("{}", context.complexity_info.nesting).yellow()
))
}
}
fn format_pattern_section(context: &FormatContext) -> Option<String> {
let pattern = context.pattern_info.as_ref()?;
let metrics_str = pattern
.display_metrics()
.iter()
.map(|s| s.as_str())
.collect::<Vec<_>>()
.join(", ");
Some(format!(
"{} {} {} ({}, confidence: {:.2})",
"├─ PATTERN:".bright_blue(),
pattern.icon(),
pattern.type_name().bright_magenta().bold(),
metrics_str.cyan(),
pattern.confidence
))
}
fn format_coverage_section(context: &FormatContext) -> Option<String> {
let coverage_info = context.coverage_info.as_ref()?;
if let Some(coverage_pct) = coverage_info.coverage_percentage {
Some(format!(
"{} {:.1}%",
"├─ COVERAGE:".bright_blue(),
coverage_pct
))
} else {
Some(format!(
"{} {}",
"├─ COVERAGE:".bright_blue(),
"no coverage data"
))
}
}
fn format_evidence_section(context: &FormatContext) -> Option<String> {
if !context.complexity_info.has_complexity {
return None;
}
let mut section = format!("{}", "├─ EVIDENCE:".bright_blue());
if context.complexity_info.cyclomatic > 0 {
section.push_str(&format!(
"\n│ {} Cyclomatic Complexity: {}",
"├─",
format!("{}", context.complexity_info.cyclomatic).yellow()
));
}
if context.complexity_info.cognitive > 0 {
section.push_str(&format!(
"\n│ {} Cognitive Complexity: {}",
"├─",
format!("{}", context.complexity_info.cognitive).yellow()
));
}
if context.complexity_info.branch_count > 0 {
section.push_str(&format!(
"\n│ {} Estimated Branches: {}",
"├─",
format!("{}", context.complexity_info.branch_count).yellow()
));
}
if context.complexity_info.nesting > 0 {
section.push_str(&format!(
"\n│ {} Nesting Depth: {}",
"└─",
format!("{}", context.complexity_info.nesting).yellow()
));
}
Some(section)
}
pub(crate) fn format_dependencies_section_with_config(
context: &FormatContext,
formatting_config: FormattingConfig,
) -> Option<String> {
let config = &formatting_config.caller_callee;
let _formatter = ColoredFormatter::new(formatting_config);
let filtered_callers = filter_dependencies(&context.dependency_info.upstream_callers, config);
let filtered_callees = filter_dependencies(&context.dependency_info.downstream_callees, config);
let mut section = format!("{}", "├─ DEPENDENCIES:".bright_blue());
if !filtered_callers.is_empty() {
let caller_count = filtered_callers.len();
let display_count = caller_count.min(config.max_callers);
section.push_str(&format!(
"\n{} {} {} ({}):",
"|", "|-", "Called by", caller_count
));
for caller in filtered_callers.iter().take(display_count) {
let formatted_caller = format_function_reference(caller);
section.push_str(&format!(
"\n{} {} {} {}",
"|",
"|",
"*",
formatted_caller.bright_cyan()
));
}
if caller_count > display_count {
section.push_str(&format!(
"\n{} {} {} (showing {} of {})",
"|", "|", "...", display_count, caller_count
));
}
} else {
section.push_str(&format!(
"\n{} {} {} No direct callers detected",
"|", "|-", "Called by"
));
}
if !filtered_callees.is_empty() {
let callee_count = filtered_callees.len();
let display_count = callee_count.min(config.max_callees);
section.push_str(&format!(
"\n{} {} {} ({}):",
"|", "+-", "Calls", callee_count
));
for callee in filtered_callees.iter().take(display_count) {
let formatted_callee = format_function_reference(callee);
section.push_str(&format!(
"\n{} {} {}",
"|",
"*",
formatted_callee.bright_magenta()
));
}
if callee_count > display_count {
section.push_str(&format!(
"\n{} {} (showing {} of {})",
"|", "...", display_count, callee_count
));
}
} else {
section.push_str(&format!(
"\n{} {} {} Calls no other functions",
"|", "+-", "Calls"
));
}
Some(section)
}
fn format_dependencies_section(context: &FormatContext) -> Option<String> {
format_dependencies_section_with_config(context, FormattingConfig::default())
}
fn format_debt_specific_section(context: &FormatContext) -> Option<String> {
match &context.debt_specific_info {
DebtSpecificInfo::DeadCode {
visibility,
usage_hints,
} => {
let mut section = format!(
"├─ VISIBILITY: {} function with no callers",
visibility.yellow()
);
for hint in usage_hints {
section.push_str(&format!("\n│ • {}", hint.bright_white()));
}
Some(section)
}
DebtSpecificInfo::Other => None,
}
}
fn format_rationale_section(context: &FormatContext) -> String {
let _formatter = ColoredFormatter::new(FormattingConfig::default());
format!(
"{} {}",
"├─ WHY THIS MATTERS:".bright_blue(),
context.rationale
)
}