Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support displaying shortcodes instead of Emojis in messages #222

Merged
merged 5 commits into from
Mar 23, 2024
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
1 change: 1 addition & 0 deletions docs/example_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"settings": {
"log_level": "warn",
"message_shortcode_display": false,
"reaction_display": true,
"reaction_shortcode_display": false,
"read_receipt_send": true,
Expand Down
4 changes: 4 additions & 0 deletions docs/iamb.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ overridden as described in *PROFILES*.
> Specifies the lowest log level that should be shown. Possible values
> are: _trace_, _debug_, _info_, _warn_, and _error_.

**message_shortcode_display** (type: boolean)
> Defines whether or not emoji characters in messages should be replaced by
> their respective shortcodes.

**reaction_display** (type: boolean)
> Defines whether or not reactions should be shown.

Expand Down
6 changes: 6 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ impl SortOverrides {
#[derive(Clone)]
pub struct TunableValues {
pub log_level: Level,
pub message_shortcode_display: bool,
pub reaction_display: bool,
pub reaction_shortcode_display: bool,
pub read_receipt_send: bool,
Expand All @@ -489,6 +490,7 @@ pub struct TunableValues {
#[derive(Clone, Default, Deserialize)]
pub struct Tunables {
pub log_level: Option<LogLevel>,
pub message_shortcode_display: Option<bool>,
pub reaction_display: Option<bool>,
pub reaction_shortcode_display: Option<bool>,
pub read_receipt_send: Option<bool>,
Expand All @@ -511,6 +513,9 @@ impl Tunables {
fn merge(self, other: Self) -> Self {
Tunables {
log_level: self.log_level.or(other.log_level),
message_shortcode_display: self
.message_shortcode_display
.or(other.message_shortcode_display),
reaction_display: self.reaction_display.or(other.reaction_display),
reaction_shortcode_display: self
.reaction_shortcode_display
Expand All @@ -534,6 +539,7 @@ impl Tunables {
fn values(self) -> TunableValues {
TunableValues {
log_level: self.log_level.map(Level::from).unwrap_or(Level::INFO),
message_shortcode_display: self.message_shortcode_display.unwrap_or(false),
reaction_display: self.reaction_display.unwrap_or(true),
reaction_shortcode_display: self.reaction_shortcode_display.unwrap_or(false),
read_receipt_send: self.read_receipt_send.unwrap_or(true),
Expand Down
98 changes: 65 additions & 33 deletions src/message/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl Table {
}
}

fn to_text(&self, width: usize, style: Style) -> Text {
fn to_text(&self, width: usize, style: Style, emoji_shortcodes: bool) -> Text {
let mut text = Text::default();
let columns = self.columns();
let cell_total = width.saturating_sub(columns).saturating_sub(1);
Expand All @@ -166,7 +166,8 @@ impl Table {

if let Some(caption) = &self.caption {
let subw = width.saturating_sub(6);
let mut printer = TextPrinter::new(subw, style, true).align(Alignment::Center);
let mut printer =
TextPrinter::new(subw, style, true, emoji_shortcodes).align(Alignment::Center);
caption.print(&mut printer, style);

for mut line in printer.finish().lines {
Expand Down Expand Up @@ -213,7 +214,7 @@ impl Table {
CellType::Data => style,
};

cell.to_text(*w, style)
cell.to_text(*w, style, emoji_shortcodes)
} else {
space_text(*w, style)
};
Expand Down Expand Up @@ -274,8 +275,8 @@ pub enum StyleTreeNode {
}

impl StyleTreeNode {
pub fn to_text(&self, width: usize, style: Style) -> Text {
let mut printer = TextPrinter::new(width, style, true);
pub fn to_text(&self, width: usize, style: Style, emoji_shortcodes: bool) -> Text {
let mut printer = TextPrinter::new(width, style, true, emoji_shortcodes);
self.print(&mut printer, style);
printer.finish()
}
Expand Down Expand Up @@ -428,7 +429,7 @@ impl StyleTreeNode {
}
},
StyleTreeNode::Table(table) => {
let text = table.to_text(width, style);
let text = table.to_text(width, style, printer.emoji_shortcodes());
printer.push_text(text);
},
StyleTreeNode::Break => {
Expand Down Expand Up @@ -464,8 +465,14 @@ impl StyleTree {
return links;
}

pub fn to_text(&self, width: usize, style: Style, hide_reply: bool) -> Text<'_> {
let mut printer = TextPrinter::new(width, style, hide_reply);
pub fn to_text(
&self,
width: usize,
style: Style,
hide_reply: bool,
emoji_shortcodes: bool,
) -> Text<'_> {
let mut printer = TextPrinter::new(width, style, hide_reply, emoji_shortcodes);

for child in self.children.iter() {
child.print(&mut printer, style);
Expand Down Expand Up @@ -805,14 +812,15 @@ pub mod tests {
use super::*;
use crate::util::space_span;
use pretty_assertions::assert_eq;
use unicode_width::UnicodeWidthStr;

#[test]
fn test_header() {
let bold = Style::default().add_modifier(StyleModifier::BOLD);

let s = "<h1>Header 1</h1>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("#", bold),
Span::styled(" ", bold),
Expand All @@ -824,7 +832,7 @@ pub mod tests {

let s = "<h2>Header 2</h2>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("#", bold),
Span::styled("#", bold),
Expand All @@ -837,7 +845,7 @@ pub mod tests {

let s = "<h3>Header 3</h3>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("#", bold),
Span::styled("#", bold),
Expand All @@ -851,7 +859,7 @@ pub mod tests {

let s = "<h4>Header 4</h4>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("#", bold),
Span::styled("#", bold),
Expand All @@ -866,7 +874,7 @@ pub mod tests {

let s = "<h5>Header 5</h5>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("#", bold),
Span::styled("#", bold),
Expand All @@ -882,7 +890,7 @@ pub mod tests {

let s = "<h6>Header 6</h6>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("#", bold),
Span::styled("#", bold),
Expand All @@ -909,7 +917,7 @@ pub mod tests {

let s = "<b>Bold!</b>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Bold", bold),
Span::styled("!", bold),
Expand All @@ -918,7 +926,7 @@ pub mod tests {

let s = "<strong>Bold!</strong>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Bold", bold),
Span::styled("!", bold),
Expand All @@ -927,7 +935,7 @@ pub mod tests {

let s = "<i>Italic!</i>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Italic", italic),
Span::styled("!", italic),
Expand All @@ -936,7 +944,7 @@ pub mod tests {

let s = "<em>Italic!</em>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Italic", italic),
Span::styled("!", italic),
Expand All @@ -945,7 +953,7 @@ pub mod tests {

let s = "<del>Strikethrough!</del>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Strikethrough", strike),
Span::styled("!", strike),
Expand All @@ -954,7 +962,7 @@ pub mod tests {

let s = "<strike>Strikethrough!</strike>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Strikethrough", strike),
Span::styled("!", strike),
Expand All @@ -963,7 +971,7 @@ pub mod tests {

let s = "<u>Underline!</u>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Underline", underl),
Span::styled("!", underl),
Expand All @@ -972,7 +980,7 @@ pub mod tests {

let s = "<font color=\"#ff0000\">Red!</u>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Red", red),
Span::styled("!", red),
Expand All @@ -981,7 +989,7 @@ pub mod tests {

let s = "<font color=\"red\">Red!</u>";
let tree = parse_matrix_html(s);
let text = tree.to_text(20, Style::default(), false);
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::styled("Red", red),
Span::styled("!", red),
Expand All @@ -993,7 +1001,7 @@ pub mod tests {
fn test_paragraph() {
let s = "<p>Hello world!</p><p>Content</p><p>Goodbye world!</p>";
let tree = parse_matrix_html(s);
let text = tree.to_text(10, Style::default(), false);
let text = tree.to_text(10, Style::default(), false, false);
assert_eq!(text.lines.len(), 7);
assert_eq!(
text.lines[0],
Expand All @@ -1020,7 +1028,7 @@ pub mod tests {
fn test_blockquote() {
let s = "<blockquote>Hello world!</blockquote>";
let tree = parse_matrix_html(s);
let text = tree.to_text(10, Style::default(), false);
let text = tree.to_text(10, Style::default(), false, false);
assert_eq!(text.lines.len(), 2);
assert_eq!(
text.lines[0],
Expand All @@ -1036,7 +1044,7 @@ pub mod tests {
fn test_list_unordered() {
let s = "<ul><li>List Item 1</li><li>List Item 2</li><li>List Item 3</li></ul>";
let tree = parse_matrix_html(s);
let text = tree.to_text(8, Style::default(), false);
let text = tree.to_text(8, Style::default(), false, false);
assert_eq!(text.lines.len(), 6);
assert_eq!(
text.lines[0],
Expand Down Expand Up @@ -1098,7 +1106,7 @@ pub mod tests {
fn test_list_ordered() {
let s = "<ol><li>List Item 1</li><li>List Item 2</li><li>List Item 3</li></ol>";
let tree = parse_matrix_html(s);
let text = tree.to_text(9, Style::default(), false);
let text = tree.to_text(9, Style::default(), false, false);
assert_eq!(text.lines.len(), 6);
assert_eq!(
text.lines[0],
Expand Down Expand Up @@ -1168,7 +1176,7 @@ pub mod tests {
<tr><td>a</td><td>b</td><td>c</td></tr>\
</tbody></table>";
let tree = parse_matrix_html(s);
let text = tree.to_text(15, Style::default(), false);
let text = tree.to_text(15, Style::default(), false, false);
let bold = Style::default().add_modifier(StyleModifier::BOLD);
assert_eq!(text.lines.len(), 11);

Expand Down Expand Up @@ -1261,7 +1269,7 @@ pub mod tests {
let s = "<mx-reply>This was replied to</mx-reply>This is the reply";

let tree = parse_matrix_html(s);
let text = tree.to_text(10, Style::default(), false);
let text = tree.to_text(10, Style::default(), false, false);
assert_eq!(text.lines.len(), 4);
assert_eq!(
text.lines[0],
Expand Down Expand Up @@ -1298,7 +1306,7 @@ pub mod tests {
);

let tree = parse_matrix_html(s);
let text = tree.to_text(10, Style::default(), true);
let text = tree.to_text(10, Style::default(), true, false);
assert_eq!(text.lines.len(), 2);
assert_eq!(
text.lines[0],
Expand All @@ -1325,7 +1333,7 @@ pub mod tests {
fn test_self_closing() {
let s = "Hello<br>World<br>Goodbye";
let tree = parse_matrix_html(s);
let text = tree.to_text(7, Style::default(), true);
let text = tree.to_text(7, Style::default(), true, false);
assert_eq!(text.lines.len(), 3);
assert_eq!(text.lines[0], Line::from(vec![Span::raw("Hello"), Span::raw(" "),]));
assert_eq!(text.lines[1], Line::from(vec![Span::raw("World"), Span::raw(" "),]));
Expand All @@ -1336,7 +1344,7 @@ pub mod tests {
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);
let text = tree.to_text(15, Style::default(), true, false);
assert_eq!(text.lines.len(), 1);
assert_eq!(
text.lines[0],
Expand All @@ -1359,7 +1367,7 @@ pub mod tests {
"</code></pre>\n"
);
let tree = parse_matrix_html(s);
let text = tree.to_text(25, Style::default(), true);
let text = tree.to_text(25, Style::default(), true, false);
assert_eq!(text.lines.len(), 5);
assert_eq!(
text.lines[0],
Expand Down Expand Up @@ -1420,4 +1428,28 @@ pub mod tests {
])
);
}

#[test]
fn test_emoji_shortcodes() {
for shortcode in ["exploding_head", "polar_bear", "canada"] {
let emoji = emojis::get_by_shortcode(shortcode).unwrap().as_str();
let emoji_width = UnicodeWidthStr::width(emoji);
let replacement = format!(":{shortcode}:");
let replacement_width = UnicodeWidthStr::width(replacement.as_str());
let s = format!("<p>{emoji}</p>");
let tree = parse_matrix_html(s.as_str());
// Test with emojis_shortcodes set to false
let text = tree.to_text(20, Style::default(), false, false);
assert_eq!(text.lines, vec![Line::from(vec![
Span::raw(emoji),
space_span(20 - emoji_width, Style::default()),
]),]);
// Test with emojis_shortcodes set to true
let text = tree.to_text(20, Style::default(), false, true);
assert_eq!(text.lines, vec![Line::from(vec![
Span::raw(replacement.as_str()),
space_span(20 - replacement_width, Style::default()),
])]);
}
}
}
Loading
Loading