events: Avoid unnecessary copying in reply generation
This commit is contained in:
parent
ae26730e29
commit
d15fc3f5ec
@ -1,11 +1,11 @@
|
|||||||
use std::fmt;
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
sanitize::remove_plain_reply_fallback, FormattedBody, MessageType, OriginalRoomMessageEvent,
|
sanitize::remove_plain_reply_fallback, FormattedBody, MessageType, OriginalRoomMessageEvent,
|
||||||
Relation,
|
Relation,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "unstable-sanitize")]
|
#[cfg(feature = "unstable-sanitize")]
|
||||||
use super::{sanitize_html, HtmlSanitizerMode, RemoveReplyFallback};
|
use super::{sanitize::HtmlSanitizer, HtmlSanitizerMode, RemoveReplyFallback};
|
||||||
|
|
||||||
fn get_message_quote_fallbacks(original_message: &OriginalRoomMessageEvent) -> (String, String) {
|
fn get_message_quote_fallbacks(original_message: &OriginalRoomMessageEvent) -> (String, String) {
|
||||||
let get_quotes = |body: &str, formatted: Option<&FormattedBody>, is_emote: bool| {
|
let get_quotes = |body: &str, formatted: Option<&FormattedBody>, is_emote: bool| {
|
||||||
@ -14,9 +14,9 @@ fn get_message_quote_fallbacks(original_message: &OriginalRoomMessageEvent) -> (
|
|||||||
let emote_sign = is_emote.then_some("* ").unwrap_or_default();
|
let emote_sign = is_emote.then_some("* ").unwrap_or_default();
|
||||||
let body = is_reply.then(|| remove_plain_reply_fallback(body)).unwrap_or(body);
|
let body = is_reply.then(|| remove_plain_reply_fallback(body)).unwrap_or(body);
|
||||||
#[cfg(feature = "unstable-sanitize")]
|
#[cfg(feature = "unstable-sanitize")]
|
||||||
let html_body = formatted_or_plain_body(formatted, body, is_reply);
|
let html_body = FormattedOrPlainBody { formatted, body, is_reply };
|
||||||
#[cfg(not(feature = "unstable-sanitize"))]
|
#[cfg(not(feature = "unstable-sanitize"))]
|
||||||
let html_body = formatted_or_plain_body(formatted, body);
|
let html_body = FormattedOrPlainBody { formatted, body };
|
||||||
|
|
||||||
(
|
(
|
||||||
format!("> {emote_sign}<{sender}> {body}").replace('\n', "\n> "),
|
format!("> {emote_sign}<{sender}> {body}").replace('\n', "\n> "),
|
||||||
@ -48,46 +48,51 @@ fn get_message_quote_fallbacks(original_message: &OriginalRoomMessageEvent) -> (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a plaintext body to HTML, escaping any characters that would cause problems.
|
struct EscapeHtmlEntities<'a>(&'a str);
|
||||||
fn escape_html_entities(body: &str) -> String {
|
|
||||||
let mut escaped_body = String::with_capacity(body.len());
|
impl fmt::Display for EscapeHtmlEntities<'_> {
|
||||||
for c in body.chars() {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// Escape reserved HTML entities and new lines.
|
for c in self.0.chars() {
|
||||||
// <https://developer.mozilla.org/en-US/docs/Glossary/Entity#reserved_characters>
|
// Escape reserved HTML entities and new lines.
|
||||||
let s = match c {
|
// <https://developer.mozilla.org/en-US/docs/Glossary/Entity#reserved_characters>
|
||||||
'&' => Some("&"),
|
match c {
|
||||||
'<' => Some("<"),
|
'&' => f.write_str("&")?,
|
||||||
'>' => Some(">"),
|
'<' => f.write_str("<")?,
|
||||||
'"' => Some("""),
|
'>' => f.write_str(">")?,
|
||||||
'\n' => Some("<br>"),
|
'"' => f.write_str(""")?,
|
||||||
_ => None,
|
'\n' => f.write_str("<br>")?,
|
||||||
};
|
_ => f.write_char(c)?,
|
||||||
if let Some(s) = s {
|
}
|
||||||
escaped_body.push_str(s);
|
|
||||||
} else {
|
|
||||||
escaped_body.push(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
escaped_body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn formatted_or_plain_body(
|
struct FormattedOrPlainBody<'a> {
|
||||||
formatted: Option<&FormattedBody>,
|
formatted: Option<&'a FormattedBody>,
|
||||||
body: &str,
|
body: &'a str,
|
||||||
#[cfg(feature = "unstable-sanitize")] is_reply: bool,
|
#[cfg(feature = "unstable-sanitize")]
|
||||||
) -> String {
|
is_reply: bool,
|
||||||
if let Some(formatted_body) = formatted {
|
}
|
||||||
#[cfg(feature = "unstable-sanitize")]
|
|
||||||
if is_reply {
|
|
||||||
sanitize_html(&formatted_body.body, HtmlSanitizerMode::Strict, RemoveReplyFallback::Yes)
|
|
||||||
} else {
|
|
||||||
formatted_body.body.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unstable-sanitize"))]
|
impl fmt::Display for FormattedOrPlainBody<'_> {
|
||||||
formatted_body.body.clone()
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
} else {
|
if let Some(formatted_body) = self.formatted {
|
||||||
escape_html_entities(body)
|
#[cfg(feature = "unstable-sanitize")]
|
||||||
|
if self.is_reply {
|
||||||
|
let sanitizer =
|
||||||
|
HtmlSanitizer::new(HtmlSanitizerMode::Strict, RemoveReplyFallback::Yes);
|
||||||
|
write!(f, "{}", sanitizer.clean(&formatted_body.body))
|
||||||
|
} else {
|
||||||
|
f.write_str(&formatted_body.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unstable-sanitize"))]
|
||||||
|
f.write_str(&formatted_body.body)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", EscapeHtmlEntities(self.body))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +116,7 @@ pub fn plain_and_formatted_reply_body(
|
|||||||
let plain = format!("{quoted}\n{body}");
|
let plain = format!("{quoted}\n{body}");
|
||||||
let html = match formatted {
|
let html = match formatted {
|
||||||
Some(formatted) => format!("{quoted_html}{formatted}"),
|
Some(formatted) => format!("{quoted_html}{formatted}"),
|
||||||
None => format!("{quoted_html}{}", escape_html_entities(body)),
|
None => format!("{quoted_html}{}", EscapeHtmlEntities(body)),
|
||||||
};
|
};
|
||||||
|
|
||||||
(plain, html)
|
(plain, html)
|
||||||
|
@ -6,7 +6,7 @@ mod html_fragment;
|
|||||||
mod html_sanitizer;
|
mod html_sanitizer;
|
||||||
|
|
||||||
#[cfg(feature = "unstable-sanitize")]
|
#[cfg(feature = "unstable-sanitize")]
|
||||||
use html_sanitizer::HtmlSanitizer;
|
pub(super) use html_sanitizer::HtmlSanitizer;
|
||||||
|
|
||||||
/// Sanitize the given HTML string.
|
/// Sanitize the given HTML string.
|
||||||
///
|
///
|
||||||
|
Loading…
x
Reference in New Issue
Block a user