diff --git a/Cargo.lock b/Cargo.lock index 491f1e3..e201d81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1736,6 +1736,7 @@ dependencies = [ name = "tabletbot" version = "1.0.0" dependencies = [ + "arrayvec", "hex", "octocrab", "poise", diff --git a/Cargo.toml b/Cargo.toml index bce738c..9fc0ecf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,4 @@ octocrab = "0.19.0" reqwest = "0.11.22" hex = "0.4.3" to-arraystring = "0.1.3" +arrayvec = "0.7.4" diff --git a/src/commands/mod.rs b/src/commands/mod.rs index f3c5166..73fd0e0 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -5,6 +5,9 @@ pub(crate) const ACCENT_COLOUR: Colour = Colour(0x8957e5); pub(crate) const OK_COLOUR: Colour = Colour(0x2ecc71); pub(crate) const ERROR_COLOUR: Colour = Colour(0xe74c3c); +use arrayvec::ArrayString; +use to_arraystring::ToArrayString; + use crate::{Context, Error}; use poise::serenity_prelude::{ @@ -64,20 +67,43 @@ pub async fn interaction_err(ctx: &serenity::Context, press: &ComponentInteracti let _ = press.create_response(ctx, builder).await; } -pub async fn paginate_lists( - ctx: poise::Context<'_, U, E>, +enum Kind { + Next, + Previous, +} + +impl Kind { + fn from_id(id: &str, ctx_id: &str) -> Option { + let this = match id.strip_prefix(ctx_id)? { + "next" => Self::Next, + "prev" => Self::Previous, + _ => return None, + }; + + Some(this) + } +} + +pub async fn paginate_lists( + ctx: crate::Context<'_>, pages: &[Vec<(String, String, bool)>], embed_title: &str, ) -> Result<(), Error> { - let ctx_id = ctx.id(); - let prev_button_id = format!("{ctx_id}prev"); - let next_button_id = format!("{ctx_id}next"); + let ctx_id = ctx.id().to_arraystring(); + + let mut prev_button_id = ArrayString::<24>::new(); + prev_button_id.push_str(&ctx_id); + prev_button_id.push_str("prev"); + + let mut next_button_id = ArrayString::<24>::new(); + next_button_id.push_str(&ctx_id); + next_button_id.push_str("next"); let colour = Colour::TEAL; let components = CreateActionRow::Buttons(vec![ - CreateButton::new(&prev_button_id).emoji('◀'), - CreateButton::new(&next_button_id).emoji('▶'), + CreateButton::new(&*prev_button_id).emoji('◀'), + CreateButton::new(&*next_button_id).emoji('▶'), ]); let mut current_page = 0; @@ -113,15 +139,17 @@ pub async fn paginate_lists( .timeout(std::time::Duration::from_secs(180)) .await { - if press.data.custom_id == next_button_id { - current_page += 1; - if current_page >= pages.len() { - current_page = 0; + match Kind::from_id(&press.data.custom_id, &ctx_id) { + Some(Kind::Next) => { + current_page += 1; + if current_page >= pages.len() { + current_page = 0; + } + } + Some(Kind::Previous) => { + current_page = current_page.checked_sub(1).unwrap_or(pages.len() - 1); } - } else if press.data.custom_id == prev_button_id { - current_page = current_page.checked_sub(1).unwrap_or(pages.len() - 1); - } else { - continue; + None => continue, } press diff --git a/src/events/issues/mod.rs b/src/events/issues/mod.rs index b0cc6b8..7be18ab 100644 --- a/src/events/issues/mod.rs +++ b/src/events/issues/mod.rs @@ -2,6 +2,7 @@ use std::time::Duration; use crate::{commands::interaction_err, structures::Embeddable, Data}; +use arrayvec::ArrayString; use poise::serenity_prelude::{ self as serenity, ButtonStyle, Context, CreateActionRow, CreateButton, CreateEmbed, CreateInteractionResponse, Message, Permissions, @@ -43,18 +44,26 @@ pub async fn message(data: &Data, ctx: &Context, message: &Message) { // we can avoid even a stack allocation! (thanks gnome) let ctx_id = message.id.get().to_arraystring(); - let remove_id = format!("{ctx_id}delete"); - let hide_body_id = format!("{ctx_id}hide_body"); + // we know the max size so we don't need to allocate. + // 20 + 6 + let mut remove_id = ArrayString::<26>::new(); + remove_id.push_str(&ctx_id); + remove_id.push_str("delete"); - let remove = CreateActionRow::Buttons(vec![CreateButton::new(&remove_id) + // 20 + 9 + let mut hide_body_id = ArrayString::<29>::new(); + hide_body_id.push_str(&ctx_id); + hide_body_id.push_str("hide_body"); + + let remove = CreateActionRow::Buttons(vec![CreateButton::new(&*remove_id) .label("delete") .style(ButtonStyle::Danger)]); let components = serenity::CreateActionRow::Buttons(vec![ - CreateButton::new(&remove_id) + CreateButton::new(&*remove_id) .label("delete") .style(ButtonStyle::Danger), - CreateButton::new(&hide_body_id).label("hide body"), + CreateButton::new(&*hide_body_id).label("hide body"), ]); let content: serenity::CreateMessage = serenity::CreateMessage::default() diff --git a/src/events/issues/utils.rs b/src/events/issues/utils.rs index fac1047..4d76dff 100644 --- a/src/events/issues/utils.rs +++ b/src/events/issues/utils.rs @@ -2,6 +2,7 @@ use octocrab::models::{issues::Issue, pulls::PullRequest}; use poise::serenity_prelude::{Colour, CreateEmbed, CreateEmbedAuthor}; use crate::structures::Embeddable; +use std::fmt::Write; const OPEN_COLOUR: Colour = Colour::new(0x238636); const RESOLVED_COLOUR: Colour = Colour::new(0x8957e5); @@ -47,9 +48,9 @@ impl Document for Issue { fn get_content(&self) -> String { let body = self.body.as_deref().unwrap_or_default(); - let mut description = String::default(); + let mut description = String::new(); for line in body.split('\n').take(15) { - description.push_str(&format!("{line}\n")); + writeln!(description, "{line}").unwrap(); } description.shrink_to(4096); @@ -123,9 +124,9 @@ impl Document for PullRequest { fn get_content(&self) -> String { let body = self.body.as_deref().unwrap_or_default(); - let mut content = String::default(); + let mut content = String::new(); for line in body.split('\n').take(15) { - content.push_str(&format!("{line}\n")); + writeln!(content, "{line}").unwrap(); } content.shrink_to(4096);