aboutsummaryrefslogtreecommitdiff
path: root/src/output.rs
diff options
context:
space:
mode:
authorUMTS at Teleco <crt@teleco.ch>2026-03-08 07:30:34 +0100
committerUMTS at Teleco <crt@teleco.ch>2026-03-08 07:30:34 +0100
commit8623ef0ee74ff48a5ee24ee032f5b549f662f09d (patch)
tree7f11543d05cfe0e7bd5aaca31ff1d4c86a271fd0 /src/output.rs
goofy ah
Diffstat (limited to 'src/output.rs')
-rw-r--r--src/output.rs209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/output.rs b/src/output.rs
new file mode 100644
index 0000000..fe3b141
--- /dev/null
+++ b/src/output.rs
@@ -0,0 +1,209 @@
+use crate::types::{DomainResult, DomainStatus, ErrorKind};
+use colored::*;
+use std::io::Write;
+use std::path::PathBuf;
+
+pub fn print_available_table(results: &[DomainResult], no_color: bool, no_unicode: bool) {
+ let available: Vec<&DomainResult> = results.iter().filter(|r| r.is_available()).collect();
+
+ if available.is_empty() {
+ println!("No available domains found.");
+ return;
+ }
+
+ let max_len = available.iter().map(|r| r.full.len()).max().unwrap_or(20);
+ let width = max_len + 4; // padding
+
+ let title = "Available Domains";
+ let title_padded = format!("{:^width$}", title, width = width);
+
+ if no_unicode {
+ // ASCII box
+ let border = format!("+{}+", "-".repeat(width));
+ println!("{}", border);
+ if no_color {
+ println!("|{}|", title_padded);
+ } else {
+ println!("|{}|", title_padded.green());
+ }
+ println!("+{}+", "-".repeat(width));
+ for r in &available {
+ println!("| {:<pad$} |", r.full, pad = width - 2);
+ }
+ println!("{}", border);
+ } else {
+ // Unicode box
+ let top = format!("┌{}┐", "─".repeat(width));
+ let sep = format!("├{}┤", "─".repeat(width));
+ let bot = format!("└{}┘", "─".repeat(width));
+ println!("{}", top);
+ if no_color {
+ println!("│{}│", title_padded);
+ } else {
+ println!("│{}│", title_padded.green());
+ }
+ println!("{}", sep);
+ for r in &available {
+ println!("│ {:<pad$} │", r.full, pad = width - 2);
+ }
+ println!("{}", bot);
+ }
+}
+
+pub fn print_full_table(results: &[DomainResult], no_color: bool, no_unicode: bool) {
+ if results.is_empty() {
+ println!("No results.");
+ return;
+ }
+
+ // calc column widths
+ let domain_w = results.iter().map(|r| r.full.len()).max().unwrap_or(10).max(7);
+ let status_w = 10; // "registered" is the longest
+ let note_w = results.iter().map(|r| r.note_str().len()).max().unwrap_or(4).max(4);
+
+ let domain_col = domain_w + 2;
+ let status_col = status_w + 2;
+ let note_col = note_w + 2;
+
+ if no_unicode {
+ print_full_table_ascii(results, domain_col, status_col, note_col, no_color);
+ } else {
+ print_full_table_unicode(results, domain_col, status_col, note_col, no_color);
+ }
+}
+
+fn print_full_table_unicode(
+ results: &[DomainResult],
+ dc: usize,
+ sc: usize,
+ nc: usize,
+ no_color: bool,
+) {
+ let top = format!("┌{}┬{}┬{}┐", "─".repeat(dc), "─".repeat(sc), "─".repeat(nc));
+ let sep = format!("├{}┼{}┼{}┤", "─".repeat(dc), "─".repeat(sc), "─".repeat(nc));
+ let bot = format!("└{}┴{}┴{}┘", "─".repeat(dc), "─".repeat(sc), "─".repeat(nc));
+
+ println!("{}", top);
+ println!(
+ "│{:^dc$}│{:^sc$}│{:^nc$}│",
+ "Domains",
+ "Status",
+ "Note",
+ dc = dc,
+ sc = sc,
+ nc = nc,
+ );
+ println!("{}", sep);
+
+ for r in results {
+ let domain_str = format!(" {:<width$} ", r.full, width = dc - 2);
+ let status_str = format!(" {:<width$} ", r.status_str(), width = sc - 2);
+ let note_str = format!(" {:<width$} ", r.note_str(), width = nc - 2);
+
+ if no_color {
+ println!("│{}│{}│{}│", domain_str, status_str, note_str);
+ } else {
+ let colored_domain = color_domain(&domain_str, &r.status);
+ println!("│{}│{}│{}│", colored_domain, status_str, note_str);
+ }
+ }
+
+ println!("{}", bot);
+}
+
+fn print_full_table_ascii(
+ results: &[DomainResult],
+ dc: usize,
+ sc: usize,
+ nc: usize,
+ no_color: bool,
+) {
+ let border = format!("+{}+{}+{}+", "-".repeat(dc), "-".repeat(sc), "-".repeat(nc));
+
+ println!("{}", border);
+ println!(
+ "|{:^dc$}|{:^sc$}|{:^nc$}|",
+ "Domains",
+ "Status",
+ "Note",
+ dc = dc,
+ sc = sc,
+ nc = nc,
+ );
+ println!("{}", border);
+
+ for r in results {
+ let domain_str = format!(" {:<width$} ", r.full, width = dc - 2);
+ let status_str = format!(" {:<width$} ", r.status_str(), width = sc - 2);
+ let note_str = format!(" {:<width$} ", r.note_str(), width = nc - 2);
+
+ if no_color {
+ println!("|{}|{}|{}|", domain_str, status_str, note_str);
+ } else {
+ let colored_domain = color_domain(&domain_str, &r.status);
+ println!("|{}|{}|{}|", colored_domain, status_str, note_str);
+ }
+ }
+
+ println!("{}", border);
+}
+
+fn color_domain(domain: &str, status: &DomainStatus) -> ColoredString {
+ match status {
+ DomainStatus::Available => domain.green(),
+ DomainStatus::Registered { .. } => domain.red(),
+ DomainStatus::Error { kind, .. } => match kind {
+ ErrorKind::InvalidTld => domain.yellow(),
+ _ => domain.blue(),
+ },
+ }
+}
+
+pub fn print_csv(results: &[DomainResult]) {
+ println!("Domains, Status, Note");
+ for r in results {
+ println!("{}, {}, {}", r.full, r.status_str(), r.note_str());
+ }
+}
+
+pub fn write_csv_file(results: &[DomainResult], path: &PathBuf) -> Result<(), String> {
+ let mut file = std::fs::File::create(path)
+ .map_err(|e| format!("Could not create CSV file: {}", e))?;
+ writeln!(file, "Domains, Status, Note")
+ .map_err(|e| format!("Write error: {}", e))?;
+ for r in results {
+ writeln!(file, "{}, {}, {}", r.full, r.status_str(), r.note_str())
+ .map_err(|e| format!("Write error: {}", e))?;
+ }
+ Ok(())
+}
+
+pub fn print_errors(results: &[DomainResult], verbose: bool) {
+ for r in results {
+ if let DomainStatus::Error { kind, message } = &r.status {
+ match kind {
+ ErrorKind::InvalidTld => {
+ eprintln!("Error for {}, tld does not seem to exist", r.full);
+ }
+ _ => {
+ if verbose {
+ eprintln!("Error for {}, {} (raw: {})", r.full, message, message);
+ } else {
+ eprintln!(
+ "Error for {}, unknown error (enable verbose to see raw error)",
+ r.full
+ );
+ }
+ }
+ }
+ }
+ }
+}
+
+pub fn print_progress(current: usize, total: usize) {
+ let percent = (current as f64 / total as f64 * 100.0) as u32;
+ eprint!("\rParsing results : {}%", percent);
+ if current == total {
+ eprintln!("\rParsing results : Done ");
+ }
+}