Small Rust scripts

Add colors, epoch, into_qr, and port_check

+336
+141
colors.rs
··· 1 + #!/usr/bin/env -S cargo +nightly -Zscript 2 + 3 + --- 4 + [package] 5 + edition = "2024" 6 + [dependencies] 7 + argh = "0.1" 8 + owo-colors = "4" 9 + --- 10 + 11 + use argh::FromArgs; 12 + use owo_colors::{AnsiColors, OwoColorize, Rgb, XtermColors}; 13 + 14 + #[derive(FromArgs)] 15 + #[argh(description = "Display terminal color capabilities")] 16 + struct App { 17 + #[argh(switch, description = "show only basic 16 ANSI colors.")] 18 + basic: bool, 19 + 20 + #[argh(switch, description = "show 256 color palette.")] 21 + palette: bool, 22 + 23 + #[argh(switch, description = "show true color (24-bit) gradient.")] 24 + truecolor: bool, 25 + } 26 + 27 + const BLOCK: &str = " "; 28 + 29 + fn main() { 30 + let app: App = argh::from_env(); 31 + let show_all = !app.basic && !app.palette && !app.truecolor; 32 + 33 + if show_all || app.basic { 34 + print_basic_colors(); 35 + } 36 + if show_all || app.palette { 37 + print_256_palette(); 38 + } 39 + if show_all || app.truecolor { 40 + print_truecolor(); 41 + } 42 + } 43 + 44 + fn print_basic_colors() { 45 + use AnsiColors::*; 46 + const COLORS: [AnsiColors; 8] = [Black, Red, Green, Yellow, Blue, Magenta, Cyan, White]; 47 + 48 + println!("ANSI 16 Colors:\n"); 49 + 50 + print!(" Normal: "); 51 + for color in COLORS { 52 + print!("{}", BLOCK.on_color(color)); 53 + } 54 + println!(); 55 + 56 + print!(" Bright: "); 57 + for color in COLORS { 58 + print!("{}", BLOCK.on_color(color).bold()); 59 + } 60 + println!("\n"); 61 + } 62 + 63 + fn print_256_palette() { 64 + println!("256 Color Palette:\n"); 65 + 66 + // Standard 0-15 67 + print!(" "); 68 + for i in 0..16u8 { 69 + print!("{}", BLOCK.on_color(XtermColors::from(i))); 70 + } 71 + println!("\n"); 72 + 73 + // Color cube 16-231 74 + for row in 0..6u8 { 75 + print!(" "); 76 + for green in 0..6u8 { 77 + for red in 0..6u8 { 78 + let color = 16 + row * 36 + green * 6 + red; 79 + print!("{}", BLOCK.on_color(XtermColors::from(color))); 80 + } 81 + print!(" "); 82 + } 83 + println!(); 84 + } 85 + println!(); 86 + 87 + // Grayscale 232-255 88 + print!(" "); 89 + for i in 232..=255u8 { 90 + print!("{}", BLOCK.on_color(XtermColors::from(i))); 91 + } 92 + println!("\n"); 93 + } 94 + 95 + fn print_truecolor() { 96 + println!("True Color (24-bit) Test:\n"); 97 + 98 + // Red gradient 99 + print!(" "); 100 + for i in 0..64u8 { 101 + print!("{}", " ".on_color(Rgb(i * 4, 0, 0))); 102 + } 103 + println!(); 104 + 105 + // Green gradient 106 + print!(" "); 107 + for i in 0..64u8 { 108 + print!("{}", " ".on_color(Rgb(0, i * 4, 0))); 109 + } 110 + println!(); 111 + 112 + // Blue gradient 113 + print!(" "); 114 + for i in 0..64u8 { 115 + print!("{}", " ".on_color(Rgb(0, 0, i * 4))); 116 + } 117 + println!(); 118 + 119 + // Rainbow 120 + print!(" "); 121 + for i in 0..64 { 122 + let (r, g, b) = hsv_to_rgb(i as f32 / 64.0 * 360.0); 123 + print!("{}", " ".on_color(Rgb(r, g, b))); 124 + } 125 + println!("\n"); 126 + 127 + println!(" If gradients appear smooth, your terminal supports true color.\n"); 128 + } 129 + 130 + fn hsv_to_rgb(h: f32) -> (u8, u8, u8) { 131 + let x = 1.0 - ((h / 60.0) % 2.0 - 1.0).abs(); 132 + let (r, g, b) = match h as u32 { 133 + 0..=59 => (1.0, x, 0.0), 134 + 60..=119 => (x, 1.0, 0.0), 135 + 120..=179 => (0.0, 1.0, x), 136 + 180..=239 => (0.0, x, 1.0), 137 + 240..=299 => (x, 0.0, 1.0), 138 + _ => (1.0, 0.0, x), 139 + }; 140 + ((r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8) 141 + }
+77
epoch.rs
··· 1 + #!/usr/bin/env -S cargo +nightly -Zscript 2 + 3 + --- 4 + [package] 5 + edition = "2024" 6 + [dependencies] 7 + argh = "0.1" 8 + chrono = "0.4" 9 + --- 10 + 11 + use argh::FromArgs; 12 + use chrono::{DateTime, Local, NaiveDateTime, TimeZone, Utc}; 13 + 14 + #[derive(FromArgs)] 15 + #[argh(description = "Convert between Unix timestamps and human-readable dates.")] 16 + struct App { 17 + #[argh(switch, description = "use UTC instead of local time.")] 18 + utc: bool, 19 + 20 + #[argh(switch, description = "treat timestamp as milliseconds.")] 21 + millis: bool, 22 + 23 + #[argh(positional, description = "timestamp, date (YYYY-MM-DD HH:MM:SS), or 'now'.")] 24 + input: Option<String>, 25 + } 26 + 27 + fn main() { 28 + let app: App = argh::from_env(); 29 + let input = app.input.as_deref().unwrap_or("now"); 30 + 31 + match input { 32 + "now" => { 33 + let now = Utc::now(); 34 + if app.millis { 35 + println!("{}", now.timestamp_millis()); 36 + } else { 37 + println!("{}", now.timestamp()); 38 + } 39 + } 40 + s if s.chars().all(|c| c.is_ascii_digit()) => { 41 + let ts: i64 = s.parse().expect("invalid timestamp"); 42 + let dt = if app.millis { 43 + Utc.timestamp_millis_opt(ts).single() 44 + } else { 45 + Utc.timestamp_opt(ts, 0).single() 46 + } 47 + .expect("invalid timestamp"); 48 + 49 + if app.utc { 50 + println!("{}", dt.format("%Y-%m-%d %H:%M:%S UTC")); 51 + } else { 52 + let local: DateTime<Local> = dt.into(); 53 + println!("{}", local.format("%Y-%m-%d %H:%M:%S")); 54 + } 55 + } 56 + s => { 57 + let naive = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") 58 + .expect("expected format: YYYY-MM-DD HH:MM:SS"); 59 + 60 + let dt: DateTime<Utc> = if app.utc { 61 + Utc.from_utc_datetime(&naive) 62 + } else { 63 + Local 64 + .from_local_datetime(&naive) 65 + .single() 66 + .expect("invalid local time") 67 + .into() 68 + }; 69 + 70 + if app.millis { 71 + println!("{}", dt.timestamp_millis()); 72 + } else { 73 + println!("{}", dt.timestamp()); 74 + } 75 + } 76 + } 77 + }
+70
into_qr.rs
··· 1 + #!/usr/bin/env -S cargo +nightly -Zscript 2 + 3 + --- 4 + [package] 5 + edition = "2024" 6 + [dependencies] 7 + argh = "0.1" 8 + qrcode = "0.14.1" 9 + --- 10 + 11 + use std::fs; 12 + use std::path::PathBuf; 13 + 14 + use argh::FromArgs; 15 + 16 + use qrcode::QrCode; 17 + use qrcode::render::unicode::Dense1x2; 18 + 19 + #[derive(FromArgs)] 20 + #[argh(description = "Create a QR code from anything.")] 21 + struct App { 22 + #[argh(option, description = "module width in characters.", default = "1")] 23 + scale: u32, 24 + 25 + #[argh(switch, description = "disable quiet zone border.")] 26 + no_quiet_zone: bool, 27 + 28 + #[argh(subcommand)] 29 + command: Command, 30 + } 31 + 32 + #[derive(FromArgs)] 33 + #[argh(subcommand)] 34 + enum Command { 35 + File(FileCmd), 36 + Raw(RawCmd), 37 + } 38 + 39 + #[derive(FromArgs)] 40 + #[argh(subcommand, name = "file")] 41 + #[argh(description = "Read from a file")] 42 + struct FileCmd { 43 + #[argh(positional)] 44 + path: PathBuf, 45 + } 46 + 47 + #[derive(FromArgs)] 48 + #[argh(subcommand, name = "raw")] 49 + #[argh(description = "Use raw input")] 50 + struct RawCmd { 51 + #[argh(positional)] 52 + input: String, 53 + } 54 + 55 + fn main() { 56 + let app: App = argh::from_env(); 57 + 58 + let data = match app.command { 59 + Command::File(FileCmd { path }) => fs::read_to_string(path).expect("could not read file"), 60 + Command::Raw(RawCmd { input }) => input, 61 + }; 62 + 63 + let code = QrCode::new(data.into_bytes()).expect("could not create qr code"); 64 + let rendered = code 65 + .render::<Dense1x2>() 66 + .module_dimensions(app.scale, app.scale) 67 + .quiet_zone(!app.no_quiet_zone) 68 + .build(); 69 + println!("{}", rendered); 70 + }
+48
port_check.rs
··· 1 + #!/usr/bin/env -S cargo +nightly -Zscript 2 + 3 + --- 4 + [package] 5 + edition = "2024" 6 + [dependencies] 7 + argh = "0.1" 8 + --- 9 + 10 + use std::net::{TcpStream, ToSocketAddrs}; 11 + use std::process; 12 + use std::time::Duration; 13 + 14 + use argh::FromArgs; 15 + 16 + #[derive(FromArgs)] 17 + #[argh(description = "Check if a TCP port is reachable.")] 18 + struct App { 19 + #[argh(option, description = "timeout in seconds.", default = "5")] 20 + timeout: u64, 21 + 22 + #[argh(positional, description = "host to connect to.")] 23 + host: String, 24 + 25 + #[argh(positional, description = "port to connect to.")] 26 + port: u16, 27 + } 28 + 29 + fn main() { 30 + let app: App = argh::from_env(); 31 + let address = format!("{}:{}", app.host, app.port); 32 + let timeout = Duration::from_secs(app.timeout); 33 + 34 + let addrs: Vec<_> = address 35 + .to_socket_addrs() 36 + .expect("failed to resolve address") 37 + .collect(); 38 + 39 + for addr in &addrs { 40 + if TcpStream::connect_timeout(addr, timeout).is_ok() { 41 + println!("reachable"); 42 + process::exit(0); 43 + } 44 + } 45 + 46 + println!("unreachable"); 47 + process::exit(1); 48 + }