use super::{DecompositionContext, DecompositionSuggestion};
#[cfg(test)]
#[path = "note_tests.rs"]
mod tests;
const MAX_SUGGESTIONS: usize = 3;
const MAX_METHODS_PER_SUGGESTION: usize = 3;
#[must_use]
pub fn format_diagnostic_note(
context: &DecompositionContext,
suggestions: &[DecompositionSuggestion],
) -> Option<String> {
if suggestions.is_empty() {
return None;
}
let visible_suggestions = &suggestions[..suggestions.len().min(MAX_SUGGESTIONS)];
let mut lines = vec![format!(
"Potential decomposition for `{}`:",
context.subject_name()
)];
lines.extend(visible_suggestions.iter().map(render_suggestion_line));
let omitted_suggestions = suggestions.len().saturating_sub(MAX_SUGGESTIONS);
if omitted_suggestions > 0 {
lines.push(format_omitted_areas_line(omitted_suggestions));
}
Some(lines.join("\n"))
}
fn format_omitted_areas_line(omitted_suggestions: usize) -> String {
let noun = if omitted_suggestions == 1 {
"area"
} else {
"areas"
};
format!("{omitted_suggestions} more {noun} omitted")
}
fn render_suggestion_line(suggestion: &DecompositionSuggestion) -> String {
let rendered_methods = render_method_list(suggestion.methods());
format!(
"- [{}] {} for {}",
suggestion.label(),
suggestion.extraction_kind(),
rendered_methods
)
}
fn render_method_list(methods: &[String]) -> String {
let visible_methods = &methods[..methods.len().min(MAX_METHODS_PER_SUGGESTION)];
let mut rendered = visible_methods
.iter()
.map(|method| format!("`{method}`"))
.collect::<Vec<_>>()
.join(", ");
let omitted_methods = methods.len().saturating_sub(MAX_METHODS_PER_SUGGESTION);
if omitted_methods > 0 {
rendered.push_str(&format!(", +{omitted_methods} more methods"));
}
rendered
}