diff --git a/src/utils/html.rs b/src/utils/html.rs index 4d0bf5ed..371380e1 100644 --- a/src/utils/html.rs +++ b/src/utils/html.rs @@ -1,3 +1,4 @@ +//! Utils for working with the [HTML message style.](https://core.telegram.org/bots/api#html-style) use std::string::String; // Escapes the string to be shown "as is" within the Telegram HTML message style. @@ -9,6 +10,42 @@ pub fn escape(s: &str) -> String { .replace(">", ">") } +pub fn bold(s: &str) -> String { + format!("{}", s) +} + +pub fn italic(s: &str) -> String { + format!("{}", s) +} + +pub fn underline(s: &str) -> String { + format!("{}", s) +} + +pub fn strike(s: &str) -> String { + format!("{}", s) +} + +pub fn link(url: &str, text: &str) -> String { + format!("{}", escape(url), text) +} + +pub fn user_mention(user_id: i32, text: &str) -> String { + link(format!("tg://user?id={}", user_id).as_str(), text) +} + +pub fn code_block(code: &str) -> String { + format!("
\n{}\n
", escape(code)) +} + +pub fn code_block_with_lang(code: &str, lang: &str) -> String { + format!("
\n{}\n
", escape(lang), escape(code)) +} + +pub fn code_inline(s: &str) -> String { + format!("{}", escape(s)) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/utils/markdown.rs b/src/utils/markdown.rs index 376946d8..b2f70097 100644 --- a/src/utils/markdown.rs +++ b/src/utils/markdown.rs @@ -6,7 +6,7 @@ use std::string::String; /// Passed string will not be automatically escaped /// because it can contain nested markup. pub fn bold(s: &str) -> String { - wrap(s, "*", "*") + format!("*{}*", s) } /// Applies the italic font style to the string. @@ -15,9 +15,9 @@ pub fn bold(s: &str) -> String { /// because it can contain nested markup. pub fn italic(s: &str) -> String { if s.starts_with("__") && s.ends_with("__") { - return wrap(&s[..s.len() - 1], "_", r"\r__"); + return format!(r"_{}\r__", &s[..s.len() - 1]) } - wrap(s, "_", "_") + format!("_{}_", s) } /// Applies the underline font style to the string. @@ -30,25 +30,22 @@ pub fn underline(s: &str) -> String { // so instead of ___italic underline___ we should use ___italic underline_\r__, // where \r is a character with code 13, which will be ignored. if s.starts_with("_") && s.ends_with("_") { - return wrap(s, "__", r"\r__"); + return format!(r"__{}\r__", s) } - wrap(s, "__", "__") + format!("__{}__", s) } /// Applies the strikethrough font style to the string. /// Passed string will not be automatically escaped /// because it can contain nested markup. pub fn strike(s: &str) -> String { - wrap(s, "~", "~") + format!("~{}~", s) } /// Builds an inline link with an anchor. /// Escapes `)` and ``` characters inside the link url. pub fn link(url: &str, text: &str) -> String { - let mut out = String::with_capacity(url.len() + text.len() + 4); - out.push_str(wrap(text, "[", "]").as_str()); - out.push_str(wrap(escape_link_url(url).as_str(), "(", ")").as_str()); - out + format!("[{}]({})", text, escape_link_url(url)) } /// Builds an inline user mention link with an anchor. @@ -58,23 +55,19 @@ pub fn user_mention(user_id: i32, text: &str) -> String { /// Formats the code block. Escapes ``` and `\` characters inside the block. pub fn code_block(code: &str) -> String { - code_block_with_lang(code, "") + format!("```\n{}\n```", escape_code(code)) } /// Formats the code block with a specific language syntax. /// Escapes ``` and `\` characters inside the block. pub fn code_block_with_lang(code: &str, lang: &str) -> String { - wrap( - escape_code(code).as_str(), - format!("```{}\n", lang).as_str(), - "\n```", - ) + format!("```{}\n{}\n```", escape(lang), escape_code(code)) } /// Formats the string as an inline code. /// Escapes ``` and `\` characters inside the block. pub fn code_inline(s: &str) -> String { - wrap(escape_code(s).as_str(), "`", "`") + format!("`{}`", escape_code(s)) } /// Escapes all markdown special characters in the passed string. @@ -98,24 +91,16 @@ pub fn escape(s: &str) -> String { .replace("!", r"\!") } -/// Escapes all markdown special characters specific for the inline link URL (``` and `)`) +/// Escapes all markdown special characters specific for the inline link URL (``` and `)`). pub fn escape_link_url(s: &str) -> String { s.replace("`", r"\`").replace(")", r"\)") } -/// Escapes all markdown special characters specific for the code block (``` and `\`) +/// Escapes all markdown special characters specific for the code block (``` and `\`). pub fn escape_code(s: &str) -> String { s.replace(r"\", r"\\").replace("`", r"\`") } -fn wrap(s: &str, left: &str, right: &str) -> String { - let mut out = String::with_capacity(left.len() + s.len() + right.len()); - out.push_str(left); - out.push_str(s); - out.push_str(right); - out -} - #[cfg(test)] mod tests { use super::*; @@ -183,9 +168,9 @@ mod tests { assert_eq!( code_block_with_lang( "pre-'formatted'\nfixed-width \\code `block`", - "python" + "[python]" ), - "```python\npre-'formatted'\nfixed-width \\\\code \\`block\\`\n```" + "```\\[python\\]\npre-'formatted'\nfixed-width \\\\code \\`block\\`\n```" ); }