diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 0f70da0..f3c5166 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -28,7 +28,7 @@ pub async fn respond_embed(ctx: &Context<'_>, embed: CreateEmbed, ephemeral: boo let result = ctx.send(builder).await; if let Err(e) = result { - println!("Failed to respond: {}", e) + println!("Failed to respond: {e}"); } } @@ -70,8 +70,8 @@ pub async fn paginate_lists( embed_title: &str, ) -> Result<(), Error> { let ctx_id = ctx.id(); - let prev_button_id = format!("{}prev", ctx_id); - let next_button_id = format!("{}next", ctx_id); + let prev_button_id = format!("{ctx_id}prev"); + let next_button_id = format!("{ctx_id}next"); let colour = Colour::TEAL; diff --git a/src/commands/snippets.rs b/src/commands/snippets.rs index 3b95e51..0f634dd 100644 --- a/src/commands/snippets.rs +++ b/src/commands/snippets.rs @@ -9,6 +9,7 @@ use poise::serenity_prelude::{ CreateInteractionResponseMessage, }; +#[allow(clippy::unused_async)] async fn autocomplete_snippet<'a>( ctx: Context<'a>, partial: &'a str, @@ -40,7 +41,7 @@ pub async fn snippet( id: String, ) -> Result<(), Error> { // Lazily get snippet because this is a prefix command too. - if let Some(snippet) = get_snippet_lazy(&ctx, &id).await { + if let Some(snippet) = get_snippet_lazy(&ctx, &id) { let embed = snippet.embed(); respond_embed(&ctx, embed, false).await; @@ -78,6 +79,7 @@ pub async fn create_snippet( }; println!("New snippet created '{}: {}'", snippet.id, snippet.title); + let mut embed = snippet.embed(); embed = embed.colour(super::OK_COLOUR); @@ -111,7 +113,7 @@ pub async fn edit_snippet( #[description = "The snippet's title"] title: Option, #[description = "The snippet's content"] content: Option, ) -> Result<(), Error> { - match get_snippet_lazy(&ctx, &id).await { + match get_snippet_lazy(&ctx, &id) { Some(mut snippet) => { if let Some(title) = title { snippet.title = title; @@ -134,7 +136,7 @@ pub async fn edit_snippet( None => { let title = &"Failed to edit snippet"; let content = &&format!("The snippet '{id}' does not exist"); - respond_err(&ctx, title, content).await + respond_err(&ctx, title, content).await; } }; @@ -149,14 +151,14 @@ pub async fn remove_snippet( #[description = "The snippet's id"] id: String, ) -> Result<(), Error> { - match get_snippet_lazy(&ctx, &id).await { + match get_snippet_lazy(&ctx, &id) { Some(snippet) => { remove_snippet_confirm(&ctx, &snippet).await?; } None => { let title = &"Failed to remove snippet"; let content = &&format!("The snippet '{id}' does not exist"); - respond_err(&ctx, title, content).await + respond_err(&ctx, title, content).await; } } @@ -190,7 +192,7 @@ pub async fn list_snippets(ctx: Context<'_>) -> Result<(), Error> { .map(|snippet| (snippet.id.clone(), snippet.title.clone(), true)) .collect::>() .chunks(25) - .map(|chunk| chunk.to_vec()) + .map(<[(String, String, bool)]>::to_vec) .collect(); super::paginate_lists(ctx, &pages, "Snippets").await?; @@ -209,7 +211,7 @@ pub async fn export_snippet( #[description = "The snippet's id"] id: String, ) -> Result<(), Error> { - match get_snippet_lazy(&ctx, &id).await { + match get_snippet_lazy(&ctx, &id) { Some(snippet) => { let attachment = CreateAttachment::bytes(snippet.content.replace('\n', r"\n"), "snippet.txt"); @@ -221,7 +223,7 @@ pub async fn export_snippet( None => { let title = &"Failed to export snippet"; let content = &&format!("The snippet '{id}' does not exist"); - respond_err(&ctx, title, content).await + respond_err(&ctx, title, content).await; } } @@ -239,7 +241,7 @@ impl Embeddable for Snippet { } // Exact matches the snippet id and name. -async fn _get_snippet(ctx: &Context<'_>, id: &str) -> Option { +fn _get_snippet(ctx: &Context<'_>, id: &str) -> Option { let data = ctx.data(); let rwlock_guard = data.state.read().unwrap(); @@ -251,7 +253,7 @@ async fn _get_snippet(ctx: &Context<'_>, id: &str) -> Option { } // Matches the snippet by checking if its starts with the id and name. -async fn get_snippet_lazy(ctx: &Context<'_>, id: &str) -> Option { +fn get_snippet_lazy(ctx: &Context<'_>, id: &str) -> Option { let data = ctx.data(); let rwlock_guard = data.state.read().unwrap(); @@ -262,7 +264,7 @@ async fn get_snippet_lazy(ctx: &Context<'_>, id: &str) -> Option { .cloned() } -async fn rm_snippet(ctx: &Context<'_>, snippet: &Snippet) { +fn rm_snippet(ctx: &Context<'_>, snippet: &Snippet) { let data = ctx.data(); let mut rwlock_guard = data.state.write().unwrap(); @@ -281,8 +283,8 @@ async fn remove_snippet_confirm(ctx: &Context<'_>, snippet: &Snippet) -> Result< let snippet_embed = snippet.embed(); let ctx_id = ctx.id(); - let delete_id = format!("{}cancel", ctx_id); - let cancel_id = format!("{}delete", ctx_id); + let delete_id = format!("{ctx_id}cancel"); + let cancel_id = format!("{ctx_id}delete"); let components = serenity::CreateActionRow::Buttons(vec![ serenity::CreateButton::new(&cancel_id).label("Cancel"), @@ -322,7 +324,7 @@ async fn handle_delete( snippet: &Snippet, interaction: serenity::ComponentInteraction, ) -> Result<(), Error> { - rm_snippet(ctx, snippet).await; + rm_snippet(ctx, snippet); interaction .create_response( ctx, diff --git a/src/commands/utils.rs b/src/commands/utils.rs index 133ef42..9f5617b 100644 --- a/src/commands/utils.rs +++ b/src/commands/utils.rs @@ -8,6 +8,7 @@ use poise::serenity_prelude::{Colour, CreateEmbed, CreateEmbedFooter, EditMessag use regex::Regex; use serenity::futures::{self, Stream, StreamExt}; +#[allow(clippy::unused_async)] async fn autocomplete_key<'a>( ctx: Context<'a>, partial: &'a str, @@ -63,7 +64,7 @@ pub async fn embed( match url.parse::() { Ok(_) => { if title.is_some() { - embed = embed.url(url) + embed = embed.url(url); } else { respond_err( &ctx, @@ -76,7 +77,7 @@ pub async fn embed( } Err(e) => { let title = "Invalid url provided"; - let content = &format!("The url '{}' is not a valid url: {}", url, e); + let content = &format!("The url '{url}' is not a valid url: {e}"); respond_err(&ctx, title, content).await; return Ok(()); } @@ -229,7 +230,7 @@ pub async fn edit_embed( let builder = EditMessage::default().embed(embedb); match msg_clone.edit(ctx, builder).await { - Ok(_) => { + Ok(()) => { respond_ok( &ctx, "Successfully edited embed", @@ -239,7 +240,7 @@ pub async fn edit_embed( } Err(error) => { // Better error handling later. - respond_err(&ctx, "Error while handling message!", &format!("{}", error)).await + respond_err(&ctx, "Error while handling message!", &format!("{error}")).await; } } } else { @@ -313,7 +314,7 @@ pub async fn add_repo( respond_ok( &ctx, "Successfully added issue token", - &format!("{}: {}/{}", key, owner, repository), + &format!("{key}: {owner}/{repository}"), ) .await; @@ -333,16 +334,16 @@ pub async fn remove_repo( // impl a solution directly into the types? // not sure why I have to do this, it won't settle otherwise. - let key_str = format!("The repository with the key '{}' has been removed", key); - match get_repo_details(&ctx, &key).await { + let key_str = format!("The repository with the key '{key}' has been removed"); + match get_repo_details(&ctx, &key) { Some(_) => { - rm_repo(&ctx, &key).await; + rm_repo(&ctx, &key); respond_ok(&ctx, "Successfully removed repository!", &key_str).await; } None => { let title = "Failure to find repository"; - let content = format!("The key '{}' does not exist.", key); + let content = format!("The key '{key}' does not exist."); respond_err(&ctx, title, &content).await; } }; @@ -383,7 +384,7 @@ pub async fn list_repos(ctx: Context<'_>) -> Result<(), Error> { }) .collect::>() .chunks(25) - .map(|chunk| chunk.to_vec()) + .map(<[(String, String, bool)]>::to_vec) .collect(); super::paginate_lists(ctx, &pages, "Repositories").await?; @@ -391,14 +392,14 @@ pub async fn list_repos(ctx: Context<'_>) -> Result<(), Error> { Ok(()) } -async fn get_repo_details(ctx: &Context<'_>, key: &str) -> Option { +fn get_repo_details(ctx: &Context<'_>, key: &str) -> Option { let data = ctx.data(); let rwlock_guard = data.state.read().unwrap(); rwlock_guard.issue_prefixes.get(key).cloned() } -async fn rm_repo(ctx: &Context<'_>, key: &str) { +fn rm_repo(ctx: &Context<'_>, key: &str) { let data = ctx.data(); let mut rwlock_guard = data.state.write().unwrap(); diff --git a/src/events/code.rs b/src/events/code.rs index c1d81d5..9b89d3c 100644 --- a/src/events/code.rs +++ b/src/events/code.rs @@ -35,10 +35,10 @@ async fn get_embeds(ctx: &Context, message: &Message) -> Option typing.stop(); - if !embeds.is_empty() { - Some(embeds) - } else { + if embeds.is_empty() { None + } else { + Some(embeds) } } @@ -47,12 +47,12 @@ async fn http_get_body_text(url: &String) -> Option { Ok(res) => match res.text().await { Ok(content) => Some(content), Err(e) => { - println!("Failed to get text: {}", e); + println!("Failed to get text: {e}"); None } }, Err(e) => { - println!("Failed to get response: {}", e); + println!("Failed to get response: {e}"); None } } @@ -95,10 +95,10 @@ impl FileReference<'_> { }) .collect(); - if !files.is_empty() { - Some(files) - } else { + if files.is_empty() { None + } else { + Some(files) } } @@ -108,7 +108,7 @@ impl FileReference<'_> { if let Some(mut content) = self.display().await { content.shrink_to(4096 - 8 - extension.len()); - let description = format!("```{}\n{}\n```", extension, content); + let description = format!("```{extension}\n{content}\n```"); let mut default = CreateEmbed::default(); default = default @@ -135,7 +135,7 @@ impl FileReference<'_> { "https://raw.githubusercontent.com/{}/{}/{}/{}", self.owner, self.repo, self.git_ref, self.path ); - println!("Downloading content: {}", url); + println!("Downloading content: {url}"); if let Some(content) = http_get_body_text(&url).await { let lines: Vec<&str> = content.split('\n').collect(); diff --git a/src/events/issue.rs b/src/events/issue.rs index 386b35f..22af6a4 100644 --- a/src/events/issue.rs +++ b/src/events/issue.rs @@ -22,8 +22,8 @@ pub async fn message(data: &Data, ctx: &Context, message: &Message) { let typing = message.channel_id.start_typing(&ctx.http); let ctx_id = message.id.get(); // poise context isn't available here. - let remove_id = format!("{}remove", ctx_id); - let hide_body_id = format!("{}hide_body", ctx_id); + let remove_id = format!("{ctx_id}remove"); + let hide_body_id = format!("{ctx_id}hide_body"); let remove = CreateActionRow::Buttons(vec![CreateButton::new(&remove_id) .label("delete") .style(ButtonStyle::Danger)]); @@ -124,7 +124,7 @@ async fn issue_embeds(data: &Data, message: &Message) -> Option let client = octocrab::instance(); let ratelimit = client.ratelimit(); - let regex = Regex::new(r#" ?([a-zA-Z0-9-_.]+)?#([0-9]+) ?"#).expect("Expected numbers regex"); + let regex = Regex::new(r" ?([a-zA-Z0-9-_.]+)?#([0-9]+) ?").expect("Expected numbers regex"); let custom_repos = { data.state.read().unwrap().issue_prefixes.clone() }; @@ -211,7 +211,7 @@ impl Document for Issue { let mut description = String::default(); for line in body.split('\n').take(15) { - description.push_str(&format!("{}\n", line)); + description.push_str(&format!("{line}\n")); } description.shrink_to(4096); @@ -226,7 +226,9 @@ impl Document for Issue { } fn get_labels(&self) -> Option { - if !self.labels.is_empty() { + if self.labels.is_empty() { + None + } else { let labels = &self .labels .iter() @@ -234,8 +236,6 @@ impl Document for Issue { .collect::>(); Some(format!("`{}`", labels.join("`, `"))) - } else { - None } } } @@ -270,7 +270,7 @@ impl Embeddable for PullRequest { embed = embed.field("Labels", labels, true); } - embed.to_owned() + embed } } @@ -287,7 +287,7 @@ impl Document for PullRequest { let mut content = String::default(); for line in body.split('\n').take(15) { - content.push_str(&format!("{}\n", line)); + content.push_str(&format!("{line}\n")); } content.shrink_to(4096); diff --git a/src/formatting.rs b/src/formatting.rs index 188a178..b896f0c 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -1,6 +1,6 @@ pub fn trim_indent(lines: &[&str]) -> String { let base_indent = get_base_indent(lines); - let prefix = String::from_iter(std::iter::repeat(' ').take(base_indent)); + let prefix = " ".repeat(base_indent); let trimmed_lines: Vec<&str> = lines .iter() diff --git a/src/main.rs b/src/main.rs index 81b782d..36bed3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,11 @@ +#![warn(clippy::pedantic)] +// They aren't exactly any more unreadable this way, even more so considering they are hexadecimal. +#![allow(clippy::unreadable_literal)] +// Preference. +#![allow(clippy::single_match, clippy::single_match_else)] +// Possibly will fix in the future, it just isn't a problem as it stands. +#![allow(clippy::too_many_lines)] + pub(crate) mod commands; pub(crate) mod events; pub(crate) mod formatting; @@ -20,10 +28,10 @@ type Context<'a> = poise::Context<'a, Data, Error>; async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { match error { - poise::FrameworkError::Setup { error, .. } => panic!("Failed to start bot: {:?}", error), + poise::FrameworkError::Setup { error, .. } => panic!("Failed to start bot: {error:?}"), poise::FrameworkError::Command { ctx, error, .. } => { let error = error.to_string(); - eprintln!("An error occured in a command: {}", error); + eprintln!("An error occured in a command: {error}"); commands::respond_err(&ctx, "Command Error", &error).await; } @@ -35,12 +43,9 @@ async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { None => "Please check the help menu for usage information", }; let response = if let Some(input) = input { - format!( - "**Cannot parse `{}` as argument: {}**\n{}", - input, error, usage - ) + format!("**Cannot parse `{input}` as argument: {error}**\n{usage}") } else { - format!("### {}\n{}", error, usage) + format!("### {error}\n{usage}") }; commands::respond_err(&ctx, "Argument Parsing Error", &response).await; } @@ -55,7 +60,7 @@ async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { error => { if let Err(e) = poise::builtins::on_error(error).await { - println!("Error while handling error: {}", e) + println!("Error while handling error: {e}"); } } } diff --git a/src/structures.rs b/src/structures.rs index 1501f9b..0fccf58 100644 --- a/src/structures.rs +++ b/src/structures.rs @@ -81,11 +81,12 @@ impl BotState { .read(true) .write(true) .create(true) + .truncate(true) .open(path); match writer { Ok(writer) => match to_writer_pretty(writer, self) { - Ok(_) => println!("Successfully saved state to '{path_str}'",), + Ok(()) => println!("Successfully saved state to '{path_str}'",), Err(e) => println!("Failed to save state to '{path_str}': {e}"), }, Err(e) => println!("Unable to write state to '{path_str}': {e}"),