use std::fmt::Display; use crate::Context; use anyhow::Error; use poise::serenity_prelude::{ChannelId, ChannelType, GuildChannel}; struct Server { channels: Vec, orphanage: Vec, needs_clean: bool, } struct Channel { this: GuildChannel, children: Vec } impl Display for Server { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn print(f: &mut std::fmt::Formatter<'_>, tab: usize, channel: &Vec) { for i in channel { for _ in 0..tab { let _ = write!(f, "\t"); } let _ = writeln!(f, "{} {}", prefix(i.this.kind),i.this.name); print(f, tab+1, &i.children); } } fn prefix(kind: ChannelType) -> &'static str { match kind { poise::serenity_prelude::ChannelType::Text => "๐Ÿ’ฌ", poise::serenity_prelude::ChannelType::Private => "๐Ÿ•ต๏ธ", poise::serenity_prelude::ChannelType::Voice => "๐Ÿ”Š", poise::serenity_prelude::ChannelType::GroupDm => "๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ", poise::serenity_prelude::ChannelType::Category => "๐Ÿ“", poise::serenity_prelude::ChannelType::News => "๐Ÿ“ข", poise::serenity_prelude::ChannelType::NewsThread => "๐Ÿ“ข๐Ÿงต", poise::serenity_prelude::ChannelType::PublicThread => "๐Ÿงต", poise::serenity_prelude::ChannelType::PrivateThread => "๐Ÿ•ต๏ธ๐Ÿงต", poise::serenity_prelude::ChannelType::Stage => "๐ŸŽ™๏ธ", poise::serenity_prelude::ChannelType::Directory => "๐Ÿ“’", poise::serenity_prelude::ChannelType::Forum => "๐Ÿ—ฃ๏ธ", _ => "?", } } print(f, 0, &self.channels); if self.needs_clean { let _ = writeln!(f, "Orphans: (please clean() before displaying...)"); for i in &self.orphanage { let _ = write!(f, "{} {},", prefix(i.kind),i.name); } } write!(f, "") } } impl Server { fn new() -> Self { Self { channels: Vec::new(), orphanage: Vec::new(), needs_clean: false } } // TODO this might be broken fn search<'a>(target: &'a mut Vec, find: &ChannelId) -> Option<&'a mut Channel> { for child in target { if child.this.id == *find { return Some(child); } match Self::search(&mut child.children, find) { Some(x) => return Some(x), None => {}, } } None } fn add(&mut self, insert: GuildChannel) { // make sure the new item wants a parent if let Some(parent_id) = &insert.parent_id { // find the parent (needs to go thru all nodes) match Self::search(&mut self.channels, &parent_id) { Some(parent_node) => { parent_node.children.push(Channel { this: insert, children: Vec::new() }); }, None => { // couldn't find parent, store somewhere else until it's parent is added... self.orphanage.push(insert); self.needs_clean = true; }, } } else { self.channels.push(Channel { this: insert, children: Vec::new() }) } } fn clean(&mut self) { if !self.needs_clean {return;} // Look thru the orphanage and try to find parents for orphan in &self.orphanage { if let Some(parent_id) = orphan.parent_id { if let Some(found) = Self::search(&mut self.channels, &parent_id) { found.children.push(Channel { this: orphan.clone(), children: Vec::new() }); } else { panic!("โš ๏ธ Couldn't find parent for orphan!"); } } else { panic!("โš ๏ธ All orphans should want a parent node!"); } } self.orphanage.clear(); self.needs_clean = false; } } // NOTE!!! Make sure these names in quotes are lowercase! #[poise::command(slash_command, rename = "index", guild_only)] pub async fn index(ctx: Context<'_>) -> Result<(), Error> { let guild = ctx.guild_id().unwrap().to_partial_guild(ctx.serenity_context()).await.unwrap(); match guild.channels(ctx.http()).await { Ok(ok) => { let mut server = Server::new(); // iterate thru all channels ok.into_iter().for_each(|(_id, current)| { match current.kind { poise::serenity_prelude::ChannelType::Text => { server.add(current); // current.position, }, poise::serenity_prelude::ChannelType::Private => todo!(), poise::serenity_prelude::ChannelType::Voice => { server.add(current); // current.user_limit, // current.parent_id, }, poise::serenity_prelude::ChannelType::GroupDm => todo!(), poise::serenity_prelude::ChannelType::Category => { server.add(current); }, poise::serenity_prelude::ChannelType::News => todo!(), poise::serenity_prelude::ChannelType::NewsThread => todo!(), poise::serenity_prelude::ChannelType::PublicThread => todo!(), poise::serenity_prelude::ChannelType::PrivateThread => todo!(), poise::serenity_prelude::ChannelType::Stage => todo!(), poise::serenity_prelude::ChannelType::Directory => todo!(), poise::serenity_prelude::ChannelType::Forum => todo!(), poise::serenity_prelude::ChannelType::Unknown(_) => todo!(), _ => todo!(), } }); server.clean(); println!("{}", server); }, Err(_) => todo!(), } Ok(()) }