improved todo display

This commit is contained in:
2026-02-21 19:36:28 +01:00
parent e84e588836
commit 6111096a8c
3 changed files with 49 additions and 8 deletions

View File

@@ -90,20 +90,57 @@ impl WikiGraph {
println!("}}"); println!("}}");
} }
pub fn check_dead_links(&self) { pub fn check_dead_links(&self, reverse: bool) {
let mut found_issues = false; let mut missing_targets: HashMap<&String, Vec<&String>> = HashMap::new();
for (source, targets) in &self.edges { for (source, targets) in &self.edges {
for target in targets { for target in targets {
if !self.nodes.contains_key(target) { if !self.nodes.contains_key(target) {
println!("{} -> ❌ {}", source.bold().cyan(), target.red()); missing_targets.entry(target).or_default().push(source);
found_issues = true;
} }
} }
} }
if !found_issues { if missing_targets.is_empty() {
println!("{}", "✅ No broken links found!".green().bold()); println!("{}", "✅ No broken links found!".green().bold());
return;
}
let mut sorted_missing: Vec<_> = missing_targets.into_iter().collect();
sorted_missing.sort_by(|a, b| b.1.len().cmp(&a.1.len()).then_with(|| a.0.cmp(b.0)));
for (target, sources) in &sorted_missing {
let count = sources.len();
let sources_list = sources
.iter()
.map(|s| s.as_str())
.collect::<Vec<&str>>()
.join(", ")
.dimmed();
let target_styled = format!("{}", target).red().bold();
if reverse {
println!("{} ({}) -> {}", sources_list, count, target_styled);
} else {
println!("{} ({}) <- {}", target_styled, count, sources_list);
}
}
// Hint
println!();
if let Some((top_target, sources)) = sorted_missing.first() {
let count = sources.len();
println!(
"{}",
format!(
"Hint: Start working on '{}' as it has {} link{} pointing to it.",
top_target.red().bold(),
count,
if count > 1 { "s" } else { "" }
)
.italic()
);
} }
} }
} }

View File

@@ -32,7 +32,11 @@ pub enum Commands {
/// Output a DOT graph of the wiki connections /// Output a DOT graph of the wiki connections
Graph {}, Graph {},
/// List broken links /// List broken links
Todo {}, Todo {
/// Invert the display: "Sources -> Target" instead of "Target <- Sources"
#[arg(short, long)]
reverse: bool,
},
/// Manage wiki entries /// Manage wiki entries
Entry { Entry {
#[command(subcommand)] #[command(subcommand)]

View File

@@ -126,9 +126,9 @@ async fn main() -> anyhow::Result<()> {
let graph = analysis::WikiGraph::new(abs_path).await?; let graph = analysis::WikiGraph::new(abs_path).await?;
graph.print_dot(); graph.print_dot();
} }
Commands::Todo {} => { Commands::Todo { reverse } => {
let graph = analysis::WikiGraph::new(abs_path).await?; let graph = analysis::WikiGraph::new(abs_path).await?;
graph.check_dead_links(); graph.check_dead_links(reverse);
} }
Commands::Entry { cmd } => { Commands::Entry { cmd } => {
entry::handle(cmd, abs_path).await?; entry::handle(cmd, abs_path).await?;