use crate::git::{display_name, find_repos};
use crate::history::{self, CommitMatch};
use colored::Colorize;
use rayon::prelude::*;
use std::path::{Path, PathBuf};
#[derive(clap::Args)]
pub struct Args {
pub pattern: String,
#[arg(short, long)]
pub recursive: bool,
#[arg(short, long, default_value_t = 20)]
pub limit: usize,
}
pub fn run(args: Args) {
println!("{} {}\n", "Searching for:".dimmed(), args.pattern.bold());
let repos: Vec<PathBuf> = if args.recursive {
find_repos(Path::new("."), 10)
} else {
vec![PathBuf::from(".")]
};
let terms = vec![args.pattern.clone()];
let mut results: Vec<(String, String)> = repos
.par_iter()
.filter_map(|repo| {
let name = display_name(repo);
let repo_str = repo.to_str()?;
let commits = history::pickaxe(repo_str, &terms, false);
if commits.is_empty() {
return None;
}
Some((
name.clone(),
format_repo(&name, repo_str, &commits, args.limit),
))
})
.collect();
if results.is_empty() {
println!("{}", "No matches found.".dimmed());
return;
}
results.sort_by(|a, b| a.0.cmp(&b.0));
for (_, output) in results {
print!("{}", output);
}
}
fn format_repo(name: &str, repo: &str, commits: &[CommitMatch], limit: usize) -> String {
let total = commits.len();
let mut out = String::new();
out.push_str(&format!(
"{} {}\n",
format!("━━━ {}", name).cyan().bold(),
format!("{} commit(s)", total).dimmed()
));
for commit in commits.iter().take(limit) {
out.push_str(&format!(
"\n {} {}\n",
format!("▸ {}", commit.short).yellow(),
commit.subject
));
let branches = history::branches_for(repo, &commit.full);
if !branches.is_empty() {
out.push_str(&format!(
" {} {}\n",
"on".magenta(),
branches.join(", ").dimmed()
));
}
for file in &commit.files {
out.push_str(&format!(" {}\n", file.path.blue().bold()));
if file.lines.is_empty() {
out.push_str(&format!(
" {}\n",
"(binary or no visible diff)".dimmed()
));
}
for (is_addition, line) in &file.lines {
if *is_addition {
out.push_str(&format!(" {}\n", line.green()));
} else {
out.push_str(&format!(" {}\n", line.red()));
}
}
}
}
if total > limit {
out.push_str(&format!(
"\n {}\n",
format!("↳ {} more - use -l {} to see all", total - limit, total).dimmed()
));
}
out.push('\n');
out
}