diff options
Diffstat (limited to 'src/tui.rs')
| -rw-r--r-- | src/tui.rs | 534 |
1 files changed, 404 insertions, 130 deletions
@@ -1,5 +1,8 @@ use crossterm::{ - event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind, KeyModifiers, MouseButton, MouseEvent, MouseEventKind}, + event::{ + self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind, KeyModifiers, + MouseButton, MouseEvent, MouseEventKind, + }, execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; @@ -19,12 +22,14 @@ use crate::cli::Args; use crate::config::Config; use crate::config::FavoriteEntry; use crate::lookup; -use crate::tlds::{apply_top_tlds, get_tlds_or_default, list_names, default_list_name}; +use crate::tlds::{apply_top_tlds, default_list_name, get_tlds_or_default, list_names}; use crate::types::{DomainResult, DomainStatus, ErrorKind}; // note : this will be the worst shitshow of code you will probably have looked at in youre entire life -// it works and is somewhat stable but i didnt feel like sorting it into nice modules and all. -// have fun +// it works and is somewhat stable but i didnt feel like sorting it into nice modules and all mostly just relying +// on copy pasting shit where i need it +// +// have fun and may you forgive me for this extremly large ahh file. // names and labels const APP_NAME: &str = "hoardom"; @@ -36,7 +41,6 @@ const SEARCH_BUTTON_LABEL: &str = "[Search]"; const STOP_BUTTON_LABEL: &str = "[Stop](s)"; const CLEAR_BUTTON_LABEL: &str = "[Clear](C)"; - // Layout tuning constants const TOPBAR_HEIGHT: u16 = 1; const SEARCH_PANEL_HEIGHT: u16 = 3; @@ -88,8 +92,7 @@ fn export_favorites_txt(path: &Path, favorites: &[FavoriteEntry]) -> Result<(), .map_err(|e| format!("Failed to create export directory: {}", e))?; } let text: Vec<&str> = favorites.iter().map(|f| f.domain.as_str()).collect(); - std::fs::write(path, text.join("\n")) - .map_err(|e| format!("Failed to export favorites: {}", e)) + std::fs::write(path, text.join("\n")).map_err(|e| format!("Failed to export favorites: {}", e)) } fn export_results_csv(path: &Path, results: &[&DomainResult]) -> Result<(), String> { @@ -108,8 +111,7 @@ fn export_results_csv(path: &Path, results: &[&DomainResult]) -> Result<(), Stri )); } - std::fs::write(path, lines.join("\n")) - .map_err(|e| format!("Failed to export results: {}", e)) + std::fs::write(path, lines.join("\n")).map_err(|e| format!("Failed to export results: {}", e)) } #[derive(Debug, Clone, PartialEq)] @@ -125,7 +127,6 @@ enum ExportMode { } impl ExportMode { - fn default_file_name(self) -> &'static str { match self { ExportMode::FavoritesTxt => "hoardom-favorites.txt", @@ -229,7 +230,16 @@ struct PanelRects { } impl App { - fn new(args: &Args, config: &Config, config_path: PathBuf, can_save: bool, cache_path: Option<PathBuf>, force_refresh: bool, whois_overrides: crate::tlds::WhoisOverrides, noretry: Vec<ErrorKind>) -> Self { + fn new( + args: &Args, + config: &Config, + config_path: PathBuf, + can_save: bool, + cache_path: Option<PathBuf>, + force_refresh: bool, + whois_overrides: crate::tlds::WhoisOverrides, + noretry: Vec<ErrorKind>, + ) -> Self { let tld_list_name = args .tld_list .as_ref() @@ -271,7 +281,11 @@ impl App { verbose: args.verbose, delay: args.effective_delay(), retries: args.effective_retry(), - jobs: if args.jobs.is_some() { args.effective_jobs() } else { config.settings.jobs.max(1) }, + jobs: if args.jobs.is_some() { + args.effective_jobs() + } else { + config.settings.jobs.max(1) + }, panel_rects: PanelRects::default(), stream_rx: None, stream_task: None, @@ -421,7 +435,11 @@ impl App { last_res_export_path: self.last_res_export_path.clone(), top_tlds: self.top_tlds.clone().unwrap_or_default(), jobs: self.jobs, - noretry: self.noretry.iter().map(|k| k.to_config_str().to_string()).collect(), + noretry: self + .noretry + .iter() + .map(|k| k.to_config_str().to_string()) + .collect(), backups: self.backups_enabled, backup_count: self.backup_count, }, @@ -437,7 +455,9 @@ impl App { let d = domain.to_lowercase(); if !self.favorites.iter().any(|f| f.domain == d) { // check if we just looked this domain up - inherit its status - let status = self.results.iter() + let status = self + .results + .iter() .find(|(_, r)| r.full.to_lowercase() == d) .map(|(_, r)| r.status_str().to_string()) .unwrap_or_else(|| "unknown".to_string()); @@ -477,7 +497,11 @@ impl App { if self.show_unavailable { self.results.iter().map(|(_, r)| r).collect() } else { - self.results.iter().filter(|(_, r)| r.is_available()).map(|(_, r)| r).collect() + self.results + .iter() + .filter(|(_, r)| r.is_available()) + .map(|(_, r)| r) + .collect() } } @@ -598,7 +622,16 @@ pub async fn run_tui( let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; - let mut app = App::new(args, config, paths.config_file.clone(), paths.can_save, cache_file, force_refresh, whois_overrides, noretry); + let mut app = App::new( + args, + config, + paths.config_file.clone(), + paths.can_save, + cache_file, + force_refresh, + whois_overrides, + noretry, + ); if !paths.can_save { app.status_msg = Some("Warning: favorites and settings wont be saved".to_string()); @@ -608,10 +641,7 @@ pub async fn run_tui( // put the terminal back to normal if !args.no_mouse { - execute!( - terminal.backend_mut(), - DisableMouseCapture - )?; + execute!(terminal.backend_mut(), DisableMouseCapture)?; while event::poll(std::time::Duration::from_millis(0))? { let _ = event::read(); @@ -638,7 +668,10 @@ async fn run_app( } if let Some(popup) = app.export_popup.as_ref() { - if popup.close_at.is_some_and(|deadline| Instant::now() >= deadline) { + if popup + .close_at + .is_some_and(|deadline| Instant::now() >= deadline) + { app.export_popup = None; } } @@ -693,7 +726,9 @@ async fn run_app( Ok(lookup::StreamMsg::Result { result, .. }) => { // Update the matching favorite's status let domain_lower = result.full.to_lowercase(); - if let Some(fav) = app.favorites.iter_mut().find(|f| f.domain == domain_lower) { + if let Some(fav) = + app.favorites.iter_mut().find(|f| f.domain == domain_lower) + { let new_status = result.status_str().to_string(); if fav.status != new_status && fav.status != "unknown" { fav.changed = true; @@ -786,7 +821,11 @@ async fn run_app( app.dropdown = DropdownState::Closed; app.set_focus(match app.focus { Focus::Search => { - if app.show_notes_panel { Focus::Scratchpad } else { Focus::Results } + if app.show_notes_panel { + Focus::Scratchpad + } else { + Focus::Results + } } Focus::Scratchpad => Focus::Results, Focus::Results => Focus::Favorites, @@ -800,7 +839,11 @@ async fn run_app( Focus::Search => Focus::Settings, Focus::Scratchpad => Focus::Search, Focus::Results => { - if app.show_notes_panel { Focus::Scratchpad } else { Focus::Search } + if app.show_notes_panel { + Focus::Scratchpad + } else { + Focus::Search + } } Focus::Favorites => Focus::Results, Focus::Settings => Focus::Favorites, @@ -901,7 +944,11 @@ fn handle_export_popup_key(app: &mut App, key: KeyCode) { popup.selected_row = (popup.selected_row + 1) % 4; } KeyCode::BackTab | KeyCode::Up => { - popup.selected_row = if popup.selected_row == 0 { 3 } else { popup.selected_row - 1 }; + popup.selected_row = if popup.selected_row == 0 { + 3 + } else { + popup.selected_row - 1 + }; } KeyCode::Left => { if popup.selected_row == 0 { @@ -1057,7 +1104,9 @@ async fn handle_search_key(app: &mut App, key: KeyCode) { } } KeyCode::Delete => { - if app.cursor_pos < app.search_input.len() && app.search_input.is_char_boundary(app.cursor_pos) { + if app.cursor_pos < app.search_input.len() + && app.search_input.is_char_boundary(app.cursor_pos) + { app.search_input.remove(app.cursor_pos); } } @@ -1100,7 +1149,11 @@ fn handle_results_key(app: &mut App, key: KeyCode) { KeyCode::Up => { let i = match app.results_state.selected() { Some(i) => { - if i > 0 { i - 1 } else { 0 } + if i > 0 { + i - 1 + } else { + 0 + } } None => 0, }; @@ -1109,7 +1162,11 @@ fn handle_results_key(app: &mut App, key: KeyCode) { KeyCode::Down => { let i = match app.results_state.selected() { Some(i) => { - if i + 1 < len { i + 1 } else { i } + if i + 1 < len { + i + 1 + } else { + i + } } None => 0, }; @@ -1139,7 +1196,11 @@ fn handle_favorites_key(app: &mut App, key: KeyCode) { KeyCode::Up => { let i = match app.favorites_state.selected() { Some(i) => { - if i > 0 { i - 1 } else { 0 } + if i > 0 { + i - 1 + } else { + 0 + } } None => 0, }; @@ -1148,7 +1209,11 @@ fn handle_favorites_key(app: &mut App, key: KeyCode) { KeyCode::Down => { let i = match app.favorites_state.selected() { Some(i) => { - if i + 1 < len { i + 1 } else { i } + if i + 1 < len { + i + 1 + } else { + i + } } None => 0, }; @@ -1257,26 +1322,24 @@ fn handle_settings_key(app: &mut App, key: KeyCode) { _ => {} } } - KeyCode::Char(' ') => { - match app.settings_selected.unwrap_or(0) { - 1 => { - app.show_unavailable = !app.show_unavailable; - app.save_config(); - } - 2 => { - app.show_notes_panel = !app.show_notes_panel; - if !app.show_notes_panel && app.focus == Focus::Scratchpad { - app.set_focus(Focus::Results); - } - app.save_config(); - } - 3 => { - app.clear_on_search = !app.clear_on_search; - app.save_config(); + KeyCode::Char(' ') => match app.settings_selected.unwrap_or(0) { + 1 => { + app.show_unavailable = !app.show_unavailable; + app.save_config(); + } + 2 => { + app.show_notes_panel = !app.show_notes_panel; + if !app.show_notes_panel && app.focus == Focus::Scratchpad { + app.set_focus(Focus::Results); } - _ => {} + app.save_config(); } - } + 3 => { + app.clear_on_search = !app.clear_on_search; + app.save_config(); + } + _ => {} + }, KeyCode::Char('+') | KeyCode::Char('=') => { if app.settings_selected == Some(4) { app.jobs = if app.jobs >= 99 { 99 } else { app.jobs + 1 }; @@ -1502,7 +1565,11 @@ fn handle_mouse(app: &mut App, mouse: MouseEvent) { app.set_focus(Focus::Results); let visible_len = app.visible_results().len(); let content_start = results_rect.y + 1; - let progress_offset = if app.searching && app.search_progress.1 > 0 { 1 } else { 0 }; + let progress_offset = if app.searching && app.search_progress.1 > 0 { + 1 + } else { + 0 + }; let header_offset = if visible_len > 0 { 1 } else { 0 }; let list_start = content_start + progress_offset + header_offset; @@ -1653,14 +1720,18 @@ fn start_fav_check(app: &mut App) { app.checking_favorites = true; // Build a batch: each favorite is "name.tld" -> lookup (name, [tld]) - let batches: lookup::LookupBatch = app.favorites.iter().filter_map(|fav| { - let parts: Vec<&str> = fav.domain.splitn(2, '.').collect(); - if parts.len() == 2 { - Some((parts[0].to_string(), vec![parts[1].to_string()])) - } else { - None - } - }).collect(); + let batches: lookup::LookupBatch = app + .favorites + .iter() + .filter_map(|fav| { + let parts: Vec<&str> = fav.domain.splitn(2, '.').collect(); + if parts.len() == 2 { + Some((parts[0].to_string(), vec![parts[1].to_string()])) + } else { + None + } + }) + .collect(); if batches.is_empty() { app.checking_favorites = false; @@ -1793,7 +1864,10 @@ fn draw_ui(f: &mut Frame, app: &mut App) { .split(size); let content_area = main_chunks[1]; - let desired_sidebar = content_area.width.saturating_mul(SIDEBAR_TARGET_WIDTH_PERCENT) / 100; + let desired_sidebar = content_area + .width + .saturating_mul(SIDEBAR_TARGET_WIDTH_PERCENT) + / 100; let mut sidebar_width = clamp_panel_size(desired_sidebar, SIDEBAR_MIN_WIDTH, SIDEBAR_MAX_WIDTH) .min(content_area.width.saturating_sub(RESULTS_MIN_WIDTH)); if sidebar_width == 0 { @@ -1809,7 +1883,10 @@ fn draw_ui(f: &mut Frame, app: &mut App) { let (scratchpad_chunk, results_chunk) = if app.show_notes_panel { let center_width = content_area.width.saturating_sub(sidebar_width); - let desired_scratchpad = content_area.width.saturating_mul(SCRATCHPAD_TARGET_WIDTH_PERCENT) / 100; + let desired_scratchpad = content_area + .width + .saturating_mul(SCRATCHPAD_TARGET_WIDTH_PERCENT) + / 100; let mut scratchpad_width = clamp_panel_size( desired_scratchpad, SCRATCHPAD_MIN_WIDTH, @@ -1941,11 +2018,15 @@ fn draw_terminal_too_small(f: &mut Frame, area: Rect) { let text = vec![ Line::from(Span::styled( fit_cell_center("HELP ! HELP ! HELP !", content_width), - Style::default().fg(Color::White).add_modifier(Modifier::BOLD), + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD), )), Line::from(Span::styled( fit_cell_center("I AM BEING CRUSHED!", content_width), - Style::default().fg(Color::White).add_modifier(Modifier::BOLD), + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD), )), Line::from(fit_cell_center("", content_width)), Line::from(Span::styled( @@ -1953,21 +2034,31 @@ fn draw_terminal_too_small(f: &mut Frame, area: Rect) { Style::default().fg(Color::White), )), Line::from(Span::styled( - fit_cell_center(&format!("Need {}x{} of space", MIN_UI_WIDTH, MIN_UI_HEIGHT), content_width), + fit_cell_center( + &format!("Need {}x{} of space", MIN_UI_WIDTH, MIN_UI_HEIGHT), + content_width, + ), Style::default().fg(Color::White), )), Line::from(Span::styled( - fit_cell_center(&format!("Current: {}x{}", area.width, area.height), content_width), + fit_cell_center( + &format!("Current: {}x{}", area.width, area.height), + content_width, + ), Style::default().fg(Color::DarkGray), )), Line::from(fit_cell_center("", content_width)), Line::from(Span::styled( fit_cell_center("REFUSING TO WORK TILL YOU", content_width), - Style::default().fg(Color::White).add_modifier(Modifier::BOLD), + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD), )), Line::from(Span::styled( fit_cell_center("GIVE ME BACK MY SPACE! >:(", content_width), - Style::default().fg(Color::White).add_modifier(Modifier::BOLD), + Style::default() + .fg(Color::White) + .add_modifier(Modifier::BOLD), )), ]; @@ -1981,14 +2072,49 @@ fn draw_topbar(f: &mut Frame, area: Rect) { let right = format!("{} {}", EXPORT_BUTTON_LABEL, HELP_BUTTON_LABEL); let gap = width.saturating_sub(left.chars().count() + right.chars().count()); let paragraph = Paragraph::new(Line::from(vec![ - Span::styled(CLOSE_BUTTON_LABEL, Style::default().fg(Color::Red).bg(Color::Gray).add_modifier(Modifier::BOLD)), - Span::styled(format!(" {}", title), Style::default().fg(Color::White).bg(Color::Red).add_modifier(Modifier::BOLD)), - Span::styled(" ".repeat(gap), Style::default().bg(Color::Red).add_modifier(Modifier::BOLD)), - Span::styled(EXPORT_BUTTON_LABEL, Style::default().fg(Color::LightGreen).bg(Color::Red).add_modifier(Modifier::BOLD)), - Span::styled(" ", Style::default().bg(Color::Red).add_modifier(Modifier::BOLD)), - Span::styled(HELP_BUTTON_LABEL, Style::default().fg(Color::LightGreen).bg(Color::Red).add_modifier(Modifier::BOLD)), + Span::styled( + CLOSE_BUTTON_LABEL, + Style::default() + .fg(Color::Red) + .bg(Color::Gray) + .add_modifier(Modifier::BOLD), + ), + Span::styled( + format!(" {}", title), + Style::default() + .fg(Color::White) + .bg(Color::Red) + .add_modifier(Modifier::BOLD), + ), + Span::styled( + " ".repeat(gap), + Style::default().bg(Color::Red).add_modifier(Modifier::BOLD), + ), + Span::styled( + EXPORT_BUTTON_LABEL, + Style::default() + .fg(Color::LightGreen) + .bg(Color::Red) + .add_modifier(Modifier::BOLD), + ), + Span::styled( + " ", + Style::default().bg(Color::Red).add_modifier(Modifier::BOLD), + ), + Span::styled( + HELP_BUTTON_LABEL, + Style::default() + .fg(Color::LightGreen) + .bg(Color::Red) + .add_modifier(Modifier::BOLD), + ), ])) - .style(Style::default().fg(Color::White).bg(Color::Red).add_modifier(Modifier::BOLD)); + .style( + Style::default() + .fg(Color::White) + .bg(Color::Red) + .add_modifier(Modifier::BOLD), + ); f.render_widget(paragraph, area); } @@ -2000,22 +2126,60 @@ fn draw_help_overlay(f: &mut Frame, app: &mut App, area: Rect) { let text = vec![ Line::from(Span::styled(" ", Style::default().fg(Color::White))), Line::from(Span::styled("Global :", Style::default().fg(Color::White))), - Line::from(Span::styled("F1 or Help button Toggle this help", Style::default().fg(Color::White))), - Line::from(Span::styled("F2 or Export button Open export popup", Style::default().fg(Color::White))), - Line::from(Span::styled("Ctrl+C Quit the app", Style::default().fg(Color::White))), - Line::from(Span::styled("s Stop/cancel running search", Style::default().fg(Color::White))), - Line::from(Span::styled("Esc Clear selection or close help", Style::default().fg(Color::White))), - Line::from(Span::styled("Tab or Shift+Tab Move between panels", Style::default().fg(Color::White))), - Line::from(Span::styled("Up and Down arrows Navigate results", Style::default().fg(Color::White))), + Line::from(Span::styled( + "F1 or Help button Toggle this help", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "F2 or Export button Open export popup", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Ctrl+C Quit the app", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "s Stop/cancel running search", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Esc Clear selection or close help", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Tab or Shift+Tab Move between panels", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Up and Down arrows Navigate results", + Style::default().fg(Color::White), + )), Line::from(Span::styled(" ", Style::default().fg(Color::White))), - Line::from(Span::styled("Mouse Click Elements duh", Style::default().fg(Color::White))), - Line::from(Span::styled("Scrolling Scroll through elements (yea)", Style::default().fg(Color::White))), - + Line::from(Span::styled( + "Mouse Click Elements duh", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Scrolling Scroll through elements (yea)", + Style::default().fg(Color::White), + )), Line::from(Span::styled(" ", Style::default().fg(Color::White))), - Line::from(Span::styled("In Results :", Style::default().fg(Color::White))), - Line::from(Span::styled("Enter Add highlighted result to Favorites", Style::default().fg(Color::White))), - Line::from(Span::styled("In Favorites :", Style::default().fg(Color::White))), - Line::from(Span::styled("Backspace or Delete Remove focused favorite", Style::default().fg(Color::White))), + Line::from(Span::styled( + "In Results :", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Enter Add highlighted result to Favorites", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "In Favorites :", + Style::default().fg(Color::White), + )), + Line::from(Span::styled( + "Backspace or Delete Remove focused favorite", + Style::default().fg(Color::White), + )), ]; let block = Block::default() @@ -2066,7 +2230,10 @@ fn draw_export_popup(f: &mut Frame, app: &mut App, area: Rect) { style }; - let subtitle = fit_cell_center("Choose what to export and where to save it.", chunks[0].width as usize); + let subtitle = fit_cell_center( + "Choose what to export and where to save it.", + chunks[0].width as usize, + ); f.render_widget( Paragraph::new(subtitle).style(Style::default().fg(Color::DarkGray)), chunks[0], @@ -2118,9 +2285,13 @@ fn draw_export_popup(f: &mut Frame, app: &mut App, area: Rect) { ); let status_style = if popup_state.status_success { - Style::default().fg(Color::Green).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Green) + .add_modifier(Modifier::BOLD) } else if popup_state.confirm_overwrite { - Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Yellow) + .add_modifier(Modifier::BOLD) } else if popup_state.status.is_some() { Style::default().fg(Color::Red) } else { @@ -2132,7 +2303,6 @@ fn draw_export_popup(f: &mut Frame, app: &mut App, area: Rect) { chunks[3], ); - let cancel_label = "[Cancel]"; let button_gap = " "; let save_label = "[Save]"; @@ -2158,18 +2328,28 @@ fn draw_export_popup(f: &mut Frame, app: &mut App, area: Rect) { Span::styled( cancel_label, if popup_state.selected_row == 2 { - Style::default().fg(Color::Green).bg(Color::DarkGray).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Green) + .bg(Color::DarkGray) + .add_modifier(Modifier::BOLD) } else { - Style::default().fg(Color::Green).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Green) + .add_modifier(Modifier::BOLD) }, ), Span::raw(button_gap), Span::styled( save_label, if popup_state.selected_row == 3 { - Style::default().fg(Color::Green).bg(Color::DarkGray).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Green) + .bg(Color::DarkGray) + .add_modifier(Modifier::BOLD) } else { - Style::default().fg(Color::Green).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Green) + .add_modifier(Modifier::BOLD) }, ), ]); @@ -2207,7 +2387,12 @@ fn draw_results(f: &mut Frame, app: &mut App, area: Rect) { Some(d) => format!(" | Took: {:.1}s", d.as_secs_f64()), None => String::new(), }; - format!(" Results ({} available / {} total{}) ", avail, app.results.len(), duration_str) + format!( + " Results ({} available / {} total{}) ", + avail, + app.results.len(), + duration_str + ) }; let block = Block::default() @@ -2251,13 +2436,34 @@ fn draw_results(f: &mut Frame, app: &mut App, area: Rect) { fn draw_results_list(f: &mut Frame, app: &mut App, area: Rect) { let show_note_column = app.show_unavailable; let selected_idx = app.results_state.selected(); - let selected_bg = Color::Black; + let selected_bg = Color::Black; // collect visible results let visible_data: Vec<(String, String, String, DomainStatus)> = if app.show_unavailable { - app.results.iter().map(|(_, r)| (r.full.clone(), r.status_str().to_string(), r.note_str(), r.status.clone())).collect() + app.results + .iter() + .map(|(_, r)| { + ( + r.full.clone(), + r.status_str().to_string(), + r.note_str(), + r.status.clone(), + ) + }) + .collect() } else { - app.results.iter().filter(|(_, r)| r.is_available()).map(|(_, r)| (r.full.clone(), r.status_str().to_string(), r.note_str(), r.status.clone())).collect() + app.results + .iter() + .filter(|(_, r)| r.is_available()) + .map(|(_, r)| { + ( + r.full.clone(), + r.status_str().to_string(), + r.note_str(), + r.status.clone(), + ) + }) + .collect() }; if visible_data.is_empty() && !app.searching { @@ -2311,18 +2517,38 @@ fn draw_results_list(f: &mut Frame, app: &mut App, area: Rect) { if let Some(header_area) = header_area { let mut header_spans = vec![ - Span::styled(format!(" {}", fit_cell("Domain", domain_w)), Style::default().fg(Color::Gray).add_modifier(Modifier::BOLD)), + Span::styled( + format!(" {}", fit_cell("Domain", domain_w)), + Style::default() + .fg(Color::Gray) + .add_modifier(Modifier::BOLD), + ), Span::styled(" │ ", Style::default().fg(Color::DarkGray)), - Span::styled(fit_cell("Status", status_w), Style::default().fg(Color::Gray).add_modifier(Modifier::BOLD)), + Span::styled( + fit_cell("Status", status_w), + Style::default() + .fg(Color::Gray) + .add_modifier(Modifier::BOLD), + ), ]; if show_note_column { header_spans.push(Span::styled(" │ ", Style::default().fg(Color::DarkGray))); - header_spans.push(Span::styled(fit_cell("Details", note_w), Style::default().fg(Color::Gray).add_modifier(Modifier::BOLD))); + header_spans.push(Span::styled( + fit_cell("Details", note_w), + Style::default() + .fg(Color::Gray) + .add_modifier(Modifier::BOLD), + )); } header_spans.push(Span::styled(" │ ", Style::default().fg(Color::DarkGray))); - header_spans.push(Span::styled(" ✓ ", Style::default().fg(Color::Gray).add_modifier(Modifier::BOLD))); + header_spans.push(Span::styled( + " ✓ ", + Style::default() + .fg(Color::Gray) + .add_modifier(Modifier::BOLD), + )); f.render_widget(Paragraph::new(Line::from(header_spans)), header_area); } @@ -2361,22 +2587,40 @@ fn draw_results_list(f: &mut Frame, app: &mut App, area: Rect) { }; let mut spans = vec![ - Span::styled(format!(" {}", fit_cell(full, domain_w)), apply_bg(domain_style)), + Span::styled( + format!(" {}", fit_cell(full, domain_w)), + apply_bg(domain_style), + ), Span::styled(" \u{2502} ", apply_bg(Style::default().fg(Color::Gray))), Span::styled(fit_cell(status_str, status_w), apply_bg(status_style)), ]; if show_note_column { - spans.push(Span::styled(" \u{2502} ", apply_bg(Style::default().fg(Color::Gray)))); - spans.push(Span::styled(fit_cell(note, note_w), apply_bg(Style::default().fg(Color::White)))); + spans.push(Span::styled( + " \u{2502} ", + apply_bg(Style::default().fg(Color::Gray)), + )); + spans.push(Span::styled( + fit_cell(note, note_w), + apply_bg(Style::default().fg(Color::White)), + )); } - spans.push(Span::styled(" \u{2502} ", apply_bg(Style::default().fg(Color::Gray)))); + spans.push(Span::styled( + " \u{2502} ", + apply_bg(Style::default().fg(Color::Gray)), + )); spans.push(match status { - DomainStatus::Available => Span::styled(" ✓ ", apply_bg(Style::default().fg(Color::Green))), - DomainStatus::Registered { .. } => Span::styled(" ✗ ", apply_bg(Style::default().fg(Color::Red))), + DomainStatus::Available => { + Span::styled(" ✓ ", apply_bg(Style::default().fg(Color::Green))) + } + DomainStatus::Registered { .. } => { + Span::styled(" ✗ ", apply_bg(Style::default().fg(Color::Red))) + } DomainStatus::Error { kind, .. } => match kind { - ErrorKind::InvalidTld => Span::styled(" ? ", apply_bg(Style::default().fg(Color::Yellow))), + ErrorKind::InvalidTld => { + Span::styled(" ? ", apply_bg(Style::default().fg(Color::Yellow))) + } _ => Span::styled(" ! ", apply_bg(Style::default().fg(Color::Blue))), }, }); @@ -2553,8 +2797,7 @@ fn draw_scratchpad(f: &mut Frame, app: &mut App, area: Rect) { }; f.render_widget(block, area); f.render_widget( - Paragraph::new(text) - .style(Style::default().fg(Color::White)), + Paragraph::new(text).style(Style::default().fg(Color::White)), inner, ); @@ -2623,17 +2866,17 @@ fn draw_favorites(f: &mut Frame, app: &mut App, area: Rect) { }) .collect(); - let list = List::new(items) - .highlight_style( - Style::default() - .add_modifier(Modifier::REVERSED), - ); + let list = List::new(items).highlight_style(Style::default().add_modifier(Modifier::REVERSED)); f.render_widget(block, area); f.render_stateful_widget(list, list_area, &mut app.favorites_state); // Draw the check button at the bottom - let btn_label = if app.checking_favorites { "checking..." } else { "[c]heck all" }; + let btn_label = if app.checking_favorites { + "checking..." + } else { + "[c]heck all" + }; let btn_style = if app.checking_favorites { Style::default().fg(Color::DarkGray) } else { @@ -2688,13 +2931,17 @@ fn draw_settings(f: &mut Frame, app: &mut App, area: Rect) { }; let tld_row_style = if selected == Some(0) { - Style::default().bg(Color::DarkGray).add_modifier(Modifier::BOLD) + Style::default() + .bg(Color::DarkGray) + .add_modifier(Modifier::BOLD) } else { Style::default() }; let jobs_row_style = if selected == Some(4) { - Style::default().bg(Color::DarkGray).add_modifier(Modifier::BOLD) + Style::default() + .bg(Color::DarkGray) + .add_modifier(Modifier::BOLD) } else { Style::default() }; @@ -2801,23 +3048,44 @@ fn draw_search(f: &mut Frame, app: &mut App, area: Rect) { let cancel_enabled = app.searching; let search_style = if search_enabled { - Style::default().fg(Color::Black).bg(Color::Green).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Black) + .bg(Color::Green) + .add_modifier(Modifier::BOLD) } else { Style::default().fg(Color::DarkGray).bg(Color::Black) }; let stop_style = if cancel_enabled { - Style::default().fg(Color::Black).bg(Color::Yellow).add_modifier(Modifier::BOLD) + Style::default() + .fg(Color::Black) + .bg(Color::Yellow) + .add_modifier(Modifier::BOLD) } else { Style::default().fg(Color::DarkGray).bg(Color::Black) }; - let clear_style = Style::default().fg(Color::White).bg(Color::Red).add_modifier(Modifier::BOLD); + let clear_style = Style::default() + .fg(Color::White) + .bg(Color::Red) + .add_modifier(Modifier::BOLD); - f.render_widget(Paragraph::new(SEARCH_BUTTON_LABEL).style(search_style), chunks[1]); + f.render_widget( + Paragraph::new(SEARCH_BUTTON_LABEL).style(search_style), + chunks[1], + ); if app.clear_on_search { - f.render_widget(Paragraph::new(STOP_BUTTON_LABEL).style(stop_style), chunks[3]); + f.render_widget( + Paragraph::new(STOP_BUTTON_LABEL).style(stop_style), + chunks[3], + ); } else { - f.render_widget(Paragraph::new(STOP_BUTTON_LABEL).style(stop_style), chunks[3]); - f.render_widget(Paragraph::new(CLEAR_BUTTON_LABEL).style(clear_style), chunks[5]); + f.render_widget( + Paragraph::new(STOP_BUTTON_LABEL).style(stop_style), + chunks[3], + ); + f.render_widget( + Paragraph::new(CLEAR_BUTTON_LABEL).style(clear_style), + chunks[5], + ); } // show cursor in search bar when focused @@ -2836,7 +3104,10 @@ fn draw_dropdown(f: &mut Frame, app: &mut App, settings_area: Rect, selected: us let dropdown_full = Rect { x: settings_area.x + 1, y: settings_area.y + 1, - width: settings_area.width.saturating_sub(2).min(DROPDOWN_MAX_WIDTH), + width: settings_area + .width + .saturating_sub(2) + .min(DROPDOWN_MAX_WIDTH), height: (options.len() as u16 + 2).min(DROPDOWN_MAX_HEIGHT), }; @@ -2861,9 +3132,12 @@ fn draw_dropdown(f: &mut Frame, app: &mut App, settings_area: Rect, selected: us .title(" TLD List "); f.render_widget(Clear, dropdown_full); - let list = List::new(items) - .block(block) - .highlight_style(Style::default().fg(Color::White).bg(Color::Red).add_modifier(Modifier::BOLD)); + let list = List::new(items).block(block).highlight_style( + Style::default() + .fg(Color::White) + .bg(Color::Red) + .add_modifier(Modifier::BOLD), + ); let mut state = ListState::default(); state.select(Some(selected)); f.render_stateful_widget(list, dropdown_full, &mut state); |
