use crate::{Context, Error}; use mysql_async::{from_row, params, prelude::Queryable, Conn}; use rand::seq::IteratorRandom; async fn autocomplete_command<'a>(ctx: Context<'_>, partial: &'a str) -> Vec { let mut conn = match ctx.data().database.get_conn().await { Ok(c) => c, Err(_) => return vec![], }; let stmt = conn.prep("SELECT sign FROM commands WHERE sign LIKE CONCAT('%', :partial, '%') AND enabled ORDER BY priority DESC, sign ASC LIMIT 25").await.unwrap(); let result = match conn.exec_iter(stmt, params! {partial}).await { Ok(blah) => blah .map_and_drop(|row| from_row::(row)) .await .unwrap_or_default(), Err(e) => { println!("Error autocomplete coms {}", e); vec!["Error getting commands".to_owned()] } }; result } pub async fn get_command(sign: &str, con: &mut Conn) -> Result, mysql_async::Error> { let a: Option = con.exec_first(r"SELECT response FROM commands WHERE sign = :sign and enabled order by priority desc limit 1", (sign,)).await?; Ok(a) } /// Run any of a collection of arbitrary commands #[poise::command(slash_command)] pub async fn coms( ctx: Context<'_>, #[description = "Which command to execute?"] #[autocomplete = "autocomplete_command"] command: String, ) -> Result<(), Error> { let conn: &mut Conn = &mut ctx.data().database.get_conn().await?; match get_command(&command, conn).await? { None => { ctx.say(format!("Command `{}` not found", command)).await?; } Some(com) => { ctx.say(sky(&com)).await?; } } Ok(()) } fn sky(input: &str) -> String { let result: String = input.to_string(); let mut rng = rand::thread_rng(); loop { match sky_open(&result) { None => return result, Some((left, end)) => { match sky_closed(&end) { None => return result, Some((mid, right)) => { return sky(&format!( "{}{}{}", left, mid.split('|').choose(&mut rng).unwrap(), right )) } }; } } } } fn sky_open(input: &str) -> Option<(String, String)> { match input.rsplit_once('{') { None => return None, Some((left, end)) => { if left.ends_with('\\') { match sky_open(left) { None => return None, Some((left, right)) => { let mut end: String = end.to_string(); end.push('{'); end.push_str(right.as_str()); return Some((left.to_owned(), end)); } }; } else { return Some((left.to_owned(), end.to_owned())); } } } } fn sky_closed(input: &str) -> Option<(String, String)> { match input.split_once('}') { None => return None, Some((left, end)) => { if left.ends_with('\\') { match sky_closed(end) { None => return None, Some((mid, right)) => { let mut start: String = left.to_string(); start.push('}'); start.push_str(mid.as_str()); return Some((start, right.to_owned())); } }; } else { return Some((left.to_owned(), end.to_owned())); } } } }