Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,10 +491,15 @@ pub enum SendAction {
SubmitFromEditor,

/// Upload a file.
Upload(String),
///
/// The second argument indicates whether to use the messagebar as a caption, don't use it or
/// ask the user.
Upload(String, Option<bool>),

/// Upload the image data.
UploadImage(usize, usize, Cow<'static, [u8]>),
///
/// The [`bool`] arguments indicates whether to use the messagebar as a caption.
UploadImage(usize, usize, Cow<'static, [u8]>, bool),
}

/// An action performed against the user's homeserver.
Expand Down
2 changes: 1 addition & 1 deletion src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ fn iamb_upload(desc: CommandDescription, ctx: &mut ProgContext) -> ProgResult {
return Result::Err(CommandError::InvalidArgument);
}

let sact = SendAction::Upload(args.remove(0));
let sact = SendAction::Upload(args.remove(0), None);
let iact = IambAction::from(sact);
let step = CommandStep::Continue(iact.into(), ctx.context.clone());

Expand Down
28 changes: 28 additions & 0 deletions src/message/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,34 @@ pub fn text_to_message(input: String) -> RoomMessageEventContent {
RoomMessageEventContent::new(msg)
}

/// Returns `None` if `input` contains a non-text slash command.
pub fn text_to_text_message_event_content(input: String) -> Option<TextMessageEventContent> {
let cmd = parse_slash_command(&input);

let content = match cmd {
Ok((body, SlashCommand::Html)) => TextMessageEventContent::html(body, body),
Ok((body, SlashCommand::Plaintext)) => TextMessageEventContent::plain(body),
Ok((body, SlashCommand::Markdown)) => {
if let Some(html) = text_to_html(body) {
TextMessageEventContent::html(body, html)
} else {
TextMessageEventContent::plain(body)
}
},
Ok(_) => return None,

_ => {
if let Some(html) = text_to_html(&input) {
TextMessageEventContent::html(input, html)
} else {
TextMessageEventContent::plain(input)
}
},
};

Some(content)
}

#[cfg(test)]
pub mod tests {
use super::*;
Expand Down
167 changes: 111 additions & 56 deletions src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ mod html;
mod printer;
mod state;

pub use self::compose::text_to_message;
pub use self::compose::{text_to_message, text_to_text_message_event_content};
use self::state::{body_cow_state, html_state};
pub use html::TreeGenState;

Expand Down Expand Up @@ -462,17 +462,33 @@ impl MessageEvent {
MessageEvent::Local(_, _, content) => content,
};

if let MessageType::Text(content) = &content.msgtype {
if let Some(FormattedBody { format: MessageFormat::Html, body }) = &content.formatted {
Some(parse_matrix_html(body.as_str()))
} else {
None
}
let formatted = match &content.msgtype {
MessageType::Text(content) => content.formatted.as_ref(),
MessageType::Emote(content) => content.formatted.as_ref(),
MessageType::Notice(content) => content.formatted.as_ref(),

MessageType::Audio(content) => content.formatted.as_ref(),
MessageType::File(content) => content.formatted.as_ref(),
MessageType::Image(content) => content.formatted.as_ref(),
MessageType::Video(content) => content.formatted.as_ref(),
_ => None,
};

if let Some(FormattedBody { format: MessageFormat::Html, body }) = formatted {
Some(parse_matrix_html(body.as_str()))
} else {
None
}
}

pub fn filename(&self) -> Option<String> {
match self {
MessageEvent::Original(ev) => content_filename(&ev.content),
MessageEvent::Local(_, _, content) => content_filename(content),
_ => None,
}
}

fn redact(&mut self, redaction: SyncRoomRedactionEvent) {
match self {
MessageEvent::EncryptedOriginal(_) => return,
Expand Down Expand Up @@ -514,12 +530,12 @@ impl MessageEvent {

/// Macro rule converting a File / Image / Audio / Video to its text content with the shape:
/// `[Attached <type>: <content>[ (<human readable file size>)]]`
macro_rules! display_file_to_text {
( $msgtype:ident, $content:expr ) => {
return Cow::Owned(format!(
macro_rules! display_file_name {
( $msgtype:ident, $content:expr ) => {{
Some(format!(
"[Attached {}: {}{}]",
stringify!($msgtype),
$content.body,
$content.filename(),
$content
.info
.as_ref()
Expand All @@ -530,7 +546,39 @@ macro_rules! display_file_to_text {
})
.unwrap_or_else(String::new)
))
};
}};
}

/// Macro rule extraction the text caption of a File / Image / Audio / Video
macro_rules! display_file_to_text {
( $msgtype:ident, $content:expr ) => {{
if $content
.filename
.as_ref()
.is_none_or(|filename| *filename == $content.body)
{
return Cow::Borrowed("");
}
$content.body.as_str()
}};
}

fn content_filename(content: &RoomMessageEventContent) -> Option<String> {
match &content.msgtype {
MessageType::Audio(content) => {
display_file_name!(Audio, content)
},
MessageType::File(content) => {
display_file_name!(File, content)
},
MessageType::Image(content) => {
display_file_name!(Image, content)
},
MessageType::Video(content) => {
display_file_name!(Video, content)
},
_ => None,
}
}

fn body_cow_content(content: &RoomMessageEventContent) -> Cow<'_, str> {
Expand All @@ -542,16 +590,16 @@ fn body_cow_content(content: &RoomMessageEventContent) -> Cow<'_, str> {
MessageType::ServerNotice(content) => content.body.as_str(),

MessageType::Audio(content) => {
display_file_to_text!(Audio, content);
display_file_to_text!(Audio, content)
},
MessageType::File(content) => {
display_file_to_text!(File, content);
display_file_to_text!(File, content)
},
MessageType::Image(content) => {
display_file_to_text!(Image, content);
display_file_to_text!(Image, content)
},
MessageType::Video(content) => {
display_file_to_text!(Video, content);
display_file_to_text!(Video, content)
},
_ => content.body(),
};
Expand Down Expand Up @@ -1100,41 +1148,48 @@ impl Message {
settings: &'a ApplicationSettings,
previews: &'a PreviewManager,
) -> (Text<'a>, Option<&'a Protocol>) {
if let Some(html) = &self.html {
(html.to_text(width, style, settings), None)
let mut proto = None;
let placeholder = match self.image_preview.as_ref().and_then(|source| previews.get(source))
{
None => None,
Some(ImageStatus::Queued(image_preview_size)) => {
placeholder_frame(Some("Queued..."), width, image_preview_size)
},
Some(ImageStatus::Downloading(image_preview_size)) => {
placeholder_frame(Some("Downloading..."), width, image_preview_size)
},
Some(ImageStatus::Loaded(backend)) => {
proto = Some(backend);
placeholder_frame(Some("No Space..."), width, &backend.area().into())
},
Some(ImageStatus::Error(err)) => Some(format!("[Image error: {err}]\n")),
};

let mut text = if let Some(placeholder) = placeholder {
wrapped_text(placeholder, width, style)
} else {
let mut msg = self.event.body();
if settings.tunables.message_shortcode_display {
msg = Cow::Owned(replace_emojis_in_str(msg.as_ref()));
}
Default::default()
};

if let Some(mut filename) = self.event.filename() {
if self.downloaded {
msg.to_mut().push_str(" \u{2705}");
filename.push_str(" \u{2705}");
}

let mut proto = None;
let placeholder =
match self.image_preview.as_ref().and_then(|source| previews.get(source)) {
None => None,
Some(ImageStatus::Queued(image_preview_size)) => {
placeholder_frame(Some("Queued..."), width, image_preview_size)
},
Some(ImageStatus::Downloading(image_preview_size)) => {
placeholder_frame(Some("Downloading..."), width, image_preview_size)
},
Some(ImageStatus::Loaded(backend)) => {
proto = Some(backend);
placeholder_frame(Some("No Space..."), width, &backend.area().into())
},
Some(ImageStatus::Error(err)) => Some(format!("[Image error: {err}]\n")),
};

if let Some(placeholder) = placeholder {
msg.to_mut().insert_str(0, &placeholder);
text = text + wrapped_text(filename, width, style);
}

if let Some(html) = &self.html {
text = text + html.to_text(width, style, settings);
} else {
let mut msg = self.event.body();
if settings.tunables.message_shortcode_display {
msg = Cow::Owned(replace_emojis_in_str(msg.as_ref()));
}
text = text + wrapped_text(msg, width, style);
};

(wrapped_text(msg, width, style), proto)
}
(text, proto)
}

fn sender_span<'a>(
Expand Down Expand Up @@ -1490,79 +1545,79 @@ pub mod tests {
#[test]
fn test_display_attachment_size() {
assert_eq!(
body_cow_content(&RoomMessageEventContent::new(MessageType::Image(
content_filename(&RoomMessageEventContent::new(MessageType::Image(
ImageMessageEventContent::plain(
"Alt text".to_string(),
"mxc://matrix.org/jDErsDugkNlfavzLTjJNUKAH".into()
)
.info(Some(Box::default()))
))),
"[Attached Image: Alt text]".to_string()
"[Attached Image: Alt text]".to_string().into()
);

let mut info = ImageInfo::default();
info.size = Some(442630_u32.into());
assert_eq!(
body_cow_content(&RoomMessageEventContent::new(MessageType::Image(
content_filename(&RoomMessageEventContent::new(MessageType::Image(
ImageMessageEventContent::plain(
"Alt text".to_string(),
"mxc://matrix.org/jDErsDugkNlfavzLTjJNUKAH".into()
)
.info(Some(Box::new(info)))
))),
"[Attached Image: Alt text (442.63 kB)]".to_string()
"[Attached Image: Alt text (442.63 kB)]".to_string().into()
);

let mut info = ImageInfo::default();
info.size = Some(12_u32.into());
assert_eq!(
body_cow_content(&RoomMessageEventContent::new(MessageType::Image(
content_filename(&RoomMessageEventContent::new(MessageType::Image(
ImageMessageEventContent::plain(
"Alt text".to_string(),
"mxc://matrix.org/jDErsDugkNlfavzLTjJNUKAH".into()
)
.info(Some(Box::new(info)))
))),
"[Attached Image: Alt text (12 B)]".to_string()
"[Attached Image: Alt text (12 B)]".to_string().into()
);

let mut info = AudioInfo::default();
info.size = Some(4294967295_u32.into());
assert_eq!(
body_cow_content(&RoomMessageEventContent::new(MessageType::Audio(
content_filename(&RoomMessageEventContent::new(MessageType::Audio(
AudioMessageEventContent::plain(
"Alt text".to_string(),
"mxc://matrix.org/jDErsDugkNlfavzLTjJNUKAH".into()
)
.info(Some(Box::new(info)))
))),
"[Attached Audio: Alt text (4.29 GB)]".to_string()
"[Attached Audio: Alt text (4.29 GB)]".to_string().into()
);

let mut info = FileInfo::default();
info.size = Some(4426300_u32.into());
assert_eq!(
body_cow_content(&RoomMessageEventContent::new(MessageType::File(
content_filename(&RoomMessageEventContent::new(MessageType::File(
FileMessageEventContent::plain(
"Alt text".to_string(),
"mxc://matrix.org/jDErsDugkNlfavzLTjJNUKAH".into()
)
.info(Some(Box::new(info)))
))),
"[Attached File: Alt text (4.43 MB)]".to_string()
"[Attached File: Alt text (4.43 MB)]".to_string().into()
);

let mut info = VideoInfo::default();
info.size = Some(44000_u32.into());
assert_eq!(
body_cow_content(&RoomMessageEventContent::new(MessageType::Video(
content_filename(&RoomMessageEventContent::new(MessageType::Video(
VideoMessageEventContent::plain(
"Alt text".to_string(),
"mxc://matrix.org/jDErsDugkNlfavzLTjJNUKAH".into()
)
.info(Some(Box::new(info)))
))),
"[Attached Video: Alt text (44 kB)]".to_string()
"[Attached Video: Alt text (44 kB)]".to_string().into()
);
}
}
Loading
Loading