use std::borrow::Cow;
use std::fmt::{Display, Write};
use serenity::model::channel::AttachmentType;
pub struct PagifyOptions<'a> {
pub delims: &'a [&'a str],
pub escape_mass_mentions: bool,
pub shorten_by: usize,
pub page_length: usize,
pub priority: bool,
}
impl<'a> PagifyOptions<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn delims(&mut self, delims: &'a [&'a str]) -> &mut Self {
self.delims = delims;
self
}
pub fn escape_mass_mentions(&mut self, setting: bool) -> &mut Self {
self.escape_mass_mentions = setting;
self
}
pub fn shorten_by(&mut self, length: usize) -> &mut Self {
self.shorten_by = length;
self
}
pub fn page_length(&mut self, length: usize) -> &mut Self {
self.page_length = length;
self
}
pub fn priority(&mut self, priority: bool) -> &mut Self {
self.priority = priority;
self
}
}
impl<'a> Default for PagifyOptions<'a> {
fn default() -> Self {
Self {
delims: &["\n", " "],
escape_mass_mentions: true,
shorten_by: 8,
page_length: 2000,
priority: false,
}
}
}
pub fn pagify<S: ToString>(text: S, mut options: PagifyOptions<'_>) -> Vec<String> {
let text = text.to_string();
let mut in_text = text;
let mut texts = Vec::new();
options.page_length -= options.shorten_by;
while in_text.len() > options.page_length {
let mut this_page_len = options.page_length;
if options.escape_mass_mentions {
let sliced_text = match in_text.get(0..options.page_length) {
Some(s) => s,
None => continue,
};
this_page_len -=
sliced_text.matches("@here").count() + sliced_text.matches("@everyone").count();
}
let mut possible_delims = options
.delims
.iter()
.filter_map(|&d| in_text[1..this_page_len].rfind(d).map(|i| i + 1));
let closest_delim =
if options.priority { possible_delims.find(|&d| d > 1) } else { possible_delims.max() }
.unwrap_or(this_page_len);
let to_send = if options.escape_mass_mentions {
escape_mass_mentions(&in_text[..closest_delim])
} else {
in_text[..closest_delim].to_string()
};
if !to_send.is_empty() {
texts.push(to_send);
}
in_text = in_text[closest_delim..].to_string();
}
if !in_text.trim().is_empty() {
if options.escape_mass_mentions {
texts.push(escape_mass_mentions(in_text))
} else {
texts.push(in_text)
}
}
texts
}
pub fn escape_mass_mentions<S: ToString>(text: S) -> String {
text.to_string().replace("@everyone", "@\u{200b}everyone").replace("@here", "@\u{200b}here")
}
pub fn text_to_file<'a, S: ToString, T: Display>(
text: S,
file_name: Option<T>,
spoiler: bool,
) -> AttachmentType<'a> {
let mut qualified_file_name = String::new();
if spoiler {
let _ = write!(qualified_file_name, "spoiler_");
}
if let Some(name) = file_name {
let _ = write!(qualified_file_name, "{}", name);
} else {
let _ = write!(qualified_file_name, "file.txt");
}
AttachmentType::Bytes {
data: Cow::from(text.to_string().into_bytes()),
filename: qualified_file_name,
}
}