mirror of
https://github.com/youwen5/iamb.git
synced 2025-06-20 05:39:52 -07:00
Interpret newlines as line breaks when converting Markdown to HTML (#74)
This commit is contained in:
parent
953be6a195
commit
ad3b40d538
6 changed files with 442 additions and 42 deletions
|
@ -1027,9 +1027,8 @@ pub mod tests {
|
|||
Span::raw("│"),
|
||||
Span::raw(" "),
|
||||
Span::raw("│"),
|
||||
Span::styled(" ", bold),
|
||||
Span::styled("3", bold),
|
||||
Span::styled(" ", bold),
|
||||
Span::styled(" ", bold),
|
||||
Span::raw("│")
|
||||
]);
|
||||
|
||||
|
@ -1157,4 +1156,21 @@ pub mod tests {
|
|||
assert_eq!(text.lines[1], Spans(vec![Span::raw("World"), Span::raw(" "),]));
|
||||
assert_eq!(text.lines[2], Spans(vec![Span::raw("Goodbye")]),);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_embedded_newline() {
|
||||
let s = "<p>Hello\nWorld</p>";
|
||||
let tree = parse_matrix_html(s);
|
||||
let text = tree.to_text(15, Style::default(), true);
|
||||
assert_eq!(text.lines.len(), 1);
|
||||
assert_eq!(
|
||||
text.lines[0],
|
||||
Spans(vec![
|
||||
Span::raw("Hello"),
|
||||
Span::raw(" "),
|
||||
Span::raw("World"),
|
||||
Span::raw(" ")
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::hash::{Hash, Hasher};
|
|||
use std::slice::Iter;
|
||||
|
||||
use chrono::{DateTime, Local as LocalTz, NaiveDateTime, TimeZone};
|
||||
use comrak::{markdown_to_html, ComrakOptions};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use matrix_sdk::ruma::{
|
||||
|
@ -26,6 +27,7 @@ use matrix_sdk::ruma::{
|
|||
Relation,
|
||||
RoomMessageEvent,
|
||||
RoomMessageEventContent,
|
||||
TextMessageEventContent,
|
||||
},
|
||||
redaction::SyncRoomRedactionEvent,
|
||||
},
|
||||
|
@ -93,6 +95,19 @@ const USER_GUTTER_EMPTY_SPAN: Span<'static> = span_static(USER_GUTTER_EMPTY);
|
|||
const TIME_GUTTER_EMPTY: &str = " ";
|
||||
const TIME_GUTTER_EMPTY_SPAN: Span<'static> = span_static(TIME_GUTTER_EMPTY);
|
||||
|
||||
fn text_to_message_content(input: String) -> TextMessageEventContent {
|
||||
let mut options = ComrakOptions::default();
|
||||
options.render.hardbreaks = true;
|
||||
let html = markdown_to_html(input.as_str(), &options);
|
||||
|
||||
TextMessageEventContent::html(input, html)
|
||||
}
|
||||
|
||||
pub fn text_to_message(input: String) -> RoomMessageEventContent {
|
||||
let msg = MessageType::Text(text_to_message_content(input));
|
||||
RoomMessageEventContent::new(msg)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn millis_to_datetime(ms: UInt) -> DateTime<LocalTz> {
|
||||
let time = i64::from(ms) / 1000;
|
||||
|
@ -972,4 +987,48 @@ pub mod tests {
|
|||
// MessageCursor::latest() should point at the most recent message after conversion.
|
||||
assert_eq!(identity(&mc6), mc1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_markdown_message() {
|
||||
let input = "**bold**\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(content.formatted.unwrap().body, "<p><strong>bold</strong></p>\n");
|
||||
|
||||
let input = "*emphasis*\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(content.formatted.unwrap().body, "<p><em>emphasis</em></p>\n");
|
||||
|
||||
let input = "`code`\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(content.formatted.unwrap().body, "<p><code>code</code></p>\n");
|
||||
|
||||
let input = "```rust\nconst A: usize = 1;\n```\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(
|
||||
content.formatted.unwrap().body,
|
||||
"<pre><code class=\"language-rust\">const A: usize = 1;\n</code></pre>\n"
|
||||
);
|
||||
|
||||
let input = "para 1\n\npara 2\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(content.formatted.unwrap().body, "<p>para 1</p>\n<p>para 2</p>\n");
|
||||
|
||||
let input = "line 1\nline 2\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(content.formatted.unwrap().body, "<p>line 1<br />\nline 2</p>\n");
|
||||
|
||||
let input = "# Heading\n## Subheading\n\ntext\n";
|
||||
let content = text_to_message_content(input.into());
|
||||
assert_eq!(content.body, input);
|
||||
assert_eq!(
|
||||
content.formatted.unwrap().body,
|
||||
"<h1>Heading</h1>\n<h2>Subheading</h2>\n<p>text</p>\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,8 +156,13 @@ impl<'a> TextPrinter<'a> {
|
|||
pub fn push_str(&mut self, s: &'a str, style: Style) {
|
||||
let style = self.base_style.patch(style);
|
||||
|
||||
for word in UnicodeSegmentation::split_word_bounds(s) {
|
||||
if self.width == 0 && word.chars().all(char::is_whitespace) {
|
||||
for mut word in UnicodeSegmentation::split_word_bounds(s) {
|
||||
if let "\n" | "\r\n" = word {
|
||||
// Render embedded newlines as spaces.
|
||||
word = " ";
|
||||
}
|
||||
|
||||
if self.curr_width == 0 && word.chars().all(char::is_whitespace) {
|
||||
// Drop leading whitespace.
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ use crate::base::{
|
|||
SendAction,
|
||||
};
|
||||
|
||||
use crate::message::{Message, MessageEvent, MessageKey, MessageTimeStamp};
|
||||
use crate::message::{text_to_message, Message, MessageEvent, MessageKey, MessageTimeStamp};
|
||||
use crate::worker::Requester;
|
||||
|
||||
use super::scrollback::{Scrollback, ScrollbackState};
|
||||
|
@ -407,10 +407,7 @@ impl ChatState {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let msg = TextMessageEventContent::markdown(msg.to_string());
|
||||
let msg = MessageType::Text(msg);
|
||||
|
||||
let mut msg = RoomMessageEventContent::new(msg);
|
||||
let mut msg = text_to_message(msg.to_string());
|
||||
|
||||
if let Some((_, event_id)) = &self.editing {
|
||||
msg.relates_to = Some(Relation::Replacement(Replacement::new(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue