diff --git a/crates/ruma-events/src/room/message.rs b/crates/ruma-events/src/room/message.rs index bd3f822b..976e8e3f 100644 --- a/crates/ruma-events/src/room/message.rs +++ b/crates/ruma-events/src/room/message.rs @@ -427,13 +427,13 @@ impl EmoteMessageEventContent { } /// A convenience constructor to create a markdown emote. + /// + /// Returns an html emote message if some markdown formatting was detected, otherwise returns a + /// plain-text emote. #[cfg(feature = "markdown")] #[cfg_attr(docsrs, doc(cfg(feature = "markdown")))] - pub fn markdown(body: impl Into) -> Self { - let body = body.into(); - let mut html_body = String::new(); - pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(&body)); - Self::html(body, html_body) + pub fn markdown(body: impl AsRef + Into) -> Self { + Self { formatted: FormattedBody::markdown(&body), ..Self::plain(body) } } } @@ -629,6 +629,16 @@ impl NoticeMessageEventContent { pub fn html(body: impl Into, html_body: impl Into) -> Self { Self { formatted: Some(FormattedBody::html(html_body)), ..Self::plain(body) } } + + /// A convenience constructor to create a markdown notice. + /// + /// Returns an html notice if some markdown formatting was detected, otherwise returns a plain + /// text notice. + #[cfg(feature = "markdown")] + #[cfg_attr(docsrs, doc(cfg(feature = "markdown")))] + pub fn markdown(body: impl AsRef + Into) -> Self { + Self { formatted: FormattedBody::markdown(&body), ..Self::plain(body) } + } } /// The payload for a server notice message. @@ -725,6 +735,24 @@ impl FormattedBody { pub fn html(body: impl Into) -> Self { Self { format: MessageFormat::Html, body: body.into() } } + + /// Creates a new HTML-formatted message body by parsing the markdown in `body`. + /// + /// Returns `None` if no markdown formatting was found. + #[cfg(feature = "markdown")] + #[cfg_attr(docsrs, doc(cfg(feature = "markdown")))] + pub fn markdown(body: impl AsRef) -> Option { + let body = body.as_ref(); + let mut html_body = String::new(); + + pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(body)); + + if html_body == format!("

{}

\n", body) { + None + } else { + Some(Self::html(html_body)) + } + } } /// The payload for a text message. @@ -752,13 +780,13 @@ impl TextMessageEventContent { } /// A convenience constructor to create a markdown message. + /// + /// Returns an html message if some markdown formatting was detected, otherwise returns a plain + /// text message. #[cfg(feature = "markdown")] #[cfg_attr(docsrs, doc(cfg(feature = "markdown")))] - pub fn markdown(body: impl Into) -> Self { - let body = body.into(); - let mut html_body = String::new(); - pulldown_cmark::html::push_html(&mut html_body, pulldown_cmark::Parser::new(&body)); - Self::html(body, html_body) + pub fn markdown(body: impl AsRef + Into) -> Self { + Self { formatted: FormattedBody::markdown(&body), ..Self::plain(body) } } /// A convenience constructor to create a plain text message. diff --git a/crates/ruma-events/tests/room_message.rs b/crates/ruma-events/tests/room_message.rs index eb0699bb..026c9f8c 100644 --- a/crates/ruma-events/tests/room_message.rs +++ b/crates/ruma-events/tests/room_message.rs @@ -155,6 +155,50 @@ fn plain_text_content_serialization() { ); } +#[test] +#[cfg(feature = "markdown")] +fn markdown_content_serialization() { + let formatted_message = MessageEventContent::new(MessageType::Text( + TextMessageEventContent::markdown("Testing **bold** and _italic_!"), + )); + + assert_eq!( + to_json_value(&formatted_message).unwrap(), + json!({ + "body": "Testing **bold** and _italic_!", + "formatted_body": "

Testing bold and italic!

\n", + "format": "org.matrix.custom.html", + "msgtype": "m.text" + }) + ); + + let plain_message_simple = MessageEventContent::new(MessageType::Text( + TextMessageEventContent::markdown("Testing a simple phrase…"), + )); + + assert_eq!( + to_json_value(&plain_message_simple).unwrap(), + json!({ + "body": "Testing a simple phrase…", + "msgtype": "m.text" + }) + ); + + let plain_message_paragraphs = MessageEventContent::new(MessageType::Text( + TextMessageEventContent::markdown("Testing\n\nSeveral\n\nParagraphs."), + )); + + assert_eq!( + to_json_value(&plain_message_paragraphs).unwrap(), + json!({ + "body": "Testing\n\nSeveral\n\nParagraphs.", + "formatted_body": "

Testing

\n

Several

\n

Paragraphs.

\n", + "format": "org.matrix.custom.html", + "msgtype": "m.text" + }) + ); +} + #[test] fn relates_to_content_serialization() { let message_event_content =